|
|
<?php
|
|
|
/**
|
|
|
* Created by PhpStorm.
|
|
|
* User: weizongsong
|
|
|
* Date: 2019-04-12
|
|
|
* Time: 22:34
|
|
|
*/
|
|
|
|
|
|
namespace App\Http\Controllers\Admin;
|
|
|
|
|
|
use App\Customer;
|
|
|
use App\Libs\AlipayF2F;
|
|
|
use App\Models\AdminAreaLink;
|
|
|
use App\Models\AdminBuildingLink;
|
|
|
use App\Models\Area;
|
|
|
use App\Models\Balance;
|
|
|
use App\Models\Bed;
|
|
|
use App\Models\FactorItems;
|
|
|
use App\Models\OrderItems;
|
|
|
use App\Models\Orders;
|
|
|
use App\Models\Paramedic;
|
|
|
use App\Models\Product;
|
|
|
use App\Models\ProductItems;
|
|
|
use App\Models\ProductParamedicLevel;
|
|
|
use App\Models\Project;
|
|
|
use App\Models\Recharge;
|
|
|
use App\Models\Refund;
|
|
|
use App\Scopes\AdminProjectScope;
|
|
|
use Carbon\Carbon;
|
|
|
use Illuminate\Http\Request;
|
|
|
use Illuminate\Pagination\LengthAwarePaginator;
|
|
|
use Illuminate\Support\Facades\Auth;
|
|
|
use Illuminate\Support\Facades\DB;
|
|
|
use PhpOffice\PhpSpreadsheet\Spreadsheet;
|
|
|
use PhpOffice\PhpSpreadsheet\Writer\Xlsx;
|
|
|
use Spatie\Permission\Models\Role;
|
|
|
|
|
|
class StatisticsController extends CommonController
|
|
|
{
|
|
|
public $bladePath = "admin.statistics";
|
|
|
public $urlPrefix = "admin/statistics";
|
|
|
public $modelName = "数据统计";
|
|
|
public $noProjects = "用户名下没有可以管理的项目";
|
|
|
|
|
|
public function _checkProjects()
|
|
|
{
|
|
|
$projects = (new Project())->adminProject()->orderBy("id", "desc")->get();
|
|
|
view()->share(compact("projects"));
|
|
|
return $projects;
|
|
|
}
|
|
|
|
|
|
public function getYears()
|
|
|
{
|
|
|
$start_year = config("start_year");
|
|
|
$years = [];
|
|
|
for ($i = date("Y"); $i >= $start_year; $i--) {
|
|
|
$years[] = $i;
|
|
|
}
|
|
|
view()->share(compact("years"));
|
|
|
}
|
|
|
|
|
|
public function _getMonths()
|
|
|
{
|
|
|
$months = [];
|
|
|
for ($i = 1; $i <= 12; $i++) {
|
|
|
$mm = $i < 10 ? "0" . $i : $i;
|
|
|
$months[] = (date("Y") - 2) . "-" . $mm;
|
|
|
}
|
|
|
for ($i = 1; $i <= 12; $i++) {
|
|
|
$mm = $i < 10 ? "0" . $i : $i;
|
|
|
$months[] = (date("Y") - 1) . "-" . $mm;
|
|
|
}
|
|
|
for ($i = 1; $i <= 12; $i++) {
|
|
|
$mm = $i < 10 ? "0" . $i : $i;
|
|
|
$months[] = date("Y") . "-" . $mm;
|
|
|
}
|
|
|
|
|
|
view()->share(compact("months"));
|
|
|
return $months;
|
|
|
}
|
|
|
|
|
|
public function _getMonthData()
|
|
|
{
|
|
|
$projects = $this->_checkProjects();
|
|
|
$project_id = request()->project_id ?? $projects->first()->id;
|
|
|
$project = $projects->keyBy("id")->toArray()["{$project_id}"];
|
|
|
|
|
|
$month = request()->month ?? date("Y-m");
|
|
|
$months = $this->_getMonths();
|
|
|
|
|
|
DB::enableQueryLog();
|
|
|
$paramedics = (new Paramedic())->withoutGlobalScope(AdminProjectScope::class)->where(function ($query) use ($project_id, $month) {
|
|
|
$order_item_paramedic_ids = (new OrderItems())
|
|
|
->whereRaw("(DATE_FORMAT(`service_date`,'%Y-%m') = '{$month}' or DATE_FORMAT(`paid_at`,'%Y-%m') = '{$month}')")
|
|
|
->whereHas("order", function ($query) use ($project_id) {
|
|
|
$query->where("project_id", $project_id);
|
|
|
})->pluck("paramedic_id")->toArray();
|
|
|
$query->where("project_id", $project_id)->orWhereIn("id", $order_item_paramedic_ids);
|
|
|
})->with([
|
|
|
"orderItems" => function ($query) use ($month, $project_id) {
|
|
|
$query->whereRaw("(DATE_FORMAT(`service_date`,'%Y-%m') = '{$month}' or DATE_FORMAT(`paid_at`,'%Y-%m') = '{$month}')")
|
|
|
->where("total", ">", 0)
|
|
|
->whereHas("order", function ($query) use ($project_id) {
|
|
|
$query->where("project_id", $project_id);
|
|
|
})
|
|
|
->with([
|
|
|
"order",
|
|
|
"product" => function ($query) {
|
|
|
$query->withoutGlobalScope(AdminProjectScope::class);
|
|
|
},
|
|
|
"productItem",
|
|
|
"productParamedicLevel",
|
|
|
"paramedic" => function ($query) {
|
|
|
$query->withoutGlobalScope(AdminProjectScope::class);
|
|
|
},
|
|
|
"bed",
|
|
|
"room",
|
|
|
"building",
|
|
|
"area"
|
|
|
])
|
|
|
->orderBy("id");
|
|
|
}
|
|
|
])->get();
|
|
|
|
|
|
$allItems = collect();
|
|
|
foreach ($paramedics as $paramedic) {
|
|
|
foreach ($paramedic->orderItems as $orderItem) {
|
|
|
if ($orderItem->paid_at) {
|
|
|
$paid_at_this_month = Carbon::parse($orderItem->paid_at)->isSameMonth($month) ? true : false;
|
|
|
} else {
|
|
|
$paid_at_this_month = false;
|
|
|
}
|
|
|
|
|
|
if (Carbon::parse($orderItem->service_date)->isSameMonth($month)) {
|
|
|
$orderItem->service_date_in_this_month = $orderItem->service_date;
|
|
|
} else {
|
|
|
$orderItem->service_date_in_this_month = OrderItems::PREV_MONTH;
|
|
|
}
|
|
|
|
|
|
$orderItem->paid_at_this_month = $paid_at_this_month;
|
|
|
$orderItem = $orderItem->calculateFee();
|
|
|
}
|
|
|
$paramedic->originalOrderItems = $paramedic->orderItems;
|
|
|
$allItems = $allItems->concat($paramedic->orderItems);
|
|
|
$paramedic->orderItems = $paramedic->orderItems->groupBy("service_date_in_this_month");
|
|
|
}
|
|
|
|
|
|
$days = date("t", strtotime($month));
|
|
|
$dates = [];
|
|
|
for ($i = 1; $i <= $days; $i++) {
|
|
|
$dd = $i < 10 ? "0" . $i : $i;
|
|
|
$dates[] = $dd;
|
|
|
}
|
|
|
$dates[] = OrderItems::PREV_MONTH;
|
|
|
|
|
|
view()->share(compact("projects", "project_id", "month", "months", "dates", "paramedics", "allItems"));
|
|
|
return compact("projects", "project_id", "month", "months", "dates", "paramedics", "allItems");
|
|
|
}
|
|
|
|
|
|
public function salary(Request $request)
|
|
|
{
|
|
|
$projects = $this->_checkProjects();
|
|
|
if (!$projects->count()) {
|
|
|
return $this->error($this->noProjects);
|
|
|
}
|
|
|
$this->_getMonthData();
|
|
|
$laravel_duration = microtime(true) - LARAVEL_START;
|
|
|
|
|
|
return view($this->urlPrefix . "/salary", compact("laravel_duration"));
|
|
|
}
|
|
|
|
|
|
public function overview(Request $request)
|
|
|
{
|
|
|
$projects = $this->_checkProjects();
|
|
|
if (!$projects->count()) {
|
|
|
return $this->error($this->noProjects);
|
|
|
}
|
|
|
$project_id = request()->project_id ?? $projects->first()->id;
|
|
|
$project = Project::find($project_id);
|
|
|
|
|
|
$month = request()->month ?? date("Y-m");
|
|
|
$months = $this->_getMonths();
|
|
|
|
|
|
$start_timestamp = strtotime($month);
|
|
|
$end_timestamp = strtotime("+1 month", strtotime($month));
|
|
|
|
|
|
//根据项目获取相关数据
|
|
|
$prev_month_balance = Balance::whereRaw("UNIX_TIMESTAMP(`created_at`) < " . $start_timestamp)
|
|
|
->whereHas("order", function ($query) use ($project_id) {
|
|
|
$query->where("project_id", $project_id);
|
|
|
})->sum("money");
|
|
|
$this_month_balance = Balance::whereRaw("UNIX_TIMESTAMP(`created_at`) < " . $end_timestamp)
|
|
|
->whereHas("order", function ($query) use ($project_id) {
|
|
|
$query->where("project_id", $project_id);
|
|
|
})->sum("money");
|
|
|
$this_month_balances = Balance::whereRaw("UNIX_TIMESTAMP(`created_at`) >= " . $start_timestamp . " and UNIX_TIMESTAMP(`created_at`) < " . $end_timestamp)
|
|
|
->whereHas("order", function ($query) use ($project_id) {
|
|
|
$query->where("project_id", $project_id);
|
|
|
})->get();
|
|
|
|
|
|
return view($this->urlPrefix . "/overview", compact("project_id", "month", "project", "prev_month_balance", "this_month_balance", "this_month_balances"));
|
|
|
}
|
|
|
|
|
|
public function syncOrderItems(Request $request)
|
|
|
{
|
|
|
DB::enableQueryLog();
|
|
|
//采用指定订单号
|
|
|
$model = OrderItems::whereHas("order", function ($query) {
|
|
|
$query->whereIn("serial", ["20240101000016", "20240103000044", "20240103000055", "20240103000068", "20240104000010", "20240104000011", "20240104000012", "20240104000035", "20240104000040", "20240105000009", "20240105000042", "20240105000049", "20240105000051", "20240105000063", "20240105000064", "20231212000051", "20240104000023", "20240104000033", "20240104000036", "20240104000049", "20240104000059", "20240104000060", "20240105000043", "20240105000045", "20240105000048", "20240105000065", "20240105000066", "20240101000024", "20240104000007", "20240104000030", "20240104000034", "20240104000044", "20240104000065"]);
|
|
|
})->where("factors", "not like", "%所在科室%");
|
|
|
//采用指定订单号结束
|
|
|
|
|
|
if ($request->last_id) {
|
|
|
$model = $model->where("id", ">", $request->last_id);
|
|
|
}
|
|
|
$orderItems = $model->with("order")->limit(50)->get();
|
|
|
|
|
|
if (!$orderItems->count()) {
|
|
|
dd("已处理完毕");
|
|
|
}
|
|
|
|
|
|
DB::beginTransaction();
|
|
|
try {
|
|
|
foreach ($orderItems as $orderItem) {
|
|
|
$factors = json_decode($orderItem->factors, true);
|
|
|
$parent_factors = json_decode($orderItem->order->factors, true);
|
|
|
|
|
|
if (
|
|
|
!in_array("所在科室", collect($factors)->pluck("factor_name")->toArray())
|
|
|
&& in_array("所在科室", collect($parent_factors)->pluck("factor_name")->toArray())
|
|
|
) {
|
|
|
$add = collect($parent_factors)->keyBy("factor_name")["所在科室"];
|
|
|
$factors[] = $add;
|
|
|
$orderItem->update([
|
|
|
"factors" => json_encode($factors, JSON_UNESCAPED_UNICODE)
|
|
|
]);
|
|
|
}
|
|
|
}
|
|
|
DB::commit();
|
|
|
return $this->success("处理成功一批,正在跳转到下一批!", url($this->urlPrefix . "/salary/sync-order-items?month={$request->month}&last_id=" . $orderItems->last()->id));
|
|
|
} catch (\Exception $exception) {
|
|
|
DB::rollBack();
|
|
|
dd($exception->getMessage());
|
|
|
}
|
|
|
}
|
|
|
|
|
|
public function finance(Request $request)
|
|
|
{
|
|
|
$projects = $this->_checkProjects();
|
|
|
if (!$projects->count()) {
|
|
|
return $this->error($this->noProjects);
|
|
|
}
|
|
|
|
|
|
$project_id = request()->project_id ?? $projects->first()->id;
|
|
|
$project = $projects->keyBy("id")->toArray()["{$project_id}"];
|
|
|
|
|
|
$month = request()->month ?? date("Y-m");
|
|
|
$months = $this->_getMonths();
|
|
|
|
|
|
|
|
|
// 判断是否护士长
|
|
|
$userId = auth()->id();
|
|
|
$roleId = Role::where('name', 'like', '%护士长%')->where('guard_name', 'admin')->value('id');
|
|
|
$hushizhang = DB::table('model_has_roles')->where('role_id', $roleId)
|
|
|
->where('model_type', 'App\Admin')
|
|
|
->where('model_id', $userId)
|
|
|
->count();
|
|
|
|
|
|
// 是否院方管理
|
|
|
$roleId = Role::where('name', 'like', '%院方管理%')->where('guard_name', 'admin')->value('id');
|
|
|
$yuanfang = DB::table('model_has_roles')->where('role_id', $roleId)
|
|
|
->where('model_type', 'App\Admin')
|
|
|
->where('model_id', $userId)
|
|
|
->count();
|
|
|
|
|
|
// 获取这个护士长病区的订单或院方管理楼栋的订单
|
|
|
$user = auth()->user();
|
|
|
$orderIds = [];
|
|
|
if ($hushizhang) {
|
|
|
$areaId = AdminAreaLink::where('project_id', $project_id)->where('admin_id', $user->id)->pluck('area_id');
|
|
|
if ($areaId->isNotEmpty()) {
|
|
|
$bedList = Bed::whereIn('area_id', $areaId)->pluck('id');
|
|
|
if ($bedList->isNotEmpty()) {
|
|
|
$orderIds = Orders::whereIn('bed_id', $bedList)->pluck('id');
|
|
|
}
|
|
|
}
|
|
|
} elseif ($yuanfang) {
|
|
|
$buildingId = AdminBuildingLink::where('project_id', $project_id)->where('admin_id', $user->id)->pluck('building_id');
|
|
|
if ($buildingId->isNotEmpty()) {
|
|
|
$areaId = Area::whereIn('building_id', $buildingId)->pluck('id');
|
|
|
if ($areaId->isNotEmpty()) {
|
|
|
$bedList = Bed::whereIn('area_id', $areaId)->pluck('id');
|
|
|
if ($bedList->isNotEmpty()) {
|
|
|
$orderIds = Orders::whereIn('bed_id', $bedList)->pluck('id');
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
// 如果没有关联数据,$orderIds 保持为空数组,后续查询会返回空结果
|
|
|
}
|
|
|
|
|
|
|
|
|
$recharges = Recharge::with(["manager", "order", "patient"])
|
|
|
->where(function ($query) use ($hushizhang, $yuanfang, $orderIds) {
|
|
|
if ($hushizhang || $yuanfang) {
|
|
|
if (!empty($orderIds)) {
|
|
|
$query->whereIn('order_id', $orderIds);
|
|
|
} else {
|
|
|
// 如果没有关联数据,返回空结果
|
|
|
$query->whereIn('order_id', []);
|
|
|
}
|
|
|
}
|
|
|
})
|
|
|
->withCount("refunds")
|
|
|
->whereNotNull("paid_at")
|
|
|
->whereRaw("DATE_FORMAT(`paid_at`,'%Y-%m') = '{$month}'")
|
|
|
->whereHas("order", function ($query) use ($project_id) {
|
|
|
$query->where("project_id", $project_id);
|
|
|
})
|
|
|
->get();
|
|
|
$recharges_sum = $recharges->sum('money');
|
|
|
|
|
|
$refunds = Refund::whereNotNull("paid_at")
|
|
|
->where(function ($query) use ($hushizhang, $yuanfang, $orderIds) {
|
|
|
if ($hushizhang || $yuanfang) {
|
|
|
if (!empty($orderIds)) {
|
|
|
$query->whereIn('order_id', $orderIds);
|
|
|
} else {
|
|
|
// 如果没有关联数据,返回空结果
|
|
|
$query->whereIn('order_id', []);
|
|
|
}
|
|
|
}
|
|
|
})
|
|
|
->whereRaw("DATE_FORMAT(`paid_at`,'%Y-%m') = '{$month}'")
|
|
|
->whereHas("order", function ($query) use ($project_id) {
|
|
|
$query->where("project_id", $project_id);
|
|
|
})
|
|
|
->get();
|
|
|
$refunds_sum = $refunds->sum('money');
|
|
|
return view($this->bladePath . ".finance", compact("recharges_sum", "refunds_sum", "recharges", "refunds", "projects", "project_id", "months", "month"));
|
|
|
}
|
|
|
|
|
|
public function memberBalanceByDate(Request $request)
|
|
|
{
|
|
|
$is_export = $request->get('is_export', 0);
|
|
|
$projects = $this->_checkProjects();
|
|
|
if (!$projects->count()) {
|
|
|
return $this->error($this->noProjects);
|
|
|
}
|
|
|
$mode = $request->mode ?: 'customer';
|
|
|
$project_id = request()->project_id ?? $projects->first()->id;
|
|
|
$project = Project::find($project_id);
|
|
|
$before_date = $request->before_date ?: date("Y-m-d");
|
|
|
$before_datetime = strtotime($before_date . " 23:59:59");
|
|
|
$before_datetime_text = date("Y-m-d H:i:s", $before_datetime);
|
|
|
|
|
|
DB::enableQueryLog();
|
|
|
$customers = collect();
|
|
|
$orderBalances = collect();
|
|
|
|
|
|
if ($mode == 'order') {
|
|
|
$orderBalances = Orders::query()
|
|
|
->withoutGlobalScopes()
|
|
|
->leftJoin("project", "project.id", "=", "orders.project_id")
|
|
|
->leftJoin("customers", "customers.id", "=", "orders.customer_id")
|
|
|
->leftJoin("patient", "patient.id", "=", "orders.patient_id")
|
|
|
->leftJoin("balance", function ($join) use ($before_datetime_text) {
|
|
|
$join->on("balance.order_id", "=", "orders.id")
|
|
|
->whereNull("balance.deleted_at")
|
|
|
->where("balance.created_at", "<=", $before_datetime_text);
|
|
|
})
|
|
|
->whereNull("orders.deleted_at")
|
|
|
->where("orders.project_id", $project_id)
|
|
|
->whereExists(function ($query) use ($before_date) {
|
|
|
$query->select(DB::raw(1))
|
|
|
->from('order_items')
|
|
|
->whereColumn('order_items.order_id', 'orders.id')
|
|
|
->whereNull('order_items.deleted_at')
|
|
|
->whereDate('order_items.service_date', $before_date);
|
|
|
})
|
|
|
->groupBy(
|
|
|
"orders.id",
|
|
|
"orders.serial",
|
|
|
"project.name",
|
|
|
"orders.from_date",
|
|
|
"orders.to_date",
|
|
|
"orders.contact",
|
|
|
"orders.mobile",
|
|
|
"orders.status",
|
|
|
"customers.mobile",
|
|
|
"patient.name"
|
|
|
)
|
|
|
->orderBy("orders.from_date")
|
|
|
->orderBy("orders.id")
|
|
|
->get([
|
|
|
"orders.id",
|
|
|
"orders.serial",
|
|
|
"project.name as project_name",
|
|
|
"orders.from_date",
|
|
|
"orders.to_date",
|
|
|
"orders.contact",
|
|
|
"orders.mobile as contact_mobile",
|
|
|
DB::raw("'" . $before_datetime_text . "' as point_time"),
|
|
|
DB::raw("
|
|
|
CASE orders.status
|
|
|
WHEN " . Orders::STATUS_UNCONFIRMED . " THEN '" . Orders::TEXT_UNCONFIRMED . "'
|
|
|
WHEN " . Orders::STATUS_UNASSIGNED . " THEN '" . Orders::TEXT_UNASSIGNED . "'
|
|
|
WHEN " . Orders::STATUS_ONGOING . " THEN '" . Orders::TEXT_ONGOING . "'
|
|
|
WHEN " . Orders::STATUS_FINISHED . " THEN '" . Orders::TEXT_FINISHED . "'
|
|
|
ELSE orders.status
|
|
|
END as status_name
|
|
|
"),
|
|
|
"customers.mobile as customer_mobile",
|
|
|
"patient.name as patient_name",
|
|
|
DB::raw("COALESCE(SUM(balance.money), 0) as balance"),
|
|
|
]);
|
|
|
|
|
|
if ($is_export) {
|
|
|
$rows = $orderBalances->toArray();
|
|
|
$spreadsheet = new Spreadsheet();
|
|
|
$sheet = $spreadsheet->getActiveSheet();
|
|
|
$sheet->setCellValue('A1', '项目名称');
|
|
|
$sheet->setCellValue('B1', '时点');
|
|
|
$sheet->setCellValue('C1', '订单号');
|
|
|
$sheet->setCellValue('D1', '订单状态');
|
|
|
$sheet->setCellValue('E1', '客户手机号');
|
|
|
$sheet->setCellValue('F1', '联系人');
|
|
|
$sheet->setCellValue('G1', '联系电话');
|
|
|
$sheet->setCellValue('H1', '被陪护人');
|
|
|
$sheet->setCellValue('I1', '服务开始');
|
|
|
$sheet->setCellValue('J1', '服务结束');
|
|
|
$sheet->setCellValue('K1', '时点余额');
|
|
|
|
|
|
$count = count($rows);
|
|
|
for ($i = 2; $i <= $count + 1; $i++) {
|
|
|
$row = $rows[$i - 2];
|
|
|
$sheet->setCellValue('A' . $i, $row['project_name']);
|
|
|
$sheet->setCellValue('B' . $i, $row['point_time']);
|
|
|
$sheet->setCellValue('C' . $i, $row['serial']);
|
|
|
$sheet->setCellValue('D' . $i, $row['status_name']);
|
|
|
$sheet->setCellValue('E' . $i, $row['customer_mobile']);
|
|
|
$sheet->setCellValue('F' . $i, $row['contact']);
|
|
|
$sheet->setCellValue('G' . $i, $row['contact_mobile']);
|
|
|
$sheet->setCellValue('H' . $i, $row['patient_name']);
|
|
|
$sheet->setCellValue('I' . $i, $row['from_date']);
|
|
|
$sheet->setCellValue('J' . $i, $row['to_date']);
|
|
|
$sheet->setCellValue('K' . $i, $row['balance']);
|
|
|
}
|
|
|
header('Content-Type: application/vnd.ms-excel');
|
|
|
header('Content-Disposition: attachment;filename="' . ($project ? $project->name : '项目') . '_订单时点余额_' . date('YmdHis') . '.xlsx"');
|
|
|
header('Cache-Control: max-age=0');
|
|
|
$writer = new Xlsx($spreadsheet);
|
|
|
$writer->save('php://output');
|
|
|
exit;
|
|
|
}
|
|
|
} else {
|
|
|
$customers = (new Customer())
|
|
|
->whereNull("deleted_at")
|
|
|
->with([
|
|
|
"patients" => function ($query) use ($before_datetime) {
|
|
|
$query->whereRaw("UNIX_TIMESTAMP(`created_at`) <= {$before_datetime}")->orderBy("id", "desc");
|
|
|
},
|
|
|
])
|
|
|
->whereHas("orders", function ($query) use ($before_datetime, $project_id) {
|
|
|
$query
|
|
|
->where("project_id", $project_id);
|
|
|
})
|
|
|
->get();
|
|
|
}
|
|
|
|
|
|
$laravel_duration = microtime(true) - LARAVEL_START;
|
|
|
return view($this->bladePath . ".customer-balance", compact(
|
|
|
"customers",
|
|
|
"orderBalances",
|
|
|
"before_datetime",
|
|
|
"before_date",
|
|
|
"before_datetime_text",
|
|
|
"project_id",
|
|
|
"laravel_duration",
|
|
|
"mode"
|
|
|
));
|
|
|
}
|
|
|
|
|
|
public function fixMonthLastDayCheckout(Request $request)
|
|
|
{
|
|
|
$day = $request->day;
|
|
|
if (!$day) {
|
|
|
dd("日期不正确");
|
|
|
}
|
|
|
DB::enableQueryLog();
|
|
|
$orders = Orders::whereIn("serial", ["20201130000003", "20201130000005", "20201128000004", "20201126000006", "20201127000005", "20201126000003", "20201130000004", "20201127000008", "20201130000001", "20201126000008"])->get();
|
|
|
$orderItems = OrderItems::with(["balance", "order"])
|
|
|
->whereNotNull("paid_at")
|
|
|
->whereRaw("UNIX_TIMESTAMP(`paid_at`) > " . strtotime("2020-12-01"))
|
|
|
->whereRaw("UNIX_TIMESTAMP(`paid_at`) < " . strtotime("2020-12-04"))
|
|
|
->whereIn("order_id", $orders->pluck("id")->toArray())
|
|
|
->limit(100)->get();
|
|
|
try {
|
|
|
foreach ($orderItems as $orderItem) {
|
|
|
$new_paid_at = "{$day} 22:00:01";
|
|
|
$orderItem->update([
|
|
|
"paid_at" => $new_paid_at
|
|
|
]);
|
|
|
$orderItem->balance->update([
|
|
|
"created_at" => $new_paid_at,
|
|
|
"remark" => "本条经过时间校准处理。原始创建时间为:" . $orderItem->balance->created_at
|
|
|
]);
|
|
|
}
|
|
|
DB::commit();
|
|
|
dd("处理完毕");
|
|
|
} catch (\Exception $exception) {
|
|
|
DB::rollBack();
|
|
|
dd($exception->getMessage());
|
|
|
}
|
|
|
}
|
|
|
|
|
|
public function fixBalanceOrderId()
|
|
|
{
|
|
|
$balances = Balance::whereNull("order_id")->with("belongs")->limit("100")->get();
|
|
|
if (!$balances->count()) {
|
|
|
return $this->success("处理完毕", url($this->urlPrefix . "/overview"));
|
|
|
}
|
|
|
foreach ($balances as $balance) {
|
|
|
$balance->timestamps = false;
|
|
|
$balance->update([
|
|
|
"order_id" => $balance->belongs->order_id
|
|
|
]);
|
|
|
}
|
|
|
|
|
|
return $this->success("处理完毕" . $balances->count() . "条数据,正在进入下一批数据。", url($this->urlPrefix . "/finance/fix-balance-order-id?timer=" . time()));
|
|
|
}
|
|
|
|
|
|
public function manualQueryRecharge($id)
|
|
|
{
|
|
|
$recharge = Recharge::find($id);
|
|
|
$res = (new AlipayF2F())->manualQuery($recharge);
|
|
|
dd($res);
|
|
|
}
|
|
|
|
|
|
public function huli(Request $request)
|
|
|
{
|
|
|
$projects = (new StatisticsController())->_checkProjects();
|
|
|
$defaultProjectsId = ($projects[0]->id) ?? '';
|
|
|
$project_id = $request->get('project_id', $defaultProjectsId);
|
|
|
$month = request()->month ?? date("Y-m");
|
|
|
|
|
|
$userId = auth()->id();
|
|
|
// 判断是否护士长
|
|
|
$roleId = Role::where('name', 'like', '%护士长%')->where('guard_name', 'admin')->value('id');
|
|
|
$hushizhang = DB::table('model_has_roles')->where('role_id', $roleId)
|
|
|
->where('model_type', 'App\Admin')
|
|
|
->where('model_id', $userId)->count();
|
|
|
|
|
|
// 是否院方管理
|
|
|
$roleId = Role::where('name', 'like', '%院方管理%')->where('guard_name', 'admin')->value('id');
|
|
|
$yuanfang = DB::table('model_has_roles')->where('role_id', $roleId)
|
|
|
->where('model_type', 'App\Admin')
|
|
|
->where('model_id', $userId)->count();
|
|
|
|
|
|
$areaId = [];
|
|
|
$buildingId = [];
|
|
|
if ($hushizhang) {
|
|
|
$user = auth()->user();
|
|
|
$areaId = AdminAreaLink::where(function ($qeury) use ($project_id) {
|
|
|
if ($project_id) {
|
|
|
$qeury->where('project_id', $project_id);
|
|
|
}
|
|
|
})->where('admin_id', $user->id)->pluck('area_id');
|
|
|
} elseif ($yuanfang) {
|
|
|
$user = auth()->user();
|
|
|
$buildingId = AdminBuildingLink::where(function ($qeury) use ($project_id) {
|
|
|
if ($project_id) {
|
|
|
$qeury->where('project_id', $project_id);
|
|
|
}
|
|
|
})->where('admin_id', $user->id)->pluck('building_id');
|
|
|
}
|
|
|
$allAreas = Area::where('project_id', $project_id)->with('project', 'building')->where(function ($query) use ($areaId, $buildingId) {
|
|
|
if ($areaId) {
|
|
|
$query->whereIn('id', $areaId);
|
|
|
}
|
|
|
if ($buildingId) {
|
|
|
$query->whereIn('building_id', $buildingId);
|
|
|
}
|
|
|
})->get();
|
|
|
|
|
|
// 病区智能排序:1.数字开头按数字升序 2.中文数字开头转阿拉伯数字后升序 3.其他按myindex+id
|
|
|
$sortedAreas = $allAreas->sort(function ($a, $b) {
|
|
|
$keyA = $this->_getAreaNameSortKey($a->name ?? '', $a->myindex ?? 0, $a->id);
|
|
|
$keyB = $this->_getAreaNameSortKey($b->name ?? '', $b->myindex ?? 0, $b->id);
|
|
|
if ($keyA[0] !== $keyB[0]) {
|
|
|
return $keyA[0] <=> $keyB[0];
|
|
|
}
|
|
|
if ($keyA[1] !== $keyB[1]) {
|
|
|
return $keyA[1] <=> $keyB[1];
|
|
|
}
|
|
|
return $keyA[2] <=> $keyB[2];
|
|
|
})->values();
|
|
|
|
|
|
$perPage = 40;
|
|
|
$currentPage = (int) $request->get('page', 1);
|
|
|
$currentPage = max(1, $currentPage);
|
|
|
$items = $sortedAreas->forPage($currentPage, $perPage)->values();
|
|
|
$data = new LengthAwarePaginator($items, $sortedAreas->count(), $perPage, $currentPage, [
|
|
|
'path' => $request->url(),
|
|
|
'query' => $request->query(),
|
|
|
]);
|
|
|
$data->appends($request->all())->render();
|
|
|
|
|
|
// ===== 重构:先从 OrderItems 获取真实价格数据,生成列,然后再统计每个病区的数据 =====
|
|
|
// 1. 获取当前分页中所有病区的床位 ID
|
|
|
$areaIds = collect($data->items())->pluck('id');
|
|
|
$beds = Bed::whereIn('area_id', $areaIds)->get();
|
|
|
$bedsByArea = $beds->groupBy('area_id');
|
|
|
$allBedIds = $beds->pluck('id');
|
|
|
|
|
|
// 2. 获取这些床位在当月的所有真实子订单(仅统计 total > 0,且属于当前项目)
|
|
|
$orderItems = OrderItems::whereIn('bed_id', $allBedIds)
|
|
|
->where('total', '>', 0)
|
|
|
->where('paid_at', 'like', '%' . $month . '%')
|
|
|
->whereHas('order', function ($query) use ($project_id) {
|
|
|
$query->where('project_id', $project_id);
|
|
|
})
|
|
|
->get();
|
|
|
|
|
|
// 3. 按「真实价格」去重生成表头列(xx元/天),并取一条样本数据上的因子名称作为小字说明
|
|
|
// 使用 groupBy('total'),避免闭包分组可能导致的 array_key_exists 问题
|
|
|
$columns = $orderItems
|
|
|
->groupBy('total')
|
|
|
->map(function ($group, $total) {
|
|
|
/** @var OrderItems $sample */
|
|
|
$sample = $group->first();
|
|
|
$price = (float) $total;
|
|
|
|
|
|
$factor_item_name = '';
|
|
|
if ($sample && $sample->factors) {
|
|
|
$factors = json_decode($sample->factors, true) ?: [];
|
|
|
if (!empty($factors)) {
|
|
|
// 取第一条因子作为说明文本(前端展示不变:价格 + 小字)
|
|
|
$factor_item_name = $factors[0]['factor_item_name'] ?? '';
|
|
|
}
|
|
|
}
|
|
|
|
|
|
return [
|
|
|
'price' => $price,
|
|
|
'name' => $price . '元/天',
|
|
|
'factor_item_name' => $factor_item_name,
|
|
|
];
|
|
|
})
|
|
|
->sortBy('price')
|
|
|
->values()
|
|
|
->toArray();
|
|
|
|
|
|
// 4. 按病区 + 列价格 统计每个病区在每个价格档位上的总金额
|
|
|
$sumOrderTotal = 0;
|
|
|
foreach ($data as $item) {
|
|
|
// 当前病区所有床位 ID
|
|
|
$bedIds = $bedsByArea->get($item->id, collect())->pluck('id');
|
|
|
|
|
|
// 当前病区相关的所有子订单
|
|
|
$areaOrderItems = $orderItems->whereIn('bed_id', $bedIds->all());
|
|
|
|
|
|
// 病区总收入
|
|
|
$item->order_total = $areaOrderItems->sum('total');
|
|
|
$sumOrderTotal += $item->order_total;
|
|
|
|
|
|
// 子项:按表头列(价格)统计该病区在各价格档位上的总金额
|
|
|
$lies = [];
|
|
|
foreach ($columns as $col) {
|
|
|
$price = (float) $col['price'];
|
|
|
$colTotal = $areaOrderItems->where('total', $price)->sum('total');
|
|
|
|
|
|
$lies[] = [
|
|
|
'name' => $col['name'],
|
|
|
'factor_item_name' => $col['factor_item_name'],
|
|
|
'total_price' => $price,
|
|
|
'total' => $colTotal,
|
|
|
];
|
|
|
}
|
|
|
$item->lies = $lies;
|
|
|
}
|
|
|
|
|
|
// 表头列:使用上面生成的真实价格列(包含价格和 factor_item 名称)
|
|
|
$lie = $columns;
|
|
|
$months = $this->_getMonths();
|
|
|
|
|
|
return view($this->bladePath . ".huli", compact("sumOrderTotal", "data", "month", "lie", "projects", "project_id"));
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 获取病区名称的排序键,用于智能排序
|
|
|
* 规则:1.数字开头->按数字升序 2.中文数字开头->转阿拉伯数字后升序 3.其他->按myindex+id
|
|
|
*
|
|
|
* @return array [tier, primary_sort, secondary_sort] tier=0有数字 tier=1无数字
|
|
|
*/
|
|
|
private function _getAreaNameSortKey($name, $myindex, $id)
|
|
|
{
|
|
|
$name = trim((string) $name);
|
|
|
$myindex = (int) $myindex;
|
|
|
$id = (int) $id;
|
|
|
|
|
|
// 1. 以阿拉伯数字开头:提取数字
|
|
|
if (preg_match('/^(\d+)/', $name, $m)) {
|
|
|
return [0, (int) $m[1], 0];
|
|
|
}
|
|
|
|
|
|
// 2. 以中文数字开头:解析并转换
|
|
|
$cnNum = $this->_parseChineseNumber($name);
|
|
|
if ($cnNum !== null) {
|
|
|
return [0, $cnNum, 0];
|
|
|
}
|
|
|
|
|
|
// 3. 都不满足:按 myindex、id
|
|
|
return [1, $myindex, $id];
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 解析病区名称开头的连续中文数字,转为阿拉伯数字
|
|
|
*
|
|
|
* @return int|null 解析到的数字,若无则 null
|
|
|
*/
|
|
|
private function _parseChineseNumber($str)
|
|
|
{
|
|
|
static $digits = [
|
|
|
'〇' => 0, '零' => 0, '一' => 1, '二' => 2, '两' => 2, '三' => 3, '四' => 4,
|
|
|
'五' => 5, '六' => 6, '七' => 7, '八' => 8, '九' => 9,
|
|
|
'十' => 10, '百' => 100, '千' => 1000, '万' => 10000,
|
|
|
];
|
|
|
|
|
|
$s = preg_replace('/\s+/', '', $str);
|
|
|
if ($s === '') {
|
|
|
return null;
|
|
|
}
|
|
|
|
|
|
$len = mb_strlen($s);
|
|
|
$i = 0;
|
|
|
$result = 0;
|
|
|
$temp = 0; // 用于「十」「百」前的累积
|
|
|
|
|
|
while ($i < $len) {
|
|
|
$ch = mb_substr($s, $i, 1);
|
|
|
if (!isset($digits[$ch])) {
|
|
|
break;
|
|
|
}
|
|
|
$val = $digits[$ch];
|
|
|
|
|
|
if ($val >= 10) {
|
|
|
// 十、百、千、万:乘数
|
|
|
if ($temp === 0) {
|
|
|
$temp = 1;
|
|
|
}
|
|
|
$result += $temp * $val;
|
|
|
$temp = 0;
|
|
|
} else {
|
|
|
$temp = $val;
|
|
|
}
|
|
|
$i++;
|
|
|
}
|
|
|
$result += $temp;
|
|
|
|
|
|
if ($i === 0) {
|
|
|
return null;
|
|
|
}
|
|
|
return $result;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 获取动态列
|
|
|
*/
|
|
|
public function getLies($bedIds, $productItem, $factor, $month)
|
|
|
{
|
|
|
$list = [];
|
|
|
|
|
|
// 修复:如果床位ID为空,直接返回空数组,避免 whereIn 空数组导致的SQL错误
|
|
|
if (empty($bedIds)) {
|
|
|
return $list;
|
|
|
}
|
|
|
|
|
|
foreach ($productItem as $item) {
|
|
|
foreach ($factor as $factor_item) {
|
|
|
$query = OrderItems::where('product_item_id', $item->id)
|
|
|
->whereIn("bed_id", $bedIds)
|
|
|
->where('paid_at', 'like', '%' . $month . '%');
|
|
|
|
|
|
// 使用 MySQL 5.7 的 JSON_SEARCH 精确匹配包含指定 factor_item_id 的子订单
|
|
|
$factorItemId = (int) $factor_item->id;
|
|
|
$query->whereRaw("JSON_SEARCH(factors, 'one', ?, NULL, '$[*].factor_item_id') IS NOT NULL", [$factorItemId]);
|
|
|
|
|
|
// 1)列对应的真实总收入:该因子 + 产品子项 + 病区 + 月份 下所有子订单的 total 之和
|
|
|
$total = (float) $query->sum('total');
|
|
|
|
|
|
// 2)表头展示的价格:按“公式”计算,保证不是 0(近似真实下单价)
|
|
|
// 价格 = 产品子项基础价 + 因子价格
|
|
|
$totalPrice = (float) $item->price + (float) $factor_item->price;
|
|
|
|
|
|
$list[] = [
|
|
|
'name' => $totalPrice . '元/天',
|
|
|
'factor_item_name' => $factor_item->name ?? '',
|
|
|
'total_price' => $totalPrice,
|
|
|
'product_item_id' => $item->id,
|
|
|
'factor_item_id' => $factor_item->id,
|
|
|
'total' => $total
|
|
|
];
|
|
|
}
|
|
|
}
|
|
|
return $list;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 床位统计
|
|
|
* @return \Illuminate\Contracts\Foundation\Application|\Illuminate\Contracts\View\Factory|\Illuminate\View\View
|
|
|
*/
|
|
|
public function bed()
|
|
|
{
|
|
|
$is_export = \request('is_export', 0);
|
|
|
$projects = $this->_checkProjects();
|
|
|
if (!$projects->count()) {
|
|
|
return $this->error($this->noProjects);
|
|
|
}
|
|
|
$project_id = request()->project_id ?? $projects->first()->id;
|
|
|
$project = Project::find($project_id);
|
|
|
|
|
|
$month = request()->month ?? date("Y-m");
|
|
|
$months = $this->_getMonths();
|
|
|
// 当月天数
|
|
|
$days = date('t', strtotime($month));
|
|
|
$area = Area::withCount('beds')->where('project_id', $project_id)->get();
|
|
|
$beds = Bed::whereIn('area_id', $area->pluck('id'))->where('project_id', $project_id)->get();
|
|
|
$totalBed = $beds->count();
|
|
|
// 订单总数
|
|
|
$orderTotal = Orders::where('project_id', $project_id)
|
|
|
->where('created_at', 'like', '%' . $month . '%')
|
|
|
->whereIn('bed_id', $beds->pluck('id'))
|
|
|
->count();
|
|
|
foreach ($area as $item) {
|
|
|
// 床位占比
|
|
|
$item->bed_rate = 0;
|
|
|
if ($totalBed) {
|
|
|
$item->bed_rate = round($item->beds_count / $totalBed, 4) * 100;
|
|
|
}
|
|
|
// 订单数
|
|
|
$bedsIdTemp = Bed::where('area_id', $item->id)->where('project_id', $project_id)->pluck('id');
|
|
|
$item->order_total = OrderItems::where('created_at', 'like', '%' . $month . '%')
|
|
|
->where('total', '>', 0)
|
|
|
->whereIn('bed_id', $bedsIdTemp)
|
|
|
->count();
|
|
|
$item->rate = 0;
|
|
|
if ($bedsIdTemp->count()) {
|
|
|
// 配比
|
|
|
$item->rate = round($item->order_total / ($days * $bedsIdTemp->count()), 4) * 100;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// 导出
|
|
|
if ($is_export) {
|
|
|
$area = $area->toArray();
|
|
|
$spreadsheet = new Spreadsheet();
|
|
|
$sheet = $spreadsheet->getActiveSheet();
|
|
|
$sheet->setCellValue('A1', '病区');
|
|
|
$sheet->setCellValue('B1', '床位数量');
|
|
|
$sheet->setCellValue('C1', '床位占比');
|
|
|
$sheet->setCellValue('D1', '陪护人天');
|
|
|
$sheet->setCellValue('E1', '陪护率');
|
|
|
|
|
|
$count = count($area); //计算有多少条数据
|
|
|
for ($i = 2; $i <= $count + 1; $i++) {
|
|
|
$sheet->setCellValue('A' . $i, $area[$i - 2]['name']);
|
|
|
$sheet->setCellValue('B' . $i, $area[$i - 2]['beds_count']);
|
|
|
$sheet->setCellValue('C' . $i, $area[$i - 2]['bed_rate']);
|
|
|
$sheet->setCellValue('D' . $i, $area[$i - 2]['order_total']);
|
|
|
$sheet->setCellValue('E' . $i, $area[$i - 2]['rate']);
|
|
|
}
|
|
|
header('Content-Type: application/vnd.ms-excel');
|
|
|
header('Content-Disposition: attachment;filename="' . $project->name . '_' . date('YmdHis') . '.xlsx"');
|
|
|
header('Cache-Control: max-age=0');
|
|
|
$writer = new Xlsx($spreadsheet);
|
|
|
$writer->save('php://output');
|
|
|
exit;
|
|
|
}
|
|
|
return view($this->bladePath . ".bed", compact("area", "orderTotal", "totalBed", "project", "project_id", "month", "projects"));
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 收入统计
|
|
|
* @return \Illuminate\Contracts\Foundation\Application|\Illuminate\Contracts\View\Factory|\Illuminate\View\View
|
|
|
*/
|
|
|
public function income()
|
|
|
{
|
|
|
$is_export = \request('is_export', 0);
|
|
|
$projects = $this->_checkProjects();
|
|
|
if (!$projects->count()) {
|
|
|
return $this->error($this->noProjects);
|
|
|
}
|
|
|
$project_id = request()->project_id ?? $projects->first()->id;
|
|
|
$project = Project::find($project_id);
|
|
|
|
|
|
$month = request()->month ?? date("Y-m");
|
|
|
$months = $this->_getMonths();
|
|
|
// 当月天数
|
|
|
$days = date('t', strtotime($month));
|
|
|
$areaList = Area::withCount('beds')->where('project_id', $project_id)->get();
|
|
|
// 合计
|
|
|
$total['order_total'] = $total['shouxufei'] = $total['zengshishui'] = $total['shijishouru'] = $total['guanlifei'] = 0;
|
|
|
$area = [];
|
|
|
foreach ($areaList as $item) {
|
|
|
$beds = Bed::where('area_id', $item->id)->where('project_id', $project_id)->get();
|
|
|
$orderTotal = OrderItems::where('paid_at', 'like', '%' . $month . '%')
|
|
|
->whereIn('bed_id', $beds->pluck('id'))
|
|
|
->sum("total");
|
|
|
$item->order_total = $orderTotal;
|
|
|
$item->shouxufei = round($orderTotal * 0.006, 2);
|
|
|
$item->zengshishui = round($orderTotal * 0.06, 2);
|
|
|
$item->shijishouru = round($orderTotal - $item->shouxufei - $item->zengshishui, 2);
|
|
|
$item->guanlifei = round($item->shijishouru * 0.06, 2);
|
|
|
if (!empty($item->order_total)) {
|
|
|
$area[] = $item;
|
|
|
}
|
|
|
// 合计
|
|
|
$total['order_total'] += $item->order_total;
|
|
|
$total['shouxufei'] += $item->shouxufei;
|
|
|
$total['zengshishui'] += $item->zengshishui;
|
|
|
$total['shijishouru'] += $item->shijishouru;
|
|
|
$total['guanlifei'] += $item->guanlifei;
|
|
|
}
|
|
|
$refund['order_total'] = abs(Balance::where('created_at', 'like', '%' . $month . '%')
|
|
|
->where('belongs_type', 'App\Models\Refund')
|
|
|
->whereHas("order", function ($query) use ($project_id) {
|
|
|
$query->where("project_id", $project_id);
|
|
|
})->sum("money"));
|
|
|
$refund['shijishouru'] = $refund['order_total'];
|
|
|
$refund['guanlifei'] = round($refund['order_total'] * 0.06, 2);
|
|
|
// 总计
|
|
|
$zongji['order_total'] = $total['order_total'] - $refund['order_total'];
|
|
|
$zongji['shouxufei'] = $total['shouxufei'] * 2;
|
|
|
$zongji['zengshishui'] = $total['zengshishui'] * 2;
|
|
|
$zongji['shijishouru'] = $total['shijishouru'] - $refund['shijishouru'];
|
|
|
$zongji['guanlifei'] = $total['guanlifei'] - $refund['guanlifei'];
|
|
|
|
|
|
$admin = Auth::guard("admin")->user();
|
|
|
return view($this->bladePath . ".income", compact("admin", "zongji", "refund", "total", "area", "project", "project_id", "month", "projects"));
|
|
|
}
|
|
|
|
|
|
}
|