<?php
// +----------------------------------------------------------------------
// | A3Mall
// +----------------------------------------------------------------------
// | Copyright (c) 2020 http://www.a3-mall.com All rights reserved.
// +----------------------------------------------------------------------
// | Author: xzncit <158373108@qq.com>
// +----------------------------------------------------------------------

namespace app\adminapi\service\order;

use app\common\exception\BaseException;
use app\common\library\file\File;
use app\common\library\http\printer\xpyun\Xpyun;
use app\common\service\Config;
use think\facade\Request;
use app\common\library\utils\Image;
use app\common\model\goods\Freight as FreightModel;
use app\common\model\goods\Goods as GoodsModel;
use app\adminapi\model\order\Order as OrderModel;
use app\common\model\order\OrderGoods as OrderGoodsModel;
use app\common\model\order\OrderAddress as OrderAddressModel;
use app\common\model\order\OrderExport as OrderExportModel;
use app\common\enum\Order as OrderEnum;
use app\common\service\Config as ConfigService;
use app\common\service\Express as ExpressService;

/**
 * @package app\adminapi\service\order
 * @class Order
 * @author xzncit 2024-02-25
 */
class Order {

    /**
     * 列表
     * @param array $params
     * @return array
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public static function getList($params=[]){
        $array           = [];
        $fields          = ["active,type,pay_status,order_no,accept_name,delivery_status,time",[
            "active"            => $params["active"]??'0',
            "type"              => $params["type"]??'0',
            "pay_status"        => $params["pay_status"]??'0',
            "order_no"          => $params["order_no"]??"",
            "accept_name"       => $params["accept_name"]??"",
            "delivery_status"   => $params["delivery_status"]??"",
            "time"              => $params["time"]??""
        ]];

        $array["total"]  = OrderModel::withSearch(...$fields)->withJoin(["payment","delivery","address"])->count();
        $array["list"]   = OrderModel::withSearch(...$fields)->withJoin(["payment","delivery","address"])->order("order.id","desc")->page($params["current"]??1,$params["size"]??10)->select()->map(function ($res){
            $res["username"] = getUserName($res["user_id"]);
            $res["goods"] = OrderGoodsModel::where("order_id",$res["id"])->select()->map(function ($value){
                $value["photo"] = Image::thumb(GoodsModel::where("id",$value["goods_id"])->value("photo",""));
                $value["spec"]  = !empty($value["goods_array"]) ? json_decode($value["goods_array"],true) : ["name"=>"","value"=>""];
                return $value;
            });

            $res["active"]     = OrderEnum::active($res);
            $res["text"]       = OrderEnum::activeText($res["active"]);
            $res["order_type"] = OrderEnum::type($res["type"]);
            $res["transaction_status"] = OrderEnum::status($res["status"]);
            return $res;
        });

        $array["count"] = [
            "0"=>OrderModel::where("status","in","1,2")->count(), // 待付款
            "1"=>OrderModel::where("status","=","3")->count(), // 待发货
            "2"=>OrderModel::where("status","=","4")->count(), // 待收货
            "3"=>OrderModel::where([["status","in","3,4,5"],["refund_status","in","2,3,4"]])->count(), // 待退款/已退款
            "4"=>OrderModel::where([["status","=","5"],["evaluate_status","=","1"]])->count(), // 待评价
            "5"=>OrderModel::where("status","=","5")->count() // 已完成
        ];

        return $array;
    }

    /**
     * 详情
     * @param $id
     * @return array|mixed
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public static function detail($id){
        $row = OrderModel::with(["payment","delivery","freight"])->where("id",$id)->find();
        if(empty($row)){
            throw new \Exception("您要查找的订单不存在",0);
        }

        $row["username"] = getUserName($row["user_id"]);
        $row["goods"] = OrderGoodsModel::where("order_id",$row["id"])->select()->map(function ($value){
            $value["photo"] = Image::thumb(GoodsModel::where("id",$value["goods_id"])->value("photo",""));
            $value["spec"]  = !empty($value["goods_array"]) ? json_decode($value["goods_array"],true) : ["name"=>"","value"=>""];
            return $value;
        });

        $row["active"]     = OrderEnum::active($row);
        $row["text"]       = OrderEnum::activeText($row["active"]);
        $address = OrderAddressModel::where("order_id",$id)->find();
        $row["accept_name"]        = $address["accept_name"]??"";
        $row["mobile"]             = $address["mobile"]??"";
        $row["country"]            = $address["country"]??"";
        $row["province"]           = $address["province"]??"";
        $row["city"]               = $address["city"]??"";
        $row["area"]               = $address["area"]??"";
        $row["address"]            = $address["address"]??"";
        $row["order_type"]         = OrderEnum::type($row["type"]);
        $row["transaction_status"] = OrderEnum::status($row["status"]);
        return $row;
    }

    /**
     * 修改订单价格
     * @param array $params
     * @return bool
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public static function updatePrice($params=[]){
        $row = OrderModel::where("id",$params["id"])->find();
        if(empty($row)){
            throw new \Exception("您要查找的订单不存在",0);
        }else if(in_array($row["pay_status"],[2,3,4])){
            throw new \Exception("当前订单已支付",0);
        }

        $type  = intval($params["type"]??0);
        $price = floatval($params["price"]??0);

        if($type == 0){
            throw new \Exception("请选择操作类型",0);
        }

        if(empty($price)){
            throw new \Exception("请输入金额",0);
        }

        if($type == 2 && $price > $row["order_amount"]){
            throw new \Exception("您要操作的金额超过订单总金额",0);
        }

        $data = [];
        switch ($type){
            case 1: // 增加金额
                $data["increase_amount"] = $price;
                $data["order_amount"]    = $row["order_amount"] + $price;
                break;
            case 2: // 减少金额
                $data["reduce_amount"]   = $price;
                $data["order_amount"]    = $row["order_amount"] - $price;
                break;
        }

        OrderModel::where("id",$row["id"])->save($data);
        return true;
    }

    /**
     * 取消订单
     * @param $id
     * @return bool
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public static function cancel($id){
        $row = OrderModel::where("id",$id)->find();
        if(empty($row)){
            throw new \Exception("您要查找的订单不存在",0);
        }

        if(!in_array($row["status"],[1,2])){
            throw new \Exception("该订单不允许此操作",0);
        }

        OrderModel::where("id",$id)->save(["status"=>7]);
        return true;
    }

    /**
     * 查询物流
     * @param $id
     * @return array
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public static function express($id){
        return ExpressService::query($id);
    }

    /**
     * 订单发货
     * @param $params
     * @return bool
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public static function sendDelivery($params){
        $row = OrderModel::where("id",$params["id"])->find();
        if(empty($row)){
            throw new \Exception("您要查找的订单不存在",0);
        }

        if($row["delivery_status"] == 2){
            throw new \Exception("您选择的已发货",0);
        }

        $freight = FreightModel::where("id",$params["express_id"])->find();
        if(empty($freight)){
            throw new \Exception("请选择物流公司",0);
        }

        if(empty($params["express_no"])){
            throw new \Exception("请输入快递单号",0);
        }

        OrderModel::where("id",$params["id"])->save([
            "express_id"        => $freight["id"],
            "express_name"      => $freight["title"],
            "express_no"        => $params["express_no"],
            "remarks"           => $params["remarks"],
            "delivery_status"   => 2,
            "status"            => 4,
            "send_time"         => time()
        ]);

        return true;
    }

    /**
     * 物流方式
     * @param $id
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public static function getFreight($id){
        $order = self::detail($id);
        return ["order"=>$order,"freight"=>FreightModel::where("status",1)->select()];
    }

    /**
     * 导出列表
     * @return array
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public static function getExportList(){
        $array           = [];
        $array["total"]  = OrderExportModel::count();
        $array["list"]   = OrderExportModel::order("id","desc")->page($params["current"]??1,$params["size"]??10)->select()->map(function ($res){
            $res["path"] = Request::domain() . '/' . $res["path"];
            return $res;
        });

        return $array;
    }

    /**
     * @param array $params
     * @return bool
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public static function export($params=[]){
        $params["order_type"] = intval($params["order_type"]??1);
        if($params["order_type"] == 2){
            self::createOrderDelivery();
        }else{
            self::createBill($params);
        }

        return true;
    }

    public static function createBill($params){
        $exportID = OrderExportModel::create([
            "type"=>1,
            "path"=>"",
            "status"=>1,
            "start_time"=>time(),
            "create_time"=>time()
        ])->id;

        try{
            $fields = ["type,pay_status,delivery_status,time",[
                "type"              => $params["type"]??'0',
                "pay_status"        => $params["pay_status"]??'0',
                "delivery_status"   => $params["delivery_status"]??"",
                "time"              => $params["time"]??""
            ]];

            $order = OrderModel::withSearch(...$fields)->withJoin("payment")->order("id","desc")->select()->map(function ($res){
                $res["username"] = getUserName($res["user_id"]);
                $res["goods"] = OrderGoodsModel::where("order_id",$res["id"])->select()->map(function ($value){
                    $value["photo"] = Image::thumb(GoodsModel::where("id",$value["goods_id"])->value("photo",""));
                    $value["spec"]  = !empty($value["goods_array"]) ? json_decode($value["goods_array"],true) : ["name"=>"","value"=>""];
                    return $value;
                });

                $address           = OrderAddressModel::where("order_id",$res["id"])->find();
                $res["address"]    = implode(",",array_map(function ($res){
                    if(!empty($res)) return $res;
                },[$address["accept_name"],$address["mobile"],$address["province"],$address["city"],$address["area"],$address["address"]]));
                $res["active"]     = OrderEnum::active($res);
                $res["text"]       = OrderEnum::activeText($res["active"]);
                $res["order_type"] = OrderEnum::type($res["type"]);
                return $res;
            });

            $data  = [];
            $title = [
                "物流类型","商品信息","用户名","订单号","支付方式","订单状态",
                "收货地址","订单留言","管理员备注",
                "运费","订单金额","创建时间","支付时间","发货时间","完成时间"
            ];

            foreach($order as $value){
                $goods = '';
                foreach($value["goods"] as $val){
                    $goods .= $val["goods_name"];
                    if(!empty($goodsArray["spec"])){
                        $goods .= ' ' . $val["spec"]["name"];
                    }

                    $goods .= ' x' . $val["goods_total_nums"];
                    $goods .= ' ' . $val["sell_price"] . PHP_EOL;
                }

                $data[] = [
                    "express_name"      => $value["express_name"],
                    "goods"             => $goods,
                    "username"          => $value["username"],
                    "order_no"          => $value["order_no"],
                    "payment"           => $value["pay_name"],
                    "text"              => $value["text"],
                    "address"           => $value["address"],
                    "message"           => $value["message"],
                    "note"              => $value["note"],
                    "real_freight"      => $value["real_freight"],
                    "order_amount"      => $value["order_amount"],
                    "create_time"       => date("Y-m-d H:i:s",$value["create_time"]),
                    "pay_time"          => (!empty($value["pay_time"]) ? date("Y-m-d H:i:s",$value["pay_time"]) : "-"),
                    "send_time"         => (!empty($value["send_time"]) ? date("Y-m-d H:i:s",$value["send_time"]) : "-"),
                    "completion_time"   => (!empty($value["completion_time"]) ? date("Y-m-d H:i:s",$value["completion_time"]) : "-"),
                ];
            }

            $spreadsheet = new \PhpOffice\PhpSpreadsheet\Spreadsheet();
            $sheet = $spreadsheet->getActiveSheet();
            foreach($title as $key => $value) {
                $sheet->setCellValueByColumnAndRow($key + 1, 1, $value);
            }

            $row = 2;
            foreach($data as $item) {
                $column = 1;
                foreach ($item as $value) {
                    $sheet->setCellValueByColumnAndRow($column, $row, $value);
                    $column++;
                }
                $row++;
            }

            $titCol = 'A';
            foreach($title as $key => $value) {
                $sheet->setCellValue($titCol . '1', $value);
                $titCol++;
            }

            $row = 2;
            foreach($data as $item) {
                $dataCol = 'A';
                foreach ($item as $value) {
                    $sheet->setCellValue($dataCol . $row, $value);
                    $dataCol++;
                }
                $row++;
            }

            $file = public_path() . 'uploads/file/帐单明细-' . date("YmdHis") . '.xlsx';
            if(!file_exists(dirname($file))) mkdir($file,0777,true);
            $writer = new \PhpOffice\PhpSpreadsheet\Writer\Xlsx($spreadsheet);
            $writer->save($file);

            $update = [
                "path"      => str_replace(public_path(),'',$file),
                "status"    => 2,
                "end_time"  => time()
            ];
        }catch (\Exception $ex){
            $update = [
                "status"    => 3,
                "end_time"  => time()
            ];
        }

        OrderExportModel::where("id",$exportID)->save($update);
        return true;
    }

    /**
     * 导出发货单
     * @return bool
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public static function createOrderDelivery(){
        $exportID = OrderExportModel::create([
            "type"=>2,
            "path"=>"",
            "status"=>1,
            "start_time"=>time(),
            "create_time"=>time()
        ])->id;

        try{
            $condition = [];
            $condition[] = ["status","=","3"];
            $condition[] = ["pay_status","=","2"];
            $condition[] = ["refund_status","=","1"];
            $condition[] = ["delivery_status","=",1];
            $order = OrderModel::where($condition)->order("id","DESC")->select()->map(function ($res){
                $res["username"] = getUserName($res["user_id"]);
                $res["goods"] = OrderGoodsModel::where("order_id",$res["id"])->select()->map(function ($value){
                    $value["photo"] = Image::thumb(GoodsModel::where("id",$value["goods_id"])->value("photo",""));
                    $value["spec"]  = !empty($value["goods_array"]) ? json_decode($value["goods_array"],true) : ["name"=>"","value"=>""];
                    return $value;
                });

                $address = OrderAddressModel::where("order_id",$res["id"])->find();
                $res["active"]     = OrderEnum::active($res);
                $res["text"]       = OrderEnum::activeText($res["active"]);
                $res["order_type"] = OrderEnum::type($res["type"]);
                $res["delivery_status"] = OrderEnum::deliveryStatus($res["delivery_status"]);
                $res["address"]    = implode(",",array_map(function ($res){
                    if(!empty($res)) return $res;
                },[$address["accept_name"],$address["mobile"],$address["province"],$address["city"],$address["area"],$address["address"]]));
                return $res;
            });

            $title = [
                "订单号","商品信息","用户名","订单状态","配送状态","订单金额","收货地址","订单留言","物流单号"
            ];

            $data = [];
            foreach($order as $value){
                $goods = '';
                foreach($value["goods"] as $val){
                    $goods .= $val["goods_name"];
                    if(!empty($goodsArray["spec"])){
                        $goods .= ' ' . $val["spec"]["name"];
                    }

                    $goods .= ' x' . $val["goods_total_nums"];
                    $goods .= ' ' . $val["sell_price"] . PHP_EOL;
                }

                $data[] = [
                    "order_no"          => $value["order_no"]."",
                    "goods"             => $goods,
                    "username"          => $value["username"],
                    "text"              => $value["text"],
                    "delivery_status"   => $value["delivery_status"],
                    "order_amount"      => $value["order_amount"],
                    "address"           => $value["address"],
                    "message"           => $value["message"]
                ];
            }

            $spreadsheet = new \PhpOffice\PhpSpreadsheet\Spreadsheet();
            $sheet = $spreadsheet->getActiveSheet();
            foreach($title as $key => $value) {
                $sheet->setCellValueByColumnAndRow($key + 1, 1, $value);
            }

            $row = 2;
            foreach($data as $item) {
                $column = 1;
                foreach ($item as $value) {
                    $sheet->setCellValueByColumnAndRow($column, $row, $value);
                    $column++;
                }
                $row++;
            }

            $titCol = 'A';
            foreach($title as $key => $value) {
                $sheet->setCellValue($titCol . '1', $value);
                $titCol++;
            }

            $row = 2;
            foreach($data as $item) {
                $dataCol = 'A';
                foreach ($item as $value) {
                    $sheet->setCellValue($dataCol . $row, $value);
                    $dataCol++;
                }
                $row++;
            }

            $file = public_path() . 'uploads/file/订单发货单-' . date("YmdHis") . '.xlsx';
            if(!file_exists(dirname($file))) mkdir($file,0777,true);
            $writer = new \PhpOffice\PhpSpreadsheet\Writer\Xlsx($spreadsheet);
            $writer->save($file);
            $update = [
                "path"      => str_replace(public_path(),'',$file),
                "status"    => 2,
                "end_time"  => time()
            ];
        }catch(\Exception $ex){
            $update = [
                "status"    => 3,
                "end_time"  => time()
            ];
        }

        OrderExportModel::where("id",$exportID)->save($update);
        return true;
    }

    /**
     * 删除导出内容
     * @param $id
     * @return bool
     */
    public static function deleteExport($id){
        $row = OrderExportModel::where("id",$id)->find();
        if(!empty($row["path"])){
            $file = public_path() . $row["path"];
            if(file_exists($file)) unlink($file);
        }
        OrderExportModel::where("id",$id)->delete();
        return true;
    }

