total == 0) { return "未服务"; } if ($this->paid_at) { $next_month = date("m", strtotime("+1 month", strtotime(date("Y-m", strtotime($this->paid_at))))); return "已扣款,{$next_month}月结工资"; } else { return "未扣款"; } } public function order() { return $this->belongsTo(Orders::class); } public function siblings() { return $this->hasManyThrough(OrderItems::class, Orders::class, "id", "order_id", "order_id", "id"); } public function customer() { return $this->hasOneThrough(Customer::class, Orders::class, "id", "id", "order_id", "customer_id"); } public function product() { return $this->hasOneThrough(Product::class, ProductItems::class, "id", "id", "product_item_id", "product_id")->withTrashedParents(); } public function productItem() { return $this->belongsTo(ProductItems::class); } public function productParamedicLevel() { return $this->belongsTo(ProductParamedicLevel::class); } public function paramedicLevel() { return $this->hasOneThrough(ParamedicLevel::class, ProductParamedicLevel::class, "id", "id", "product_paramedic_level_id", "paramedic_level_id"); } public function bed() { return $this->belongsTo(Bed::class)->withTrashed(); } public function room() { return $this->hasOneThrough(Room::class, Bed::class, "id", "id", "bed_id", "room_id")->withTrashed(); } public function building() { return $this->hasOneThrough(Building::class, Bed::class, "id", "id", "bed_id", "building_id")->withTrashed(); } public function area() { return $this->hasOneThrough(Area::class, Bed::class, "id", "id", "bed_id", "area_id")->withTrashed(); } public function paramedic() { return $this->belongsTo(Paramedic::class)->withTrashed(); } public function createItem($order_id, $service_date) { $record = (new OrderItems())->where([ "order_id" => $order_id, "service_date" => $service_date ])->first(); if ($record) { return $record; } $order = (new Orders())->find($order_id); $patient_quantity = (new Orders()) ->where("status", Orders::STATUS_ONGOING) ->where("paramedic_id", $order->paramedic_id) ->count(); $order_item = [ "order_id" => $order->id, "product_item_id" => $order->product_item_id, "product_paramedic_level_id" => $order->product_paramedic_level_id, "bed_id" => $order->bed_id, "paramedic_id" => $order->paramedic_id, "service_date" => $service_date, "patient_quantity" => $patient_quantity, "total" => $order->price, "factors" => $order->factors ]; return $this->create($order_item); } public function updateTodayItem($order_id) { $service_date = date("Y-m-d"); $record = (new OrderItems())->where([ "order_id" => $order_id, "service_date" => $service_date ])->first(); if (!$record) { return [ "status" => 0, "msg" => "没找到当日子订单" ]; } if ($record->paid_at) { return [ "status" => 0, "msg" => "当日子订单已扣款,请移步至子订单修改" ]; } $order = (new Orders())->find($order_id); $patient_quantity = (new Orders()) ->where("status", Orders::STATUS_ONGOING) ->where("paramedic_id", $order->paramedic_id) ->count(); $update = [ "product_item_id" => $order->product_item_id, "product_paramedic_level_id" => $order->product_paramedic_level_id, "bed_id" => $order->bed_id, "paramedic_id" => $order->paramedic_id, "patient_quantity" => $patient_quantity, "total" => $order->price, "factors" => $order->factors ]; $record->update($update); return [ "status" => 1, "msg" => "当日子订单同步成功" ]; } public function calculateFee() { $factors = json_decode($this->factors); $factor_texts = []; if ($factors) { foreach ($factors as $factor_item) { if ($factor_item->used_for_fee) { $add_text = "(管理费{$factor_item->fee_percent}%+{$factor_item->fee})"; } else { $add_text = ""; } $factor_texts[] = "{$factor_item->factor_name}:{$factor_item->factor_item_name}{$add_text}"; } } $this->factor_texts = $factor_texts; // 标志变量:是否成功计算了管理费 $feeCalculated = false; if (!$this->product) { // 没有 product 时设置默认值(不扣除管理费) $this->paramedic_total = $this->total ?? 0; $this->fee = 0; return $this; } switch ($this->product->fee_type) { case "factor": $factor = collect($factors)->filter(function ($item) { return $item->used_for_fee; })->first(); if (!$factor) { //todo:检查factors为什么没有进去、缺失的factors已经手工补录进去了 $factorModel = (new Factor()) ->with("factorItems") ->where("product_id", $this->product->id) ->where("used_for_fee", 1) ->first(); if ($factorModel && $factorModel->factorItems) { $factor = $factorModel->factorItems->first(); } } if (!$factor) { // 找不到因子时设置默认值(不扣除管理费) $this->paramedic_total = $this->total ?? 0; $this->fee = 0; return $this; } //todo:考虑不同项目的情况,目前是全部统一 if (!$this->order) { // 没有 order 时设置默认值(不扣除管理费) $this->paramedic_total = $this->total ?? 0; $this->fee = 0; return $this; } $holidays = cache("holidays_" . $this->order->project_id); if (!$holidays) { $holidays = Holiday::where("project_id", $this->order->project_id)->get()->keyBy("date")->toArray(); cache(['holidays' . $this->order->project_id => $holidays], now()->addSeconds(90)); //只保存较短时间,省却了更新节假日时的缓存更新机制 } if (in_array($this->service_date, array_keys($holidays))) { $fee = $factor->fee_percent * ($this->total / $holidays[$this->service_date]["price_ratio"]) / 100 + $factor->fee - $this->fee_free; } else { $fee = $factor->fee_percent * $this->total / 100 + $factor->fee - $this->fee_free; } $paramedic_total = $this->total - $fee; $this->paramedic_total = $paramedic_total; $this->fee = $fee; $feeCalculated = true; break; } // 兜底逻辑:如果管理费没有被计算(通常是 fee_type 不是 "factor" 的情况),使用默认值 if (!$feeCalculated) { $this->paramedic_total = $this->total ?? 0; $this->fee = 0; } return $this; } public function autoCheckout() { $threshold = 50; $last_id = cache("last_auto_checkout_order_item_id", 0); Log::channel("daily_auto_checkout")->info("Last id:" . $last_id); // 获取所有状态为1的项目 $projects = Project::where("status", 1)->pluck("id")->toArray(); $unpaid_order_items = (new OrderItems()) ->whereHas("order", function ($query) use ($projects) { $query->where("status", Orders::STATUS_ONGOING) ->whereIn("project_id", $projects); }) ->where("total", ">", 0) ->whereNull("paid_at") ->where("id", ">", $last_id) ->with("customer"); $unpaid_order_items = $unpaid_order_items ->orderBy("id") ->limit($threshold) ->get(); if (!$unpaid_order_items->count()) { cache(['last_auto_checkout_order_item_id' => null], now()->addSeconds(90)); return; } Log::channel("daily_auto_checkout")->info("From " . $unpaid_order_items->first()->id . " to " . $unpaid_order_items->last()->id); foreach ($unpaid_order_items as $item) { $customer = $item->customer; if ($customer->balance < $item->total || $item->total == 0) { continue; } $item->update(["paid_at" => date("Y-m-d H:i:s")]); $balance = $customer->balance - $item->total; (new Balance())->create([ "customer_id" => $customer->id, "order_id" => $item->order_id, "belongs_type" => get_class($item), "belongs_id" => $item->id, "money" => -$item->total, "balance" => $balance ]); $customer->update(["balance" => $balance]); Log::channel("daily_auto_checkout")->info($item->id . "扣款成功"); } cache(['last_auto_checkout_order_item_id' => $unpaid_order_items->last()->id], now()->addSeconds(90)); } public function balance() { return $this->hasOne(Balance::class, "belongs_id")->where("belongs_type", self::class); } }