修改挂单功能
This commit is contained in:
@@ -1,8 +1,12 @@
|
||||
using Model;
|
||||
using DocumentFormat.OpenXml.Drawing;
|
||||
using Model;
|
||||
using OfficeOpenXml.FormulaParsing.Excel.Functions.DateTime;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data.Entity;
|
||||
using System.Data.Entity.Infrastructure;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Threading.Tasks;
|
||||
using System.Web;
|
||||
using System.Web.Http;
|
||||
@@ -11,7 +15,7 @@ using System.Web.Http;
|
||||
/// guadanOrderGuest 的摘要描述
|
||||
/// </summary>
|
||||
[ezAuthorize]
|
||||
public class guadanOrderGuestController: ApiController
|
||||
public class guadanOrderGuestController : ApiController
|
||||
{
|
||||
private Model.ezEntities _db = new Model.ezEntities();
|
||||
[HttpGet]
|
||||
@@ -25,12 +29,12 @@ public class guadanOrderGuestController: ApiController
|
||||
[Route("api/guadanorderguest/getbyorderno")]
|
||||
public async Task<IHttpActionResult> getByOrderNo(string orderNo)
|
||||
{
|
||||
// 先查数据库,不做格式化
|
||||
// 先查資料庫,不做格式化
|
||||
var qry = await _db.GuaDanOrderGuest
|
||||
.Where(a => a.GuaDanOrderNo == orderNo && a.IsDeleted == false)
|
||||
.Where(a => a.GuaDanOrderNo == orderNo && a.IsDeleted == false && a.RegionRoomBedStatus.Code != "404")
|
||||
.ToListAsync();
|
||||
|
||||
// 拉到内存后再处理日期
|
||||
// 拉到記憶體後再處理日期
|
||||
var data = qry.Select(a => new guadan_order_guest_display_dto
|
||||
{
|
||||
Uuid = a.Uuid,
|
||||
@@ -44,8 +48,12 @@ public class guadanOrderGuestController: ApiController
|
||||
roomName = a.Room.Name,
|
||||
bedName = a.RegionRoomBed.Name,
|
||||
orderNo = a.GuaDanOrderNo,
|
||||
follower = a.follower,
|
||||
statusUuid = a.statusUuid,
|
||||
follower = a.followers == null ? null : new FollowerDto
|
||||
{
|
||||
num = a.followers.num,
|
||||
u_name = a.followers.u_name
|
||||
},
|
||||
statuscode = a.StatusCode,
|
||||
statusName = a.RegionRoomBedStatus?.Name,
|
||||
}).ToList();
|
||||
|
||||
@@ -58,11 +66,14 @@ public class guadanOrderGuestController: ApiController
|
||||
{
|
||||
if (model == null)
|
||||
return BadRequest("");
|
||||
|
||||
/*if(model.statuscode == null)
|
||||
{
|
||||
return BadRequest("狀態不能為空");
|
||||
}*/
|
||||
// 驗證床位與蓮友
|
||||
var bed = _db.RegionRoomBed.Find(model.bedUuid.Value);
|
||||
if (model.followerNum.HasValue && model.bedUuid.HasValue)
|
||||
{
|
||||
var bed = _db.RegionRoomBed.Find(model.bedUuid.Value);
|
||||
var follower = _db.followers.Find(model.followerNum.Value);
|
||||
|
||||
if (bed == null || follower == null)
|
||||
@@ -81,16 +92,16 @@ public class guadanOrderGuestController: ApiController
|
||||
}
|
||||
|
||||
if (!model.bedUuid.HasValue)
|
||||
return BadRequest("床位 UUID 不能为空");
|
||||
return BadRequest("床位 UUID 不能為空");
|
||||
if (!model.checkInAt.HasValue)
|
||||
return BadRequest("入住时间不能为空");
|
||||
return BadRequest("入住時間不能為空");
|
||||
|
||||
// 長期占用處理:checkOutAt 可為 null
|
||||
DateTime? checkOut = model.checkOutAt.Value.Date;
|
||||
|
||||
if (checkOut.HasValue && model.checkInAt > checkOut)
|
||||
return BadRequest("掛單結束時間不能再開始時間之前");
|
||||
if(model.checkInAt == model.checkOutAt)
|
||||
if (model.checkInAt == model.checkOutAt)
|
||||
{
|
||||
return BadRequest("掛單結束時間和開始時間不能是同一天");
|
||||
}
|
||||
@@ -103,8 +114,22 @@ public class guadanOrderGuestController: ApiController
|
||||
);
|
||||
if (!bedIsCanUse)
|
||||
return BadRequest("床位在該時間段內已被占用");
|
||||
if (model.followerNum.HasValue)
|
||||
{
|
||||
if (_db.GuaDanOrderGuest.Any(a => a.FollowerNum == model.followerNum
|
||||
&& a.GuaDanOrderNo == model.orderNo
|
||||
&& a.StatusCode != "404"
|
||||
))
|
||||
return BadRequest("該蓮友已經在該掛單中");
|
||||
}
|
||||
//建立訂單的的時候,狀態只能是401或者402
|
||||
var targetStatus = _db.RegionRoomBedStatus.Where(a => a.Code == GuaDanOrderGuest.STATUS_BOOKED).FirstOrDefault();
|
||||
|
||||
if (targetStatus == null)
|
||||
{
|
||||
return Content(HttpStatusCode.PreconditionFailed, "找不到目標狀態,請先建立對應狀態");
|
||||
}
|
||||
|
||||
// 建立掛單
|
||||
var guest = new GuaDanOrderGuest
|
||||
{
|
||||
GuaDanOrderNo = model.orderNo,
|
||||
@@ -114,14 +139,9 @@ public class guadanOrderGuestController: ApiController
|
||||
CheckInAt = model.checkInAt?.Date,
|
||||
CheckOutAt = checkOut,
|
||||
Uuid = Guid.NewGuid(),
|
||||
statusUuid = model.statusUuid,
|
||||
StatusCode = GuaDanOrderGuest.STATUS_BOOKED,
|
||||
};
|
||||
|
||||
if (model.followerNum.HasValue)
|
||||
{
|
||||
if (_db.GuaDanOrderGuest.Any(a => a.FollowerNum == model.followerNum && a.GuaDanOrderNo == model.orderNo))
|
||||
return BadRequest("該蓮友已經在該掛單中");
|
||||
}
|
||||
|
||||
_db.GuaDanOrderGuest.Add(guest);
|
||||
await _db.SaveChangesAsync();
|
||||
@@ -140,12 +160,13 @@ public class guadanOrderGuestController: ApiController
|
||||
Description = "床位掛單",
|
||||
ScheduleDate = scheduleDate,
|
||||
IsDeleted = false,
|
||||
IsActive = true,
|
||||
IsCancel = false,
|
||||
TargetUuid = guest.BedUuid,
|
||||
UseType = (int)RegionAndRoomAndBedSchedule.SchedulePurpose.Bed_Reservation,
|
||||
CreatedAt = DateTime.Now,
|
||||
GuaDanOrderNo = guest.GuaDanOrderNo,
|
||||
Uuid = Guid.NewGuid()
|
||||
Uuid = Guid.NewGuid(),
|
||||
GuaDanOrderGuestUuid = guest.Uuid,
|
||||
};
|
||||
_db.RegionAndRoomAndBedSchedule.Add(schedul);
|
||||
}
|
||||
@@ -159,17 +180,17 @@ public class guadanOrderGuestController: ApiController
|
||||
Description = "床位掛單(長期占用)",
|
||||
ScheduleDate = null,
|
||||
IsDeleted = false,
|
||||
IsActive = true,
|
||||
IsCancel = false,
|
||||
TargetUuid = guest.BedUuid,
|
||||
UseType = (int)RegionAndRoomAndBedSchedule.SchedulePurpose.Bed_Reservation,
|
||||
CreatedAt = DateTime.Now,
|
||||
GuaDanOrderNo = guest.GuaDanOrderNo,
|
||||
Uuid = Guid.NewGuid()
|
||||
Uuid = Guid.NewGuid(),
|
||||
GuaDanOrderGuestUuid = guest.Uuid
|
||||
};
|
||||
_db.RegionAndRoomAndBedSchedule.Add(schedul);
|
||||
}
|
||||
|
||||
await _db.SaveChangesAsync();
|
||||
await _db.SaveChangesAsync();
|
||||
await _db.SaveChangesAsync();
|
||||
|
||||
return Ok();
|
||||
@@ -201,10 +222,10 @@ public class guadanOrderGuestController: ApiController
|
||||
}
|
||||
|
||||
if (!model.bedUuid.HasValue)
|
||||
return BadRequest("床位 UUID 不能为空");
|
||||
return BadRequest("床位 UUID 不能為空");
|
||||
|
||||
if (!model.checkInAt.HasValue)
|
||||
return BadRequest("入住时间不能为空");
|
||||
return BadRequest("入住時間不能為空");
|
||||
|
||||
// 長期占用處理
|
||||
DateTime? checkOut = model.checkOutAt?.Date;
|
||||
@@ -234,18 +255,27 @@ public class guadanOrderGuestController: ApiController
|
||||
.AnyAsync();
|
||||
if (exists) return BadRequest("該蓮友已經在該掛單中");
|
||||
}
|
||||
|
||||
/*var targetStatus = _db.RegionRoomBedStatus.Find(model.statuscode);
|
||||
if (targetStatus == null)
|
||||
{
|
||||
return BadRequest("目標狀態不存在");
|
||||
}
|
||||
if(!StatusTransitionManager.CanTransition(guest.StatusCode,targetStatus.Code))
|
||||
{
|
||||
return BadRequest("狀態的變化不合法");
|
||||
}*/
|
||||
// 更新掛單基本資料
|
||||
guest.FollowerNum = model.followerNum;
|
||||
guest.RoomUuid = model.roomUuid;
|
||||
guest.BedUuid = model.bedUuid;
|
||||
guest.CheckInAt = model.checkInAt?.Date;
|
||||
guest.CheckOutAt = checkOut;
|
||||
guest.statusUuid = model.statusUuid;
|
||||
//guest.StatusCode = model.statuscode;
|
||||
//更新的時候不能更新狀態,狀態都用單獨的操作api控制
|
||||
|
||||
// 刪除原有每日排程
|
||||
var oldSchedules = _db.RegionAndRoomAndBedSchedule
|
||||
.Where(s => s.GuaDanOrderNo == guest.GuaDanOrderNo)
|
||||
.Where(s => s.GuaDanOrderNo == guest.GuaDanOrderNo && s.TargetUuid == guest.BedUuid)
|
||||
.ToList();
|
||||
_db.RegionAndRoomAndBedSchedule.RemoveRange(oldSchedules);
|
||||
|
||||
@@ -262,12 +292,13 @@ public class guadanOrderGuestController: ApiController
|
||||
Description = "床位掛單",
|
||||
ScheduleDate = date,
|
||||
IsDeleted = false,
|
||||
IsActive = true,
|
||||
IsCancel = false,
|
||||
TargetUuid = guest.BedUuid,
|
||||
UseType = (int)RegionAndRoomAndBedSchedule.SchedulePurpose.Bed_Reservation,
|
||||
CreatedAt = DateTime.Now,
|
||||
GuaDanOrderNo = guest.GuaDanOrderNo,
|
||||
Uuid = Guid.NewGuid()
|
||||
Uuid = Guid.NewGuid(),
|
||||
GuaDanOrderGuestUuid = guest.Uuid,
|
||||
};
|
||||
_db.RegionAndRoomAndBedSchedule.Add(schedul);
|
||||
}
|
||||
@@ -281,12 +312,13 @@ public class guadanOrderGuestController: ApiController
|
||||
Description = "床位掛單(長期占用)",
|
||||
ScheduleDate = null,
|
||||
IsDeleted = false,
|
||||
IsActive = true,
|
||||
IsCancel = false,
|
||||
TargetUuid = guest.BedUuid,
|
||||
UseType = (int)RegionAndRoomAndBedSchedule.SchedulePurpose.Bed_Reservation,
|
||||
CreatedAt = DateTime.Now,
|
||||
GuaDanOrderNo = guest.GuaDanOrderNo,
|
||||
Uuid = Guid.NewGuid()
|
||||
Uuid = Guid.NewGuid(),
|
||||
GuaDanOrderGuestUuid = guest.Uuid,
|
||||
};
|
||||
_db.RegionAndRoomAndBedSchedule.Add(schedul);
|
||||
}
|
||||
@@ -298,25 +330,231 @@ public class guadanOrderGuestController: ApiController
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
[Route("api/guadanorderguest/delete")]
|
||||
public async Task<IHttpActionResult> deleteGuadanGuest([FromUri] Guid uuid)
|
||||
[Route("api/guadanorderguest/cancel")]
|
||||
public async Task<IHttpActionResult> CancelGuadanGuest([FromUri] Guid uuid)
|
||||
{
|
||||
var guest = await _db.GuaDanOrderGuest.FindAsync(uuid);
|
||||
if (guest == null)
|
||||
return BadRequest("未找到指定挂单资料");
|
||||
return NotFound();
|
||||
|
||||
// 删除所有与该 guest 相关的排程(每日排程或長期占用)
|
||||
var schedules = _db.RegionAndRoomAndBedSchedule
|
||||
.Where(s => s.GuaDanOrderNo == guest.GuaDanOrderNo)
|
||||
.ToList();
|
||||
if (guest.StatusCode == "404")
|
||||
return BadRequest("該掛單已取消,無需再取消");
|
||||
|
||||
if (schedules.Any())
|
||||
_db.RegionAndRoomAndBedSchedule.RemoveRange(schedules);
|
||||
if (!StatusTransitionManager.CanTransition(guest.StatusCode, "404"))
|
||||
{
|
||||
return BadRequest("當前狀態不能取消");
|
||||
}
|
||||
var cancelStatus = await _db.RegionRoomBedStatus
|
||||
.FirstOrDefaultAsync(a => a.Code == "404");
|
||||
if (cancelStatus == null)
|
||||
return Content(HttpStatusCode.PreconditionFailed, "找不到取消狀態(Code=404),請先建立對應狀態");
|
||||
//把狀態設置為取消
|
||||
using (var tx = _db.Database.BeginTransaction())
|
||||
{
|
||||
try
|
||||
{
|
||||
// 1) 更新 guest
|
||||
guest.StatusCode = "404";
|
||||
|
||||
_db.GuaDanOrderGuest.Remove(guest);
|
||||
await _db.SaveChangesAsync();
|
||||
// 2) 取消相關排程(常見做法:只取消未來&未取消的)
|
||||
var today = DateTime.Today;
|
||||
|
||||
return Ok(new { message = "删除成功" });
|
||||
var schedules = await _db.RegionAndRoomAndBedSchedule
|
||||
.Where(s => s.GuaDanOrderGuestUuid == guest.Uuid
|
||||
&& s.IsCancel == false
|
||||
//&& s.ScheduleDate >= today
|
||||
)
|
||||
// ✅ 只取消今天與未來的,能取消就代表未入住,
|
||||
// 未入住就要全部取消,如果是入住後提前退房,
|
||||
// 就要取消未來的,取消未來的時候要注意今日是否包含的問題
|
||||
.ToListAsync();
|
||||
|
||||
foreach (var s in schedules)
|
||||
{
|
||||
s.IsCancel = true;
|
||||
}
|
||||
|
||||
// 3) 釋放占用資源(若有床位/房間占用紀錄)
|
||||
if (guest.BedUuid != null)
|
||||
{
|
||||
// 先抓到目標狀態
|
||||
var freeStatus = await _db.RegionRoomBedStatus
|
||||
.FirstOrDefaultAsync(a => a.Code == "101");
|
||||
|
||||
if (freeStatus == null)
|
||||
return Content(HttpStatusCode.PreconditionFailed, "找不到床位狀態 Code=101");
|
||||
if (guest.RegionRoomBed != null)
|
||||
{
|
||||
guest.RegionRoomBed.StatusCode = freeStatus.Code;
|
||||
}
|
||||
}
|
||||
|
||||
await _db.SaveChangesAsync();
|
||||
tx.Commit();
|
||||
|
||||
return Ok(new
|
||||
{
|
||||
message = "取消成功",
|
||||
guestUuid = guest.Uuid,
|
||||
canceledSchedules = schedules.Count
|
||||
});
|
||||
}
|
||||
catch (DbUpdateConcurrencyException)
|
||||
{
|
||||
tx.Rollback();
|
||||
return StatusCode(HttpStatusCode.PreconditionFailed); // 或自訂訊息
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
tx.Rollback();
|
||||
return InternalServerError(ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
[Route("api/guadanorderguest/checkout")]
|
||||
public IHttpActionResult CheckoutGuadanOrderGuest(Guid uuid)
|
||||
{
|
||||
DbContextTransaction transaction = null;
|
||||
try
|
||||
{
|
||||
transaction = _db.Database.BeginTransaction(); // 開啟事務
|
||||
|
||||
// 1️⃣ 取得該筆掛單
|
||||
var guest = _db.GuaDanOrderGuest
|
||||
.Where(a => a.Uuid == uuid)
|
||||
.Where(a => !a.IsDeleted && a.StatusCode != "404")
|
||||
.FirstOrDefault();
|
||||
|
||||
if (guest == null)
|
||||
return NotFound();
|
||||
|
||||
// 2️⃣ 標記為已退房
|
||||
var targetStatus = _db.RegionRoomBedStatus
|
||||
.Where(a => a.Code == "403")
|
||||
.FirstOrDefault();
|
||||
if (targetStatus == null)
|
||||
return Content(HttpStatusCode.PreconditionFailed, "找不到退房狀態(Code=403),請先建立對應狀態");
|
||||
|
||||
if (!StatusTransitionManager.CanTransition(guest.StatusCode, targetStatus.Code))
|
||||
return BadRequest("掛單狀態轉換不對");
|
||||
|
||||
if (!StatusTransitionManager.CanTransition(guest.RegionRoomBed.StatusCode, "101"))
|
||||
return BadRequest("床位掛單狀態轉換不對");
|
||||
|
||||
guest.StatusCode = targetStatus.Code;
|
||||
guest.RegionRoomBed.StatusCode = "101";
|
||||
|
||||
//更新未來排程為取消
|
||||
var latestCheckoutStr = _db.GuadanTimeSetting
|
||||
.Select(a => a.LatestCheckOut) // 字符串 "HH:mm"
|
||||
.FirstOrDefault();
|
||||
|
||||
TimeSpan? latestCheckoutTime = null;
|
||||
if (!string.IsNullOrEmpty(latestCheckoutStr))
|
||||
{
|
||||
// 尝试解析字符串
|
||||
if (TimeSpan.TryParse(latestCheckoutStr, out var ts))
|
||||
{
|
||||
latestCheckoutTime = ts;
|
||||
}
|
||||
}
|
||||
|
||||
var futureSchedules = _db.RegionAndRoomAndBedSchedule
|
||||
.Where(s => s.GuaDanOrderGuestUuid == guest.Uuid);
|
||||
if (latestCheckoutTime == null || DateTime.Now.TimeOfDay > latestCheckoutTime)
|
||||
{
|
||||
// 包含今天
|
||||
futureSchedules = futureSchedules.Where(s => s.ScheduleDate > DateTime.Today);
|
||||
}
|
||||
else
|
||||
{
|
||||
// 不包含今天
|
||||
futureSchedules = futureSchedules.Where(s => s.ScheduleDate >= DateTime.Today);
|
||||
}
|
||||
|
||||
foreach (var schedule in futureSchedules)
|
||||
{
|
||||
schedule.IsCancel = true;
|
||||
}
|
||||
|
||||
// 4️⃣ 保存所有變更
|
||||
_db.SaveChanges();
|
||||
|
||||
// 5️⃣ 提交事務
|
||||
transaction.Commit();
|
||||
|
||||
return Ok(new { message = "退房完成", guestUuid = guest.Uuid });
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (transaction != null)
|
||||
transaction.Rollback(); // 回滾事務
|
||||
return InternalServerError(ex);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (transaction != null)
|
||||
transaction.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
[Route("api/guadanorderguest/checkin")]
|
||||
public IHttpActionResult CheckinGuadanGuest([FromUri] Guid uuid)
|
||||
{
|
||||
if (uuid == Guid.Empty)
|
||||
return BadRequest("uuid不能為空");
|
||||
|
||||
// 獲取掛單客人
|
||||
var guest = _db.GuaDanOrderGuest
|
||||
.Include(g => g.RegionRoomBedStatus) // 包含導航屬性
|
||||
.FirstOrDefault(g => g.Uuid == uuid);
|
||||
|
||||
if (guest == null)
|
||||
return NotFound();
|
||||
|
||||
string currentStatus = guest.StatusCode;
|
||||
|
||||
// 判斷狀態流轉是否合法
|
||||
if (!StatusTransitionManager.CanTransition(currentStatus, GuaDanOrderGuest.STATUS_CHECKED_IN))
|
||||
{
|
||||
return BadRequest("當前狀態不允許入住");
|
||||
}
|
||||
|
||||
// ---------- 新增:檢查今天是否在排程表 ----------
|
||||
var today = DateTime.Today;
|
||||
bool hasScheduleToday = _db.RegionAndRoomAndBedSchedule
|
||||
.Any(s => s.GuaDanOrderGuestUuid == guest.Uuid && s.ScheduleDate == today);
|
||||
|
||||
if (!hasScheduleToday)
|
||||
{
|
||||
return BadRequest("不在入住時間段內,無法入住");
|
||||
}
|
||||
try
|
||||
{
|
||||
// 更新狀態
|
||||
guest.StatusCode = GuaDanOrderGuest.STATUS_CHECKED_IN;
|
||||
|
||||
// 如果需要,更新床位狀態,比如變為占用
|
||||
if (guest.BedUuid != null)
|
||||
{
|
||||
var bed = _db.RegionRoomBed.FirstOrDefault(b => b.Uuid == guest.BedUuid);
|
||||
if (bed != null && StatusTransitionManager.CanTransition(bed.StatusCode, "102")) // 102 = 占用
|
||||
{
|
||||
bed.StatusCode = "102";
|
||||
}
|
||||
}
|
||||
|
||||
_db.SaveChanges();
|
||||
|
||||
return Ok(new { message = "入住成功", statusCode = guest.StatusCode });
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return InternalServerError(ex);
|
||||
}
|
||||
}
|
||||
|
||||
public class guadan_order_guest_dto
|
||||
@@ -328,7 +566,7 @@ public class guadanOrderGuestController: ApiController
|
||||
public Guid? bedUuid { get; set; }
|
||||
public DateTime? checkInAt { get; set; }
|
||||
public DateTime? checkOutAt { get; set; }
|
||||
public Guid? statusUuid { get; set; }
|
||||
public string statuscode { get; set; }
|
||||
}
|
||||
public class guadan_order_guest_display_dto
|
||||
{
|
||||
@@ -337,17 +575,23 @@ public class guadanOrderGuestController: ApiController
|
||||
public string orderNo { get; set; }
|
||||
public string name { get; set; }
|
||||
public Guid? roomUuid { get; set; }
|
||||
public Guid? bedUuid { get;set; }
|
||||
public string checkinat { get;set; }
|
||||
public string checkoutat { get;set; }
|
||||
public int? gender { get; set; }
|
||||
public Guid? statusUuid { get; set; }
|
||||
public Guid? bedUuid { get; set; }
|
||||
public string checkinat { get; set; }
|
||||
public string checkoutat { get; set; }
|
||||
public int? gender { get; set; }
|
||||
public string statuscode { get; set; }
|
||||
public string statusName { get; set; }
|
||||
public string phone { get; set; }
|
||||
public string note { get; set; }
|
||||
public string roomName { get; set; }
|
||||
public string bedName { get; set; }
|
||||
public follower follower { get; set; }
|
||||
public bool iscancel { get; set; }
|
||||
public FollowerDto follower { get; set; }
|
||||
}
|
||||
public class FollowerDto
|
||||
{
|
||||
public int num { get; set; }
|
||||
public string u_name { get; set; }
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user