Files
17168ERP/web/App_Code/api/guadanOrderGuestController.cs

662 lines
24 KiB
C#
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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;
/// <summary>
/// guadanOrderGuest 的摘要描述
/// </summary>
[ezAuthorize]
public class guadanOrderGuestController : ApiController
{
private Model.ezEntities _db = new Model.ezEntities();
[HttpGet]
[Route("api/guadanorderguest/get")]
public async Task<IHttpActionResult> Get()
{
var data = await _db.GuaDanOrderGuest.ToListAsync();
return Ok(data);
}
[HttpGet]
[Route("api/guadanorderguest/getbyorderno")]
public async Task<IHttpActionResult> getByOrderNo(string orderNo)
{
// 先查資料庫,不做格式化
var qry = await _db.GuaDanOrderGuest
.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,
name = null,
followerNum = a.FollowerNum,
roomUuid = a.RoomUuid,
bedUuid = a.BedUuid,
checkinat = a.CheckInAt.HasValue ? a.CheckInAt.Value.ToString("yyyy-MM-dd") : null,
checkoutat = a.CheckOutAt.HasValue ? a.CheckOutAt.Value.ToString("yyyy-MM-dd") : null,
phone = null,
roomName = a.Room.Name,
bedName = a.RegionRoomBed.Name,
orderNo = a.GuaDanOrderNo,
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();
return Ok(data);
}
[HttpPost]
[Route("api/guadanorderguest/create")]
public async Task<IHttpActionResult> create([FromBody] guadan_order_guest_dto model)
{
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 follower = _db.followers.Find(model.followerNum.Value);
if (bed == null || follower == null)
return BadRequest("床位或蓮友不存在");
bool isMaleFollower;
if (follower.sex == "男眾")
isMaleFollower = true;
else if (follower.sex == "女眾")
isMaleFollower = false;
else
return BadRequest("蓮友性別未知");
if (bed.Gender != isMaleFollower)
return BadRequest("床位性別與蓮友性別不同");
}
if (!model.bedUuid.HasValue)
return BadRequest("床位 UUID 不能為空");
if (!model.checkInAt.HasValue)
return BadRequest("入住時間不能為空");
// 長期占用處理checkOutAt 可為 null
DateTime? checkOut = model.checkOutAt.Value.Date;
if (checkOut.HasValue && model.checkInAt > checkOut)
return BadRequest("掛單結束時間不能再開始時間之前");
if (model.checkInAt == model.checkOutAt)
{
return BadRequest("掛單結束時間和開始時間不能是同一天");
}
// 檢查床位可用性
var bedIsCanUse = await RegionAndRoomAndBedSchedule.IsBedAvailableAsync(
_db,
model.bedUuid.Value,
model.checkInAt.Value.Date,
checkOut
);
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,
FollowerNum = model.followerNum,
RoomUuid = model.roomUuid,
BedUuid = model.bedUuid,
CheckInAt = model.checkInAt?.Date,
CheckOutAt = checkOut,
Uuid = Guid.NewGuid(),
StatusCode = GuaDanOrderGuest.STATUS_BOOKED,
};
_db.GuaDanOrderGuest.Add(guest);
await _db.SaveChangesAsync();
// 生成每日排程
if (checkOut.HasValue)
{
int totalDays = (checkOut.Value - model.checkInAt.Value.Date).Days;
for (int i = 0; i < totalDays; i++)
{
var scheduleDate = model.checkInAt.Value.Date.AddDays(i);
var schedul = new RegionAndRoomAndBedSchedule
{
Title = "掛單",
Description = "床位掛單",
ScheduleDate = scheduleDate,
IsDeleted = false,
IsCancel = false,
TargetUuid = guest.BedUuid,
UseType = (int)RegionAndRoomAndBedSchedule.SchedulePurpose.Bed_Reservation,
CreatedAt = DateTime.Now,
GuaDanOrderNo = guest.GuaDanOrderNo,
Uuid = Guid.NewGuid(),
GuaDanOrderGuestUuid = guest.Uuid,
};
_db.RegionAndRoomAndBedSchedule.Add(schedul);
}
}
else
{
// 長期占用ScheduleDate = null
var schedul = new RegionAndRoomAndBedSchedule
{
Title = "掛單",
Description = "床位掛單(長期占用)",
ScheduleDate = null,
IsDeleted = false,
IsCancel = false,
TargetUuid = guest.BedUuid,
UseType = (int)RegionAndRoomAndBedSchedule.SchedulePurpose.Bed_Reservation,
CreatedAt = DateTime.Now,
GuaDanOrderNo = guest.GuaDanOrderNo,
Uuid = Guid.NewGuid(),
GuaDanOrderGuestUuid = guest.Uuid
};
_db.RegionAndRoomAndBedSchedule.Add(schedul);
}
await _db.SaveChangesAsync();
return Ok();
}
[HttpPost]
[Route("api/guadanorderguest/update")]
public async Task<IHttpActionResult> update([FromBody] guadan_order_guest_dto model)
{
if (model == null)
return BadRequest("");
// 驗證床位與蓮友
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)
return BadRequest("床位或蓮友不存在");
bool isMaleFollower;
if (follower.sex == "男眾") isMaleFollower = true;
else if (follower.sex == "女眾") isMaleFollower = false;
else return BadRequest("蓮友性別未知");
if (bed.Gender != isMaleFollower)
return BadRequest("床位性別與蓮友性別不同");
}
if (!model.bedUuid.HasValue)
return BadRequest("床位 UUID 不能為空");
if (!model.checkInAt.HasValue)
return BadRequest("入住時間不能為空");
// 長期占用處理
DateTime? checkOut = model.checkOutAt?.Date;
if (checkOut.HasValue && model.checkInAt > checkOut)
return BadRequest("掛單結束時間不能再開始時間之前");
var guest = await _db.GuaDanOrderGuest.FindAsync(model.Uuid);
if (guest == null) return BadRequest();
// 檢查床位可用性
var bedIsCanUse = await RegionAndRoomAndBedSchedule.IsBedAvailableAsync(
_db,
model.bedUuid.Value,
model.checkInAt.Value.Date,
checkOut
);
if (!bedIsCanUse && guest.BedUuid != model.bedUuid)
return BadRequest("床位在該時間段內已被占用");
if (model.followerNum.HasValue)
{
bool exists = await _db.GuaDanOrderGuest
.Where(a => a.FollowerNum == model.followerNum
&& a.GuaDanOrderNo == model.orderNo
&& a.Uuid != model.Uuid)
.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.StatusCode = model.statuscode;
//更新的時候不能更新狀態狀態都用單獨的操作api控制
// 刪除原有每日排程
var oldSchedules = _db.RegionAndRoomAndBedSchedule
.Where(s => s.GuaDanOrderNo == guest.GuaDanOrderNo && s.TargetUuid == guest.BedUuid)
.ToList();
_db.RegionAndRoomAndBedSchedule.RemoveRange(oldSchedules);
// 重新生成每日排程
if (checkOut.HasValue)
{
int totalDays = (checkOut.Value - model.checkInAt.Value.Date).Days;
for (int i = 0; i < totalDays; i++)
{
var date = model.checkInAt.Value.Date.AddDays(i);
var schedul = new RegionAndRoomAndBedSchedule
{
Title = "掛單",
Description = "床位掛單",
ScheduleDate = date,
IsDeleted = false,
IsCancel = false,
TargetUuid = guest.BedUuid,
UseType = (int)RegionAndRoomAndBedSchedule.SchedulePurpose.Bed_Reservation,
CreatedAt = DateTime.Now,
GuaDanOrderNo = guest.GuaDanOrderNo,
Uuid = Guid.NewGuid(),
GuaDanOrderGuestUuid = guest.Uuid,
};
_db.RegionAndRoomAndBedSchedule.Add(schedul);
}
}
else
{
// 長期占用
var schedul = new RegionAndRoomAndBedSchedule
{
Title = "掛單",
Description = "床位掛單(長期占用)",
ScheduleDate = null,
IsDeleted = false,
IsCancel = false,
TargetUuid = guest.BedUuid,
UseType = (int)RegionAndRoomAndBedSchedule.SchedulePurpose.Bed_Reservation,
CreatedAt = DateTime.Now,
GuaDanOrderNo = guest.GuaDanOrderNo,
Uuid = Guid.NewGuid(),
GuaDanOrderGuestUuid = guest.Uuid,
};
_db.RegionAndRoomAndBedSchedule.Add(schedul);
}
await _db.SaveChangesAsync();
await _db.SaveChangesAsync();
return Ok();
}
[HttpPost]
[Route("api/guadanorderguest/xuzhu")]
public async Task<IHttpActionResult> ExtendStay([FromBody] XuZhuModel model)
{
//續住方法
if (model == null)
return BadRequest("請求數據為空");
if (model.GuestUuid == Guid.Empty || model.GuestBedUuid == Guid.Empty)
return BadRequest("GuestUuid 或 GuestBedUuid 無效");
var guest = await _db.GuaDanOrderGuest.FindAsync(model.GuestUuid);
if (guest == null)
{
return BadRequest("掛單不存在");
}
if (guest.BedUuid != model.GuestBedUuid)
{
return BadRequest("床位不正確");
}
var bedIsCanUse = await RegionAndRoomAndBedSchedule.IsBedAvailableAsync(_db, model.GuestBedUuid, model.CurrentCheckoutDate, model.NewCheckoutDate);
if (!bedIsCanUse)
{
return BadRequest("該床位在續住時間段內被預定,無法續住");
}
var newStartDate = model.CurrentCheckoutDate.Date;
var newEndDate = model.NewCheckoutDate.Date.AddDays(-1);
if (newEndDate < newStartDate)
return BadRequest("續住日期區間無效");
for (var date = newStartDate; date <= newEndDate; date = date.AddDays(1))
{
var newSchedule = new RegionAndRoomAndBedSchedule
{
GuaDanOrderNo = guest.GuaDanOrderNo,
Uuid = Guid.NewGuid(),
TargetUuid = model.GuestBedUuid,
GuaDanOrderGuestUuid = model.GuestUuid,
ScheduleDate = date,
Title = "續住掛單", // 一天一條,開始和結束是同一天
Description = "續住掛單",
UseType = 30,
CreatedAt = DateTime.UtcNow
};
_db.RegionAndRoomAndBedSchedule.Add(newSchedule);
}
guest.CheckOutAt = model.NewCheckoutDate.Date;
await _db.SaveChangesAsync(); // 保存資料庫操作
return Ok(new { message = "續住成功" });
}
[HttpPost]
[Route("api/guadanorderguest/cancel")]
public async Task<IHttpActionResult> CancelGuadanGuest([FromUri] Guid uuid)
{
var guest = await _db.GuaDanOrderGuest.FindAsync(uuid);
if (guest == null)
return NotFound();
if (guest.StatusCode == "404")
return BadRequest("該掛單已取消,無需再取消");
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";
// 2) 取消相關排程(常見做法:只取消未來&未取消的)
var today = DateTime.Today;
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)
{
return BadRequest("入住床位不存在");
}
if (StatusTransitionManager.CanTransition(bed.StatusCode, "102")) // 102 = 占用
{
bed.StatusCode = "102";
}
else
{
return BadRequest($"當前床位狀態:{bed.RegionRoomBedStatus.Name} 不能入住");
}
}
else if (guest.BedUuid == null)
{
return BadRequest("入住床位不存在");
}
_db.SaveChanges();
return Ok(new { message = "入住成功", statusCode = guest.StatusCode });
}
catch (Exception ex)
{
return InternalServerError(ex);
}
}
public class guadan_order_guest_dto
{
public Guid? Uuid { get; set; }
public int? followerNum { get; set; }
public string orderNo { get; set; }
public Guid? roomUuid { get; set; }
public Guid? bedUuid { get; set; }
public DateTime? checkInAt { get; set; }
public DateTime? checkOutAt { get; set; }
public string statuscode { get; set; }
}
public class guadan_order_guest_display_dto
{
public Guid? Uuid { get; set; }
public int? followerNum { get; set; }
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 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 bool iscancel { get; set; }
public FollowerDto follower { get; set; }
}
public class FollowerDto
{
public int num { get; set; }
public string u_name { get; set; }
}
public class XuZhuModel
{
public Guid GuestUuid { get; set; } // 不可為空
public Guid GuestBedUuid { get; set; } // 不可為空
public DateTime CurrentCheckoutDate { get; set; } // 當前退房時間
public DateTime NewCheckoutDate { get; set; } // 新退房時間
}
}