You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

310 lines
10 KiB

5 years ago
<?php
namespace App\Models;
use App\Customer;
5 years ago
use Carbon\Carbon;
5 years ago
use Illuminate\Support\Facades\DB;
5 years ago
use Illuminate\Support\Facades\Log;
5 years ago
class OrderItems extends SoftDeletesModel
{
protected $table = "order_items";
3 years ago
const PREV_MONTH = "往月服务单";
5 years ago
5 years ago
protected $appends = ["paid_status"];
public function getPaidStatusAttribute()
{
5 years ago
if ($this->total == 0) {
5 years ago
return "未服务";
}
if ($this->paid_at) {
3 years ago
$next_month = date("m", strtotime("+1 month", strtotime(date("Y-m", strtotime($this->paid_at)))));
3 years ago
return "已扣款,{$next_month}月结工资";
5 years ago
} else {
return "未扣款";
}
}
5 years ago
public function order()
{
return $this->belongsTo(Orders::class);
}
3 years ago
public function siblings()
{
return $this->hasManyThrough(OrderItems::class, Orders::class, "id", "order_id", "order_id", "id");
4 years ago
}
5 years ago
public function customer()
{
5 years ago
return $this->hasOneThrough(Customer::class, Orders::class, "id", "id", "order_id", "customer_id");
5 years ago
}
public function product()
{
3 months ago
return $this->hasOneThrough(Product::class, ProductItems::class, "id", "id", "product_item_id", "product_id")
->withoutGlobalScope(\App\Scopes\AdminProjectScope::class)
->withTrashedParents();
5 years ago
}
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()
{
5 years ago
return $this->belongsTo(Bed::class)->withTrashed();
5 years ago
}
public function room()
{
5 years ago
return $this->hasOneThrough(Room::class, Bed::class, "id", "id", "bed_id", "room_id")->withTrashed();
5 years ago
}
public function building()
{
5 years ago
return $this->hasOneThrough(Building::class, Bed::class, "id", "id", "bed_id", "building_id")->withTrashed();
5 years ago
}
public function area()
{
5 years ago
return $this->hasOneThrough(Area::class, Bed::class, "id", "id", "bed_id", "area_id")->withTrashed();
5 years ago
}
public function paramedic()
{
2 years ago
return $this->belongsTo(Paramedic::class)->withTrashed();
5 years ago
}
5 years ago
public function createItem($order_id, $service_date)
5 years ago
{
5 years ago
$record = (new OrderItems())->where([
"order_id" => $order_id,
"service_date" => $service_date
])->first();
if ($record) {
return $record;
}
5 years ago
5 years ago
$order = (new Orders())->find($order_id);
5 years ago
$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
];
5 years ago
return $this->create($order_item);
5 years ago
}
5 years ago
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" => "当日子订单同步成功"
];
}
5 years ago
public function calculateFee()
{
$factors = json_decode($this->factors);
$factor_texts = [];
3 months ago
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}";
5 years ago
}
}
$this->factor_texts = $factor_texts;
3 months ago
// 标志变量:是否成功计算了管理费
$feeCalculated = false;
3 months ago
if (!$this->product) {
3 months ago
// 没有 product 时设置默认值(不扣除管理费)
$this->paramedic_total = $this->total ?? 0;
$this->fee = 0;
3 months ago
return $this;
}
5 years ago
switch ($this->product->fee_type) {
case "factor":
$factor = collect($factors)->filter(function ($item) {
return $item->used_for_fee;
})->first();
if (!$factor) {
//todo:检查factors为什么没有进去、缺失的factors已经手工补录进去了
3 months ago
$factorModel = (new Factor())
5 years ago
->with("factorItems")
->where("product_id", $this->product->id)
->where("used_for_fee", 1)
->first();
3 months ago
if ($factorModel && $factorModel->factorItems) {
$factor = $factorModel->factorItems->first();
}
}
if (!$factor) {
3 months ago
// 找不到因子时设置默认值(不扣除管理费)
$this->paramedic_total = $this->total ?? 0;
$this->fee = 0;
3 months ago
return $this;
5 years ago
}
3 years ago
//todo:考虑不同项目的情况,目前是全部统一
3 months ago
if (!$this->order) {
3 months ago
// 没有 order 时设置默认值(不扣除管理费)
$this->paramedic_total = $this->total ?? 0;
$this->fee = 0;
3 months ago
return $this;
}
3 years ago
$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;
}
5 years ago
$paramedic_total = $this->total - $fee;
$this->paramedic_total = $paramedic_total;
$this->fee = $fee;
3 months ago
$feeCalculated = true;
5 years ago
break;
}
3 months ago
// 兜底逻辑:如果管理费没有被计算(通常是 fee_type 不是 "factor" 的情况),使用默认值
if (!$feeCalculated) {
3 months ago
$this->paramedic_total = $this->total ?? 0;
3 months ago
$this->fee = 0;
3 months ago
}
3 months ago
5 years ago
return $this;
}
5 years ago
public function autoCheckout()
5 years ago
{
5 years ago
$threshold = 50;
5 years ago
$last_id = cache("last_auto_checkout_order_item_id", 0);
5 years ago
Log::channel("daily_auto_checkout")->info("Last id:" . $last_id);
5 years ago
4 months ago
// 获取所有状态为1的项目
$projects = Project::where("status", 1)->pluck("id")->toArray();
5 years ago
$unpaid_order_items = (new OrderItems())
4 months ago
->whereHas("order", function ($query) use ($projects) {
$query->where("status", Orders::STATUS_ONGOING)
3 months ago
->whereIn("project_id", $projects);
5 years ago
})
4 months ago
->where("total", ">", 0)
5 years ago
->whereNull("paid_at")
5 years ago
->where("id", ">", $last_id)
->with("customer");
5 years ago
$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;
}
5 years ago
Log::channel("daily_auto_checkout")->info("From " . $unpaid_order_items->first()->id . " to " . $unpaid_order_items->last()->id);
5 years ago
foreach ($unpaid_order_items as $item) {
5 years ago
$customer = $item->customer;
5 years ago
if ($customer->balance < $item->total || $item->total == 0) {
continue;
}
5 years ago
$item->update(["paid_at" => date("Y-m-d H:i:s")]);
5 years ago
$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
]);
5 years ago
$customer->update(["balance" => $balance]);
5 years ago
Log::channel("daily_auto_checkout")->info($item->id . "扣款成功");
5 years ago
}
5 years ago
cache(['last_auto_checkout_order_item_id' => $unpaid_order_items->last()->id], now()->addSeconds(90));
5 years ago
}
public function balance()
{
return $this->hasOne(Balance::class, "belongs_id")->where("belongs_type", self::class);
}
}