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 getStatusNameAttribute() { return $this->getStatusLabelAttribute(); } 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 (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")->with([ "productItem", "productParamedicLevel", "bed", "paramedic" ]); } public function lastItem() { return $this->hasOne(OrderItems::class, "order_id")->with([ "productItem", "productParamedicLevel", "bed", "paramedic" ])->orderBy("id", "desc"); } public function orderItems() { return $this->hasMany(OrderItems::class, "order_id")->with([ "productItem", "productParamedicLevel", "bed", "paramedic" ]); } public function handlingApprovalItem() { return $this->morphOne(ApprovalItems::class, "belongs")->whereHas("approval", function ($query) { $query->where("status", Approval::STATUS_HANDLING)->whereRaw(" TIMESTAMPDIFF(SECOND,DATE_FORMAT(NOW(),'%Y-%m-%d %H:%i:%s'),`expire_at`) > 0 "); })->orderBy("id", "desc"); } public function lastApproval() { return $this->hasOne(Approval::class, "order_id", "id")->orderBy("id", "desc"); } 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 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"); } public function refunds() { return $this->hasMany(Refund::class, "order_id", "id")->whereNotNull("paid_at"); } 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_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)); } 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; case self::STATUS_FINISHED: $total = $this->orderItems()->sum("total"); } if ($order_items->last()) { if (!$this->to_date || Carbon::parse($this->to_date)->diffInDays($order_items->last()->service_date, false) > 0) { $this->to_date = $order_items->last()->service_date; } } $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 determineNeedApprovePriceChange($new_price) { //todo:根据更多变化情形判断 return $this->price != $new_price; } public function getLastDayPriceOfNow() { $lastday_price_rules = $this->product->lastdayCheckoutRules; $price = $this->price; $now_rule = null; foreach ($lastday_price_rules as $rule) { if ($now_rule) { continue; } if (time() < strtotime(date("Y-m-d") . " " . $rule->before_time)) { $now_rule = $rule; } } if ($now_rule) { $price = $now_rule->percent / 100 * $price; } return $price; } public function autoCheckout() { $threshold = 50; $orders = $this::whereIn("status", [self::STATUS_ONGOING]) //已经开始 ->whereRaw("DATEDIFF(`from_date`, now()) <= 0") //今日结束 ->whereRaw("DATEDIFF(`to_date`, now()) = 0") //设定了自动结单的 ->where("auto_checkout", 1) //今日子订单已生成 ->whereHas("orderItems", function ($query) { $query->whereRaw("DATEDIFF(`service_date`, now()) = 0"); }) ->orderBy("id") ->limit($threshold) ->get(); foreach ($orders as $order) { //todo:自动结算订单 } } public function generateTodayOrderItems() { $threshold = 50; DB::enableQueryLog(); if ($this->id) { $unGeneratedOrders = (new Orders())->where("id", $this->id)->get(); } else { //获取正在进行中的订单,即使已经到了截止日,只要状态是在进行中的都继续生成 $unGeneratedOrders = $this::whereIn("status", [self::STATUS_ONGOING]) ->whereRaw("DATEDIFF(`from_date`, now()) <= 0") ->whereDoesntHave("orderItems", function ($query) { $query->whereRaw("DATEDIFF(`service_date`, now()) = 0"); }) ->orderBy("id") ->limit($threshold) ->get(); } foreach ($unGeneratedOrders as $order) { $service_date = date("Y-m-d"); $res = $order->createItem($service_date); } } public function createItem($service_date) { $patient_quantity = (new Orders()) ->where("status", self::STATUS_ONGOING) ->where("paramedic_id", $this->paramedic_id) ->count(); $order_item = [ "product_item_id" => $this->product_item_id, "product_paramedic_level_id" => $this->product_paramedic_level_id, "bed_id" => $this->bed_id, "paramedic_id" => $this->paramedic_id, "service_date" => $service_date, "patient_quantity" => $patient_quantity, "total" => $this->price, "fee" => $this->fee, "paramedic_total" => ($this->price - $this->fee), "factors" => $this->factors ]; return $this->orderItems()->create($order_item); } 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(); } }