paramedic_id && $this->project->agreement == 1 ); if ($this->paramedic_id && $this->project->agreement == 1 && strtotime($this->created_at) >= strtotime(Orders::AGREEMENT_START_DATE) && ($this->orderAgreements->isEmpty() || ($this->orderAgreements->isNotEmpty() && $this->orderAgreements[0]->paramedic_id != $this->paramedic_id))) { return 1; } return 0; } public function getStatusLabelAttribute($pure_text = true) { switch ($this->status) { case self::STATUS_UNCONFIRMED: $text = self::TEXT_UNCONFIRMED; return $pure_text !== false ? $text : "$text"; break; case self::STATUS_UNASSIGNED: $text = self::TEXT_UNASSIGNED; return $pure_text !== false ? $text : "$text"; break; case self::STATUS_ONGOING: $text = self::TEXT_ONGOING; return $pure_text !== false ? $text : "$text"; break; case self::STATUS_FINISHED: $text = self::TEXT_FINISHED; return $pure_text !== false ? $text : "$text"; break; default: return $this->status; } } public function isPending() { return in_array($this->status, [self::STATUS_UNCONFIRMED, self::STATUS_UNASSIGNED]); } public function orderAgreements() { return $this->hasMany(OrderAgreement::class, "order_id", "id"); } public function orderAgreementByLast() { return $this->hasOne(OrderAgreement::class, "order_id", "id")->orderBy("id", "desc"); } public function isOngoing() { return $this->status == self::STATUS_ONGOING; } public function getStatusNameAttribute() { return $this->getStatusLabelAttribute(); } public function getDaysAttribute() { return Carbon::parse($this->from_date)->diffInDays($this->to_date) + 1; } protected static function booted() { static::addGlobalScope(new AdminProjectScope()); static::updating(function (Orders $order) { if ($order->isClean()) return; $dirty = $order->getDirty(); foreach ($dirty as $k => $v) { $original_v = $order->getOriginal($k); if (is_numeric($v) && is_numeric($original_v) && floatval($v) == floatval($original_v)) { unset($dirty[$k]); } if ($k == "updated_at") { unset($dirty[$k]); } } if (empty($dirty)) { return; } $guards = array_keys((array)config("auth.guards")); $user = null; foreach ($guards as $guard) { if ($user) continue; $user = Auth::guard($guard)->user(); } $last_batch = (new OrderAudit())->max("batch"); $batch = (int)$last_batch + 1; $audits = []; foreach ($dirty as $k => $v) { $audits[] = [ "batch" => $batch, "field_name" => $k, "old_value" => $order->getOriginal($k), "new_value" => $v, "operator_type" => ($user ? get_class($user) : null), "operator_id" => ($user ? $user->id : null), ]; } $order->audits()->createMany($audits); }); } public function scopeOfCustomer($query, $customer_id) { return $query->whereIn('customer_id', (array)$customer_id); } public function scopeOfManager($query, $manager_id) { return $query->whereIn('manager_id', (array)$manager_id); } public function scopeOfProject($query, $project_id) { return $query->whereIn('project_id', (array)$project_id); } public function audits() { return $this->hasMany(OrderAudit::class, "order_id", "id"); } public function firstItem() { return $this->hasOne(OrderItems::class, "order_id"); } public function lastItem() { return $this->hasOne(OrderItems::class, "order_id"); } public function orderItems() { return $this->hasMany(OrderItems::class, "order_id")->with([ "paramedic" => function ($query) { $query ->select("paramedic.id", "paramedic.name", "paramedic.avatar", "paramedic.sex") ->leftJoin("paramedic_level", "paramedic_level.id", "=", "paramedic.paramedic_level_id") ->addSelect("paramedic_level.name as paramedic_level_name"); }, "bed" => function ($query) { $query->select("bed.id", "bed.name") ->leftJoin("building", "building.id", "=", "bed.building_id") ->leftJoin("area", "area.id", "=", "bed.area_id") ->leftJoin("room", "room.id", "=", "bed.room_id") ->addSelect("room.name as room_name", "area.name as area_name", "building.name as building_name"); } ]); } public function customer() { return $this->belongsTo(Customer::class)->select(["id", "name", "mobile", "username", "sex", "balance", "openid", "unionid"]); } public function patient() { return $this->belongsTo(Patient::class); } public function project() { return $this->belongsTo(Project::class); } public function product() { return $this->belongsTo(Product::class); } public function manager() { return $this->belongsTo(Manager::class)->select(["id", "name", "mobile", "username", "sex", "openid", "unionid"]); } 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 wechatpayAccount() { return $this->hasOneThrough(WechatpayAccount::class, Project::class, "id", "id", "project_id", "wechatpay_account_id"); } public function alipayAccount() { return $this->hasOneThrough(AlipayAccount::class, Project::class, "id", "id", "project_id", "alipay_account_id"); } public function bed() { return $this->belongsTo(Bed::class); } public function room() { return $this->hasOneThrough(Room::class, Bed::class, "id", "id", "bed_id", "room_id"); } public function area() { return $this->hasOneThrough(Area::class, Bed::class, "id", "id", "bed_id", "area_id"); } public function building() { return $this->hasOneThrough(Building::class, Bed::class, "id", "id", "bed_id", "building_id"); } public function paramedic() { return $this->belongsTo(Paramedic::class); } public function recharges() { return $this ->hasMany(Recharge::class, "order_id", "id") ->whereNotNull("paid_at") ->select("recharge.id", "recharge.order_id", "recharge.manager_id", "recharge.serial", "recharge.money", "recharge.payment", "recharge.payment_serial", "recharge.remark", "recharge.created_at") ->leftJoin("managers", "managers.id", "=", "recharge.manager_id") ->addSelect("managers.name as manager_name") ->orderBy("id", "desc"); } public function refunds() { return $this->hasMany(Refund::class, "order_id", "id") ->whereNotNull("paid_at") ->orderBy("id", "desc"); } public function getSerial() { if ($this->serial) { return $this; } $daily_index = (new Orders())->where("id", "<", $this->id)->whereRaw("DATEDIFF(`created_at`,'" . $this->created_at . "') = 0")->withTrashed()->count(); $serial = date("Ymd", strtotime($this->created_at)) . sprintf("%06d", ($daily_index + 1)); $this->update(["serial" => $serial]); return $this; } public function refreshTotal() { $order_items = $this->orderItems()->get(); switch ($this->status) { case self::STATUS_FINISHED: $total = $order_items->sum("total"); break; case self::STATUS_UNCONFIRMED: case self::STATUS_UNASSIGNED: case self::STATUS_ONGOING: default: $items_total = $order_items->sum("total"); $price = $this->price; if ($order_items->last()) { $days = max(0, Carbon::parse($order_items->last()->service_date)->diffInDays($this->to_date, false)); if (Carbon::parse($this->to_date)->diffInDays($order_items->last()->service_date, false) > 0) { $this->to_date = $order_items->last()->service_date; } } else { $days = max(0, Carbon::parse($this->from_date)->diffInDays($this->to_date, false) + 1); } $un_generated_total = $price * $days; $total = $items_total + $un_generated_total; break; } $paid_total = $order_items->filter(function ($item) { return $item->paid_at; })->sum("total"); $this->paid_total = $paid_total; $this->total = $total; $this->save(); return $this; } public function requestFactorsToOrderFactors() { $request_factors = (array)json_decode(request()->factors, true); $factors = []; foreach ($request_factors as $factor) { $factor_item = FactorItems::join("factor", "factor_items.factor_id", "=", "factor.id") ->where("factor_items.id", $factor["factor_item_id"]) ->select( "factor_items.id as factor_item_id", "factor_items.name as factor_item_name", "factor_items.price", "factor_items.factor_id", "factor_items.fee", "factor_items.fee_percent", "factor.name as factor_name", "factor.used_for_fee" ) ->first(); $factors[] = $factor_item->toArray(); } return $factors; } public function orderFactorsToRequestArray($order_factors = false) { $order_factors === false ? $order_factors = $this->factors : ""; if (!$order_factors) { return []; } $order_factors = (array)json_decode($order_factors, true); $factors = []; foreach ($order_factors as $factor) { $factors[] = [ "id" => $factor["factor_id"], "factor_item_id" => $factor["factor_item_id"] ]; } return $factors; } public function determineOrderFactorsIsDirty($order_factors = false) { if (!isset(request()->factors)) { return false; } $request_factors = json_decode(request()->factors, true); $request_factors = collect((array)$request_factors)->pluck("factor_item_id", "id")->sortKeys(); $order_factors_to_request_factors = $this->orderFactorsToRequestArray($order_factors); $order_factors_to_request_factors = collect((array)$order_factors_to_request_factors)->pluck("factor_item_id", "id")->sortKeys(); return $request_factors->diffAssoc($order_factors_to_request_factors)->count(); } //获取可用护工 public function getAvailableParamedics() { DB::enableQueryLog(); $request = request(); $bed = (new Bed())->find($request->bed_id); $date = $request->start_date ?? date("Y-m-d"); $model = new Paramedic(); $model = $model->where("project_id", $bed->project_id); $model = $model->where("status", 1); $model = $model->with(["project", "levelInProject"]); $model = $model->withCount(["orders"]); $model = $model->select("id", "name", "avatar", "sex", "birthday", "hometown", "work_years", "paramedic_level_id", "project_id", "has_health_certificate", "has_work_certificate"); //性别筛选:如果是女患者,选择女的护工 if ($request->sex == "女") { $model = $model->where("sex", "女"); } //todo:护工所在病区筛选 //一对N的数量排序 $model->withCount(["orders as ongoing_orders_count" => function ($query) use ($date) { //todo:与日期及自动结单关联 $query->where("status", Orders::STATUS_ONGOING); }]); $model = $model->orderBy("ongoing_orders_count"); //同房间的排序 $model->withCount(["orders as ongoing_orders_count_in_same_room" => function ($query) use ($date, $bed) { //todo:与日期及自动结单关联 $query->where("status", Orders::STATUS_ONGOING)->whereHas("room", function ($query) use ($bed) { $query->whereRaw("`room`.`id` = {$bed->room_id}"); }); }]); $model = $model->orderBy("ongoing_orders_count_in_same_room", "desc"); //同病区其他房间的病床排序 $model->withCount(["orders as ongoing_orders_count_in_same_area" => function ($query) use ($date, $bed) { //todo:与日期及自动结单关联 $query->where("status", Orders::STATUS_ONGOING)->whereHas("area", function ($query) use ($bed) { $query->whereRaw("`area`.`id` = {$bed->area_id}"); }); }]); $model = $model->orderBy("ongoing_orders_count_in_same_area", "desc"); $page_size = 3; $paramedics = $model->limit($page_size)->get(); //价格运算 $factors = (new Orders())->requestFactorsToOrderFactors(); $product = (new Project())->find($bed->project_id)->products->first(); foreach ($paramedics as $paramedic) { $product_item = ProductItems::where("product_id", $product->id)->where("patient_quantity", "<=", $paramedic->ongoing_orders_count + 1)->orderBy("patient_quantity", "desc")->first(); $_product_item_price = $product_item->price ?? 0; $_paramedic_price = $paramedic->levelInProject->price ?? 0; $price = $_product_item_price + $_paramedic_price; foreach ($factors as $factor) { $_factor_price = $factor["price"] ?? 0; $price += $_factor_price; } $paramedic->price = $price; } $result = []; $result[$date] = $paramedics->toArray(); return $result; } public function getOnlineRefundableRecharge($amount) { //todo:根据交易状态是否可以退款、以及多次退款金额是否足够进行更精准筛选 //but:出问题的几率微乎其微可以忽略 $recharge = Recharge::where("order_id", $this->id) ->where("merchant_id", "<>", "1621928535") //忽略微信支付的琳颖账户,2024-08-29 ->whereNotNull("paid_at") ->whereIn("payment", ["weixin", "alipay"]) ->whereNotNull("merchant_id") ->where("money", ">=", $amount) ->doesntHave("refunds") ->orderBy("id", "desc") ->first(); return $recharge; } }