    /**
     * 订单设置
     * @param array $params
     * @return bool|mixed
     * @throws \think\db\exception\DbException
     */
    public static function setting($params=[]){
        if(Request::isPost()){
            return ConfigService::save("order",$params['order']??[]);
        }

        return ConfigService::getArray("order",[]);
    }

    public static function ticket($id){
        $deviceSn = Config::getArray("printer.xpyun.device_id");
        if(empty($deviceSn)){
            throw new BaseException("请配置小票打印机",0);
        }

        $xpyun = new Xpyun();
        $statusResult = $xpyun->queryPrinterStatus($deviceSn);

        if($statusResult["data"] == 0){
            throw new BaseException("打印机离线中",0);
        }else if($statusResult["data"] == 2){
            throw new BaseException("打印机异常，查看打印机是否缺纸",0);
        }

        $export = OrderExportModel::where("id",$id)->findOrEmpty()->toArray();
        if(empty($export)){
            throw new BaseException("您要打印的订单为空 code: -1",0);
        }

        $file = File::getPath() . 'public/'.$export["path"];
        if(!file_exists($file)){
            throw new BaseException("发货单不存在",0);
        }

        $loadPath = explode(".",$file);
        $suffix   = end($loadPath);
        if('csv' == $suffix){
            $reader = new \PhpOffice\PhpSpreadsheet\Reader\Csv();
        }else if('xls' == $suffix){
            $reader = new \PhpOffice\PhpSpreadsheet\Reader\Xls();
        }else{
            $reader = new \PhpOffice\PhpSpreadsheet\Reader\Xlsx();
        }

        $spreadsheet = $reader->load($file);
        $sheetData = $spreadsheet->getActiveSheet()->ToArray();

        $orderNo = [];
        foreach($sheetData as $key=>$item){
            if($key == 0 || empty($item[0])){
                continue;
            }

            $orderNo[] = trim($item[0]);
        }

        if(empty($orderNo)){
            throw new BaseException("您要打印的订单为空 code: -2",0);
        }

        $orderResult = OrderModel::where("order_no","in",$orderNo)->select()->toArray();
        if(empty($orderResult)){
            throw new BaseException("您要打印的订单为空 code: -3",0);
        }

        foreach($orderResult as $key=>$order){
            $address              = OrderAddressModel::where("order_id",$order["id"])->find();
            $order["accept_name"] = $address["accept_name"]??"";
            $order["mobile"]      = $address["mobile"]??"";
            $order["address"]     = implode(",",array_map(function ($res){ if(!empty($res)){ return $res; } },[$address["province"]??"",$address["city"]??"",$address["area"]??"",$address["address"]??""]));
            $goods = OrderGoodsModel::where("order_id",$order["id"])->select()->map(function ($res){
                $spec = [];
                if(!empty($res["goods_array"])){
                    $spec = json_decode($res["goods_array"],true);
                }

                $res["spec"] = $spec;
                return $res;
            })->toArray();

$content = "<IMG></IMG>
<CB>--订单小票--
<BR>
<L><N>下单时间:".date('Y年m月d日H时i分',$order['create_time'])."
订单编号:".$order['order_no']."
**************商品**************";
foreach($goods as $value){
$content .= "<L><N>".$value["goods_name"] . " " . ($value["spec"]["name"]??"") . " x".$value['goods_total_nums']." " . $value["sell_price"];
}
$content .= "
--------------------------------
配送运费:￥".$order['real_freight']."
优惠券:￥".$order['coupon_amount']."
订单折扣:￥".$order['discount']."
<L><N>********************************
订单总价:￥".$order['order_amount']."
<N>" . $order['address'] . "
".$order['accept_name'].":".$order['mobile']."
订单备注：".($order['message']??'-')."
<C><HB>二维码
<L><QRCODE s=6 e=L l=center>".Request::domain()."/mobile"."</QRCODE>";

            $xpyun->print($deviceSn,$content);
        }

        return true;
    }

}