diff --git a/web/App_Code/Model/Model.Context.cs b/web/App_Code/Model/Model.Context.cs index d4d20be..5362fde 100644 --- a/web/App_Code/Model/Model.Context.cs +++ b/web/App_Code/Model/Model.Context.cs @@ -94,6 +94,7 @@ namespace Model public virtual DbSet AncestralTabletRegistrant { get; set; } public virtual DbSet AncestralTabletStatus { get; set; } public virtual DbSet GuaDanOrderGuest { get; set; } + public virtual DbSet auto_enroll { get; set; } public virtual int pager_eztrust(Nullable startRowIndex, Nullable pageSize, string tableName, string columnName, string sqlWhere, string orderBy, ObjectParameter rowCount) { diff --git a/web/App_Code/Model/Model.cs b/web/App_Code/Model/Model.cs index f943d31..43d509f 100644 --- a/web/App_Code/Model/Model.cs +++ b/web/App_Code/Model/Model.cs @@ -409,6 +409,10 @@ namespace Model public Nullable price { get; set; } public Nullable qty { get; set; } public Nullable reg_time { get; set; } + public Nullable has_yang_limit { get; set; } + public Nullable has_chao_limit { get; set; } + public Nullable yang_limit_count { get; set; } + public Nullable chao_limit_count { get; set; } public virtual actItem actItem { get; set; } public virtual activity activity { get; set; } @@ -680,6 +684,31 @@ namespace Model using System; using System.Collections.Generic; + public partial class auto_enroll + { + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")] + public auto_enroll() + { + this.pro_order = new HashSet(); + } + + public int num { get; set; } + public int f_num { get; set; } + public System.DateTime start_date { get; set; } + public System.DateTime end_date { get; set; } + public string receipt_title { get; set; } + public string receipt_address { get; set; } + + public virtual follower followers { get; set; } + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")] + public virtual ICollection pro_order { get; set; } + } +} +namespace Model +{ + using System; + using System.Collections.Generic; + public partial class bed_kind { [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")] @@ -806,6 +835,7 @@ namespace Model public string smtp_def { get; set; } public string use_sender { get; set; } public string bed_order_no { get; set; } + public string last_auto_order_no { get; set; } } } namespace Model @@ -907,6 +937,7 @@ namespace Model this.transfer_register1 = new HashSet(); this.GuaDanOrder = new HashSet(); this.GuaDanOrderGuest = new HashSet(); + this.auto_enroll = new HashSet(); } public int num { get; set; } @@ -971,6 +1002,8 @@ namespace Model public virtual ICollection GuaDanOrder { get; set; } [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")] public virtual ICollection GuaDanOrderGuest { get; set; } + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")] + public virtual ICollection auto_enroll { get; set; } } } namespace Model @@ -1344,6 +1377,7 @@ namespace Model public Nullable introducer { get; set; } public Nullable send_receipt { get; set; } public string receipt_title { get; set; } + public Nullable au_num { get; set; } public virtual activity activity { get; set; } [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")] @@ -1352,6 +1386,7 @@ namespace Model public virtual follower follower1 { get; set; } [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")] public virtual ICollection pro_order_detail { get; set; } + public virtual auto_enroll auto_enroll { get; set; } } } namespace Model diff --git a/web/App_Code/Model/Model.edmx b/web/App_Code/Model/Model.edmx index ab8c87b..1029793 100644 --- a/web/App_Code/Model/Model.edmx +++ b/web/App_Code/Model/Model.edmx @@ -193,6 +193,10 @@ + + + + @@ -333,6 +337,17 @@ + + + + + + + + + + + @@ -404,6 +419,7 @@ + @@ -700,6 +716,7 @@ + @@ -1269,6 +1286,18 @@ + + + + + + + + + + + + @@ -1647,6 +1676,18 @@ + + + + + + + + + + + + @@ -2117,6 +2158,7 @@ + @@ -2248,6 +2290,10 @@ + + + + @@ -2372,6 +2418,10 @@ + + + + @@ -2736,6 +2786,10 @@ + + + + @@ -2899,6 +2953,7 @@ + @@ -2977,6 +3032,7 @@ + @@ -3155,6 +3211,8 @@ + + @@ -4553,6 +4611,15 @@ + + + + + + + + + @@ -5270,6 +5337,45 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -5456,6 +5562,10 @@ + + + + @@ -5595,6 +5705,7 @@ + @@ -5829,6 +5940,7 @@ + @@ -6323,6 +6435,18 @@ + + + + + + + + + + + + diff --git a/web/App_Code/Model/Model.edmx.diagram b/web/App_Code/Model/Model.edmx.diagram index 877866e..f56637a 100644 --- a/web/App_Code/Model/Model.edmx.diagram +++ b/web/App_Code/Model/Model.edmx.diagram @@ -162,6 +162,9 @@ + + + diff --git a/web/App_Code/api/FollowerController.cs b/web/App_Code/api/FollowerController.cs index 4df4f17..1a95070 100644 --- a/web/App_Code/api/FollowerController.cs +++ b/web/App_Code/api/FollowerController.cs @@ -1,15 +1,20 @@ -using System; +using DocumentFormat.OpenXml.Drawing.Charts; +using DocumentFormat.OpenXml.Office2010.Excel; +using Model; +using MyWeb; +using Newtonsoft.Json; +using OfficeOpenXml.FormulaParsing.Excel.Functions.DateTime; +using PagedList; +using System; +using System.Collections; using System.Collections.Generic; +using System.Data.Entity; +using System.Diagnostics; using System.Linq; using System.Net; using System.Net.Http; using System.Web.Http; -using PagedList; -using Newtonsoft.Json; -using System.Collections; -using DocumentFormat.OpenXml.Office2010.Excel; -using MyWeb; -using System.Data.Entity; +using System.Web.Razor.Tokenizer; // api/Follower //[ezAuthorize(Roles = "admin")]//群組:* @@ -723,6 +728,203 @@ public class FollowerController : ApiController } + [HttpGet] + [Route("api/follower/GetAutoEnrollList/{id}")] + public IHttpActionResult GetAutoEnrollList(int id) + { + var prod = _db.auto_enroll.Where(q => q.f_num == id).ToList(); + var ret = new + { + list = prod.Select(x => new + { + num = x.num, + auto_enroll_start_date = x.start_date.ToString("yyyy-MM-dd"), + auto_enroll_end_date = x.end_date.ToString("yyyy-MM-dd"), + auto_enroll_receipt_title = x.receipt_title?? "", + auto_enroll_receipt_address = x.receipt_address?? "", + }), + + }; + return Ok(ret); + } + + [HttpPost] + [Route("api/follower/SaveAutoEnrollList")] + public IHttpActionResult SaveAutoEnrollList([FromBody] Model.auto_enroll item) + { + Model.auto_enroll autoEnroll; + if (item.num == 0) + { + // ===== 新增 ===== + autoEnroll = new Model.auto_enroll() + { + f_num = item.f_num, + start_date = item.start_date, + end_date = item.end_date, + receipt_title = string.IsNullOrEmpty(item.receipt_title) ? null : item.receipt_title.Trim(), + receipt_address = string.IsNullOrEmpty(item.receipt_address) ? null : item.receipt_address.Trim(), + } + ; + _db.auto_enroll.Add(autoEnroll); + _db.SaveChanges(); + CreateOrdersForActivities(item.f_num, autoEnroll.num, item.start_date, item.end_date, item.receipt_title, item.receipt_address); + } + else + { + // ===== 更新 ===== + autoEnroll = _db.auto_enroll.Where(q => q.num == item.num).FirstOrDefault(); + if (autoEnroll == null) return NotFound(); + + autoEnroll.start_date = item.start_date; + autoEnroll.end_date = item.end_date; + autoEnroll.receipt_title = item.receipt_title?.Trim() ?? null; + autoEnroll.receipt_address = item.receipt_address?.Trim() ?? null; + _db.SaveChanges(); + CreateOrdersForActivities(item.f_num, autoEnroll.num, item.start_date, item.end_date, item.receipt_title, item.receipt_address); + } + + try + { + var ret = new + { + num = autoEnroll.num, + start_date = autoEnroll.start_date.ToString("yyyy-MM-dd"), + end_date = autoEnroll.end_date.ToString("yyyy-MM-dd"), + receipt_title = autoEnroll.receipt_title, + receipt_address = autoEnroll.receipt_address, + }; + return Ok(ret); + } + catch(Exception ex) + { + return InternalServerError(ex); + } + } + + [HttpPost] + [Route("api/follower/GetAffectedOrders")] + public IHttpActionResult GetAffectedOrders([FromBody] Model.auto_enroll item, bool is_delete = false) + { + if (item == null) return BadRequest(); + try + { + IQueryable query = _db.pro_order + .Where(o => o.f_num == item.f_num + && o.order_no.StartsWith("AU") + && o.au_num == item.num); + + if (is_delete) + { + // 刪除:查期間內所有自動報名訂單 + query = query.Where(o => + o.activity.startDate_solar >= item.start_date && + o.activity.startDate_solar <= item.end_date + ); + } + else + { + // 修改:查不在新範圍內的訂單 + query = query.Where(o => + o.activity.startDate_solar < item.start_date || + o.activity.startDate_solar > item.end_date + ); + } + + var rawOrders = query.Select(o => new + { + o.order_no, + o.activity.subject, + o.activity.startDate_solar + }).ToList(); + + var affectedOrders = rawOrders.Select(o => new + { + order_no = o.order_no, + activityname = o.subject, + activitydate = o.startDate_solar?.ToString("yyyy/MM/dd") ?? "" + }).ToList(); + + return Ok(new + { + count = affectedOrders.Count, + list = affectedOrders + }); + } + catch (Exception ex) + { + return InternalServerError(ex.GetBaseException()); + } + } + + + [HttpDelete] + [Route("api/follower/DeleteAutoEnroll/{id}")] + public IHttpActionResult DeleteAutoEnroll(int id) + { + try + { + var prod = _db.auto_enroll.Where(q => q.num == id).FirstOrDefault(); + if (prod != null) + { + _db.auto_enroll.Remove(prod); + _db.SaveChanges(); + return Ok(); + } + else return NotFound(); + } + catch (Exception ex) + { + return BadRequest(ex.Message); + } + } + + + [HttpGet] + [Route("api/follower/GetUnfilledActivityOrders/{id}")] + public IHttpActionResult GetUnfilledActivityOrders(int id, int page, int pageSize = 10, string sortBy = "", bool sortDesc = false) + { + try + { + var config = _db.auto_enroll.FirstOrDefault(x => x.num == id); + if (config == null) return NotFound(); + + var query = from o in _db.pro_order + join a in _db.activities on o.activity_num equals a.num + where o.f_num == config.f_num + && a.startDate_solar >= config.start_date + && a.startDate_solar <= config.end_date + && !_db.pro_order_detail.Any(d => d.order_no == o.order_no) + select new { o, a }; + + int totalCount = query.Count(); + + var pagedData = query + .OrderByDescending(x => x.o.order_no) + .Skip((page - 1) * pageSize) + .Take(pageSize) + .ToList() + .Select(x => new { + order_no = x.o.order_no, + startdate = x.a.startDate_solar?.ToString("yyyy/MM/dd") ?? "", + enddate = x.a.endDate_solar?.ToString("yyyy/MM/dd") ?? "", + activityname = x.a.subject, + category = x.a.activity_category_kind?.kind ?? "" + }); + + return Ok(new + { + list = pagedData, + count = totalCount, + page = page, + pageSize = pageSize + }); + } + catch (Exception ex) + { + return BadRequest(ex.Message); + } + } + [HttpPost] [Route("api/follower/GetTabletList")] @@ -864,6 +1066,31 @@ public class FollowerController : ApiController return Ok(data); } [HttpPost] + [Route("api/follower/pending_orders")] + public IHttpActionResult GetPendingOrders(int id, string targetDate) + { + + DateTime today = DateTime.Today; + if (!DateTime.TryParse(targetDate, out DateTime limitDate)) + { + limitDate = new DateTime(2099, 12, 31); + } + var orderrecord = _db.pro_order + .Where(x => x.f_num == id && x.activity.startDate_solar >= today && x.activity.startDate_solar < limitDate) + .Include(x => x.activity) + .ToList(); + var data = new + { + list = orderrecord.Select(x => new + { + orderno = x.order_no, + activitydate = x.activity.startDate_solar.Value.ToString("yyyy/MM/dd"), + activityname = x.activity.subject, + }) + }; + return Ok(data); + } + [HttpPost] [Route("api/follower/totalorderamount")] public IHttpActionResult GetTotalOrderCount(int id) { @@ -899,5 +1126,132 @@ public class FollowerController : ApiController }; return Ok(data); } + + private void CreateOrdersForActivities(int f_num, int au_num, DateTime start_date, DateTime end_date, string receipt_title, string receipt_address) + { + var follower = _db.followers.Where(x => x.num == f_num).FirstOrDefault(); + var activities = _db.activities + .Where(x => + x.startDate_solar >= start_date && + x.startDate_solar <= end_date + ) + .ToList(); + + foreach (var activity in activities) + { + var existOrder = _db.pro_order + .Where(o => o.activity_num == activity.num && o.f_num == f_num) + .FirstOrDefault(); + + if (existOrder != null) { + existOrder.au_num = au_num; + _db.SaveChanges(); + continue; + } + + string newOrderNo = AutoOrderService.CreateAutoOrderNumber(_db); + string finalPhone = follower?.cellphone ?? follower?.phone ?? ""; + + var newOrder = new pro_order + { + order_no = newOrderNo, + up_time = DateTime.Now, + reg_time = DateTime.Now, + keyin1 = "A01", + f_num = f_num, + au_num = au_num, + phone = finalPhone, + address = string.IsNullOrEmpty(receipt_address) ? "" : receipt_address, + activity_num = activity.num, + receipt_title = receipt_title ?? "", + demo = "", + customize_data = "", + }; + _db.pro_order.Add(newOrder); + + // 抓取同活動分類的上一筆訂單,複製品項 + var latestOrder = _db.pro_order + .Where(o => + o.f_num == f_num && + o.activity.kind == activity.kind && + o.order_no != newOrderNo && + _db.pro_order_detail.Any(d => d.order_no == o.order_no) + ) + .OrderByDescending(o => o.order_no) + .FirstOrDefault(); + + if (latestOrder != null) + { + var prevDetails = _db.pro_order_detail + .Where(d => d.order_no == latestOrder.order_no) + .ToList(); + + foreach (var detail in prevDetails) + { + var newDetail = new pro_order_detail + { + order_no = newOrderNo, + actItem_num = detail.actItem_num, + parent_num = detail.parent_num, + print_id = detail.print_id, + f_num = detail.f_num, + f_num_tablet = detail.f_num_tablet, + address = detail.address, + from_id = detail.from_id, + from_id_tablet = detail.from_id_tablet, + bed_type = detail.bed_type, + qty = detail.qty, + price = detail.price, + start_date = DateTime.Today, + pay = detail.pay, + keyin1 = detail.keyin1, + demo = detail.demo, + customize_data = detail.customize_data, + printed_files = detail.printed_files, + UpdateTime = DateTime.Now, + }; + _db.pro_order_detail.Add(newDetail); + } + + } + } + + _db.SaveChanges(); + + + } + } +public static class AutoOrderService +{ + private static readonly object _lock = new object(); + + public static string CreateAutoOrderNumber(Model.ezEntities _db) + { + lock (_lock) + { + string prefix = "AU" + DateTime.Now.ToString("yyMMdd"); + + var company = _db.companies.FirstOrDefault(q => q.num == 1); + if (company == null) return ""; + + string order_no; + if (!string.IsNullOrEmpty(company.last_auto_order_no) && company.last_auto_order_no.StartsWith(prefix)) + { + string serialStr = company.last_auto_order_no.Replace(prefix, ""); + int nextSerial = int.Parse(serialStr) + 1; + order_no = prefix + nextSerial.ToString("0000"); + } + else + { + order_no = prefix + "0001"; + } + + company.last_auto_order_no = order_no; + _db.SaveChanges(); + + return order_no; + } + } +} diff --git a/web/App_Code/api/activityController.cs b/web/App_Code/api/activityController.cs index 7ad54fd..dce9c0b 100644 --- a/web/App_Code/api/activityController.cs +++ b/web/App_Code/api/activityController.cs @@ -7,6 +7,7 @@ using System; using System.Collections; using System.Collections.Generic; using System.Data.Entity; +using System.Diagnostics; using System.Linq; using System.Net; using System.Net.Http; @@ -947,7 +948,7 @@ public class activityController : ApiController //已有值 var count = qry.Count(); //pageSize = count;//一次取回?? - var qryList = (pageSize > 0) ? qry.OrderBy(a=>a.num).ToPagedList(page, pageSize).ToList() : qry.ToList(); + var qryList = (pageSize > 0) ? qry.OrderBy(a => a.num).ToPagedList(page, pageSize).ToList() : qry.ToList(); var ret = new { list = qryList.Select(x => new @@ -1104,6 +1105,10 @@ public class activityController : ApiController }, price = x.price ?? 0, qty = x.qty ?? 0, + has_yang_limit = x.has_yang_limit ?? false, + has_chao_limit = x.has_yang_limit ?? false, + yang_limit_count = x.yang_limit_count ?? 0, + chao_limit_count = x.chao_limit_count ?? 0, files = x.actItem?.actItem_files.Select(f => new { num = f.file.num, @@ -1322,6 +1327,10 @@ public class activityController : ApiController if (item.qty.HasValue) { _data.qty = item.qty.Value; } else { _data.qty = null; } _data.reg_time = DateTime.Now; + if (item.has_yang_limit.HasValue) { _data.has_yang_limit = item.has_yang_limit; } + if (item.yang_limit_count >= 0) { _data.yang_limit_count = item.yang_limit_count.Value; } + if (item.has_chao_limit.HasValue) { _data.has_chao_limit = item.has_chao_limit; } + if (item.chao_limit_count >= 0) { _data.chao_limit_count = item.chao_limit_count.Value; } _db.SaveChanges(); var ret = _data.num; @@ -1342,6 +1351,10 @@ public class activityController : ApiController if (item.qty.HasValue) { _data.qty = item.qty.Value; } else { _data.qty = null; } _data.reg_time = DateTime.Now; + if (item.has_yang_limit.HasValue) { _data.has_yang_limit = item.has_yang_limit; } + if (item.yang_limit_count >= 0) { _data.yang_limit_count = item.yang_limit_count.Value; } + if (item.has_chao_limit.HasValue) { _data.has_chao_limit = item.has_chao_limit; } + if (item.chao_limit_count >= 0) { _data.chao_limit_count = item.chao_limit_count.Value; } _db.activity_relating.Add(_data); _db.SaveChanges(); @@ -1694,13 +1707,13 @@ public class activityController : ApiController var r1 = qry.ToList(); var r2 = r1.Select(x => new { num = x.num, subject = x.subject }); var count = qry.Count(); - + // 計算昨天和今天的日期範圍 var yesterdayStart = _now.Date.AddDays(-1); var yesterdayEnd = _now.Date; var todayStart = _now.Date; var todayEnd = _now.Date.AddDays(1); - + var ret = new { list = r1.Select(x => new @@ -1754,4 +1767,136 @@ public class activityController : ApiController return Ok(ret); } + [HttpGet] + [Route("api/activity/GetUnfilledOrdersByActivity/{num}")] + public IHttpActionResult GetUnfilledOrdersByActivity(int num) + { + try + { + var activityExists = _db.activities.Any(a => a.num == num); + if (!activityExists) return NotFound(); + + var query = from o in _db.pro_order + join f in _db.followers on o.f_num equals f.num into fg + from f in fg.DefaultIfEmpty() + where o.activity_num == num + && !_db.pro_order_detail.Any(d => d.order_no == o.order_no) + select new { o, f }; + + MyWeb.encrypt encrypt = new MyWeb.encrypt(); + + var unfilledOrders = query.ToList().Select(x => new + { + order_no = x.o.order_no, + f_number = x.f.f_number, + u_name = x.f != null ? x.f.u_name : "未知", + phone = !string.IsNullOrEmpty(x.f.cellphone) ? encrypt.DecryptAutoKey(x.f.cellphone) : (encrypt.DecryptAutoKey(x.f.phone) ?? ""), + order_date = x.o.reg_time.HasValue ? x.o.reg_time.Value.ToString("yyyy/MM/dd") : "", + }).ToList(); + + return Ok(new + { + list = unfilledOrders, + count = unfilledOrders.Count + }); + } + catch (Exception ex) + { + return InternalServerError(ex.GetBaseException()); + } + } + + [HttpPost] + [Route("api/activity/TriggerAutoEnroll/{activity_num}")] + public IHttpActionResult TriggerAutoEnroll(int activity_num) + { + try + { + var activity = _db.activities.FirstOrDefault(a => a.num == activity_num); + if (activity == null) return NotFound(); + if (!activity.startDate_solar.HasValue) return BadRequest("該活動沒有設定開始日期,無法執行自動報名。"); + + DateTime actDate = activity.startDate_solar.Value; + + var validConfigs = _db.auto_enroll + .Where(ae => actDate >= ae.start_date && actDate <= ae.end_date) + .ToList(); + + int successCount = 0; + + foreach (var config in validConfigs) + { + if (_db.pro_order.Any(o => o.activity_num == activity_num && o.f_num == config.f_num)) + continue; + + var follower = _db.followers.FirstOrDefault(f => f.num == config.f_num); + string newOrderNo = AutoOrderService.CreateAutoOrderNumber(_db); + + var newOrder = new pro_order + { + order_no = newOrderNo, + up_time = DateTime.Now, + reg_time = DateTime.Now, + keyin1 = "A01", + f_num = config.f_num, + au_num = config.num, + phone = follower?.cellphone ?? follower?.phone ?? "", + address = config.receipt_address ?? "", + activity_num = activity_num, + receipt_title = config.receipt_title ?? "", + demo = "系統於新增活動時自動報名", + }; + _db.pro_order.Add(newOrder); + + CopyLatestOrderDetails(newOrderNo, config.f_num, (int)activity.kind); + + successCount++; + } + + _db.SaveChanges(); + + return Ok(new + { + message = $"自動報名執行完畢,共為 {successCount} 位信眾完成報名。", + count = successCount + }); + } + catch (Exception ex) + { + return InternalServerError(ex.GetBaseException()); + } + } + private void CopyLatestOrderDetails(string newOrderNo, int f_num, int activityKind) + { + var latestOrder = _db.pro_order + .Where(o => o.f_num == f_num && o.activity.kind == activityKind && _db.pro_order_detail.Any(d => d.order_no == o.order_no)) + .OrderByDescending(o => o.order_no) + .FirstOrDefault(); + + if (latestOrder != null) + { + var prevDetails = _db.pro_order_detail.Where(d => d.order_no == latestOrder.order_no).ToList(); + foreach (var detail in prevDetails) + { + _db.pro_order_detail.Add(new pro_order_detail + { + order_no = newOrderNo, + actItem_num = detail.actItem_num, + parent_num = detail.parent_num, + print_id = detail.print_id, + f_num = detail.f_num, + f_num_tablet = detail.f_num_tablet, + address = detail.address, + from_id = detail.from_id, + from_id_tablet = detail.from_id_tablet, + qty = detail.qty, + price = detail.price, + start_date = DateTime.Today, + pay = 0, + UpdateTime = DateTime.Now + }); + } + } + } + } diff --git a/web/App_Code/api/orderController.cs b/web/App_Code/api/orderController.cs index 6b55626..c189118 100644 --- a/web/App_Code/api/orderController.cs +++ b/web/App_Code/api/orderController.cs @@ -10,6 +10,7 @@ using System.Activities.Expressions; using System.Collections; using System.Collections.Generic; using System.Data.Entity; +using System.Data.Entity.Core.Objects; using System.Diagnostics; using System.IdentityModel.Metadata; using System.Linq; @@ -597,8 +598,10 @@ public class orderController : ApiController //var qry1 = _db.pro_order_detail.AsEnumerable(); //qry1 = qry1.Where(o => o.order_no == order_no); //var qry1 = prod.pro_order_detail.AsEnumerable(); + var qry1 = prod.pro_order_detail.AsQueryable().include(o=>o.pro_order.activity.activity_relating); + //if (!string.IsNullOrEmpty(q.subject)) // qry = qry.Where(o => o.subject.Contains(q.subject)); @@ -626,7 +629,7 @@ public class orderController : ApiController qry1 = qry1.OrderByDescending(o => o.num); } - + var tdesc = publicFun.enum_desc(); int i = 1; @@ -636,9 +639,12 @@ public class orderController : ApiController (List)qry1_list.ToPagedList(page, pageSize); var count = qry1_list.Count(); + + var ret = new { list = qry1_list.Select(x => { + var tmpActivityRelating = x.pro_order?.activity?.activity_relating?.Where(a => a.actItem_num == x.actItem_num).FirstOrDefault(); return new { @@ -717,8 +723,86 @@ public class orderController : ApiController // c, // //pay_kind = tdesc2[c.payment.HasValue && x.keyin1.Value > 0 ? x.keyin1.Value : 1], //}), + var tmpActivityRelating = x.pro_order?.activity?.activity_relating?.Where(a => a.actItem_num == x.actItem_num).FirstOrDefault(); + return new + { + has_yang_limit = tmpActivityRelating?.has_yang_limit ?? false, + has_chao_limit = tmpActivityRelating?.has_chao_limit ?? false, + yang_limit_count = tmpActivityRelating?.yang_limit_count ?? 0, + chao_limit_count = tmpActivityRelating?.chao_limit_count ?? 0, + id = i++, + num = x.num, + order_no = x.order_no, + actitem_num_selected = new + { + text = x.actItem_num.HasValue ? x.actItem.subject : "", + val = x.actItem_num.HasValue ? x.actItem_num.Value : 0, + }, + parent_num = x.parent_num, + f_num_selected = new + { + text = x.f_num.HasValue ? x.follower.u_name : "", + val = x.f_num.HasValue ? x.f_num.Value : 0, + }, + f_num_tablet = x.f_num_tablet, + print_id = x.print_id, + address = x.address, + due_date = x.due_date, + start_date = x.start_date, + extend_date = x.extend_date, + from_id_selected = new + { + text = x.from_id.HasValue ? x.follower1.u_name : "", + val = x.from_id.HasValue ? x.from_id : 0, + }, + from_id_tablet = x.from_id_tablet, + price = x.price ?? 0, + qty = x.qty ?? 0, + writeBedQty = bedDt.Where(b => b.bed_order.o_detail_id.Value == x.num && b.checkIn_date.HasValue && b.bed_kind_detail_id.HasValue).Count(), //已劃數量 + notBedQty = bedDt.Where(b => b.bed_order.o_detail_id.Value == x.num && (!b.checkIn_date.HasValue || !b.bed_kind_detail_id.HasValue)).Count(), //未劃數量 + //total = x.total.HasValue ? x.total.Value : 0, + category = x.actItem?.category, + //pay = x.pay ?? 0, + pay = x.pro_order_record.Select(c => c.price).Sum(), + pay_date = x.pay_date, + keyin1_selected = new + { + text = tdesc[x.keyin1.HasValue && x.keyin1.Value > 0 ? x.keyin1.Value : 1], + val = x.keyin1, + }, + demo = x.demo, + files = x.actItem?.actItem_files.Select(f => new + { + num = f.file.num, + subject = f.file.subject, + word = f.file.word, + cuz_column = f.file.customize_data ?? "", //?? + paperset = f.file.paperset ?? "", + }), + customize_data = x.customize_data ?? "", + customize_data_comb = new + { + from_id_cuz_data = "", + activity_cuz_data = "", + actitem_cuz_data = "", + order_cuz_data = "", + }, + printed_files = x.printed_files ?? "", + isPackage = (x.actItem.act_bom + .Any(ab => ab.package_num == null && ab.item_num != null) + ? 1 : 0), + bom_order = (x.actItem.act_bom + .Any(ab => ab.package_num == null && ab.item_num != null) + ? x.num.ToString() + : (x.parent_num.ToString() + x.num.ToString()) + ), + //cash_record = x.pro_order_record.Select( c => new { + // c, + // //pay_kind = tdesc2[c.payment.HasValue && x.keyin1.Value > 0 ? x.keyin1.Value : 1], + //}), - }) + }; + }) .ToList() .OrderByDescending(x => (x.isPackage + (x.parent_num == null ? 0 : 1))) //.ThenBy(x => (x.parent_num == null ? 1 : 2)) // Top-level items first diff --git a/web/admin/activity/item_reg.aspx.cs b/web/admin/activity/item_reg.aspx.cs index 7928ed4..0270e88 100644 --- a/web/admin/activity/item_reg.aspx.cs +++ b/web/admin/activity/item_reg.aspx.cs @@ -42,7 +42,7 @@ public partial class admin_activity_item_reg : MyWeb.config BuildKind(); subject.Text = prod.subject; print_init.Text = prod.print_init; - //PARTNO.Text = prod.partno; + //kind.SelectedValue = prod.kind.ToString(); if (!isStrNull(prod.pageSize)) { diff --git a/web/admin/activity/reg.aspx b/web/admin/activity/reg.aspx index 130269f..6c1bcf9 100644 --- a/web/admin/activity/reg.aspx +++ b/web/admin/activity/reg.aspx @@ -197,7 +197,6 @@ has_chao_limit: false, yang_limit_count: 0, chao_limit_count: 0, - }, defaultItem: { id: 0, num: 0, @@ -289,6 +288,20 @@ items: [ { order_no: "D", member_name: "S", order_date:"2025-12-07"} ], + unfilled_list: { + loading: false, + search: '', + headers: [ + { text: '訂單編號', value: 'order_no' }, + { text: '信眾編號', value: 'f_number' }, + { text: '信眾姓名', value: 'u_name' }, + { text: '聯絡電話', value: 'phone' }, + { text: '建立日期', value: 'order_date' }, + ], + items: [ + { order_no: "D", member_name: "S", order_date:"2025-12-07"} + ], + }, } }, mounted() { @@ -457,9 +470,8 @@ this.close(); }, spliceNullData() { - //if new data ,then splice it - if (this.editedItem.num == 0) { + if (this.editedItem.num == 0) { for (var i = 0; i < this.desserts.map(x => x.id).length; i++) { if (this.desserts[i].id == this.editedItem.id) { this.desserts.splice(i, 1); break; @@ -913,7 +925,7 @@ const _date = $('#<%= startDate_solar.ClientID%>').val(); return _subject + " " + _date; }, -loadUnfilledList() { + loadUnfilledList() { if (!this.this_id) return; this.unfilled_list.loading = true; @@ -1283,6 +1295,7 @@ loadUnfilledList() { {{item.chao_limit_count}} 人 + + + + + + {{ confirm_dialog.title }} + mdi-close + + + +

{{ confirm_dialog.desc }}

+ + + + + + +
+ + + + {{ confirm_dialog.btn_keep_text }} + + + + {{ confirm_dialog.btn_cancel_text }} + + +
+
+ \ No newline at end of file diff --git a/web/admin/follower/reg.aspx.cs b/web/admin/follower/reg.aspx.cs index eaa6d2f..704598e 100644 --- a/web/admin/follower/reg.aspx.cs +++ b/web/admin/follower/reg.aspx.cs @@ -11,9 +11,11 @@ using System.Diagnostics; using System.Globalization; using System.IO; using System.Linq; +using System.Security.Cryptography; using System.Web; using System.Web.UI; using System.Web.UI.WebControls; +using static Model.activity_check; public partial class admin_follower_reg : MyWeb.config { @@ -142,7 +144,7 @@ public partial class admin_follower_reg : MyWeb.config country.Value = prod.country.ToString(); } if (prod.reg_time.HasValue) - { + { timePanel1.Visible = true; reg_time.Text= prod.reg_time.Value.ToString("yyyy/MM/dd HH:mm:ss"); } @@ -153,7 +155,6 @@ public partial class admin_follower_reg : MyWeb.config modify_time.Text = prod.admin_log; } - edit.Visible = true; goback.Visible = true; add.Visible = false; @@ -178,10 +179,39 @@ public partial class admin_follower_reg : MyWeb.config Response.Redirect("index.aspx?page=" + Convert.ToString(Request["page"])); } - + #region 資料新增 + protected string createOrderNumber() + { + Application.Lock(); + string order_no = "AA" + DateTime.Now.ToString("yyMMdd"); + var qry = _db.companies.AsQueryable(); + //var prod = qry.Where(q => q.last_order_no.Contains(order_no)).FirstOrDefault(); + var prod = qry.Where(q => q.num == 1).FirstOrDefault(); + if (prod != null) + { + if (!isStrNull(prod.last_order_no) && prod.last_order_no.Contains(order_no)) + { + int tmp = Convert.ToInt32(prod.last_order_no.Replace(order_no, "")) + 1; + order_no = order_no + tmp.ToString("0000"); + } + else + { + order_no = order_no + "0001"; + } + + prod.last_order_no = order_no; + _db.SaveChanges(); + } + else + order_no = ""; + + Application.UnLock(); + + return order_no; + } protected void add_Click(object sender, EventArgs e) { if (Page.IsValid) { @@ -205,7 +235,7 @@ public partial class admin_follower_reg : MyWeb.config { ObjValue.SetValue(followers, selectDate(textBox)); } - else if (!isStrNull(((TextBox)obj).Attributes["data-encrypt"]) + else if (!isStrNull(((TextBox)obj).Attributes["data-encrypt"]) && ValString(textBox.Attributes["data-encrypt"]).Equals("Y")) { ObjValue.SetValue(followers, encrypt.EncryptAutoKey(textBox.Text.Trim())); @@ -270,9 +300,9 @@ public partial class admin_follower_reg : MyWeb.config Model.admin_log admin_log = new Model.admin_log(); admin_log.writeLog(admin.info.u_id, (int)Model.admin_log.Systems.Follower, (int)Model.admin_log.Status.Insert, f_number.Text + u_name.Text); - + Session["LastAddedID"] = followers.f_number; - + Response.Redirect("index.aspx"); } else @@ -292,8 +322,8 @@ public partial class admin_follower_reg : MyWeb.config L_msg.Type = alert_type.danger; L_msg.Text = "信眾編號重複"; } - - } + + } } #endregion @@ -331,10 +361,7 @@ public partial class admin_follower_reg : MyWeb.config } else ObjValue.SetValue(followers, null); - } - - } followers.identity_type = Val(identity_type.SelectedValue); @@ -410,16 +437,16 @@ public partial class admin_follower_reg : MyWeb.config L_msg.Type = alert_type.danger; L_msg.Text = "查無資料"; } - /* - if (chk_pro_num(f_number.Text, Val(Request["num"]))) - { - } - else - { - L_msg.Type = alert_type.danger; - L_msg.Text = "信眾編號重複"; - } - */ + /* + if (chk_pro_num(f_number.Text, Val(Request["num"]))) + { + } + else + { + L_msg.Type = alert_type.danger; + L_msg.Text = "信眾編號重複"; + } + */ } } diff --git a/web/admin/order/reg.aspx b/web/admin/order/reg.aspx index f516473..deffeff 100644 --- a/web/admin/order/reg.aspx +++ b/web/admin/order/reg.aspx @@ -835,7 +835,6 @@ this.desserts_count = response.data.list !== undefined ? response.data.count : 0 this.calutotalPrice(); this.disableButton = false; - }) .catch( error => console.log(error) @@ -920,7 +919,7 @@ // 顯示對話框 this.tablet_edit.show = true; // 立即恢復數據 - this.editedItem = $.extend(true, {}, currentData); + this.editedItem = $.extend(true, {}, currentData); } catch (error) { console.error('Error in editTablet:', error); } diff --git a/web/admin/print/tablet_edit/editor.html b/web/admin/print/tablet_edit/editor.html index 1fdf1a3..cd9233a 100644 --- a/web/admin/print/tablet_edit/editor.html +++ b/web/admin/print/tablet_edit/editor.html @@ -147,6 +147,14 @@ 超渡-已選 + + {{ family_deceased_Y_selected.length }} / {{ tabletItem.chao_limit_count }} + @@ -237,6 +245,14 @@ 陽上/祈福-已選 + + {{ family_deceased_N_selected.length }} / {{ tabletItem.yang_limit_count }} + @@ -700,6 +716,15 @@ saveData() { // 其它資料欄位, 不應在這裡修改 // 應該在進來的時候, 就已經修改(insert)好了 + if (this.tabletItem.has_chao_limit && this.family_deceased_Y_selected.length > this.tabletItem.chao_limit_count) { + alert(`超渡人數超過限制!(上限 ${this.tabletItem.chao_limit_count} 人)`); + return; // 阻斷存檔 + } + if (this.tabletItem.has_yang_limit && this.family_deceased_N_selected.length > this.tabletItem.yang_limit_count) { + alert(`陽上人數超過限制!(上限 ${this.tabletItem.yang_limit_count} 人)`); + return; // 阻斷存檔 + } + let tablet_data = {}; if (this.item_type === 'B') {// B:超渡, 超薦..... tablet_data = { diff --git a/web/web.config b/web/web.config index 25b4be6..4019585 100644 --- a/web/web.config +++ b/web/web.config @@ -42,9 +42,14 @@ +<<<<<<< HEAD +======= + + +>>>>>>> 0.1 diff --git a/資料庫修改紀錄.md b/資料庫修改紀錄.md new file mode 100644 index 0000000..15dff5c --- /dev/null +++ b/資料庫修改紀錄.md @@ -0,0 +1,102 @@ +## FK 規則更新 + +| FK 名稱 | 更新內容 | +| - | - | +| FK_act_bom_actItem1| 刪除規則設為 cascade | +| FK_pro_order_followers | 刪除規則設為 cascade | +| FK_pro_order_activity | 刪除規則設為 cascade | +| FK_pro_order_detail_pro_order | 刪除規則設為 cascade | +| FK_pro_order_detail_followers | 刪除規則設為 沒有動作 | +| FK_activity_relating_activity | 刪除規則設為 cascade | +| FK_pro_order_auto_enroll | 刪除規則設為 NULL | + +## 資料表欄位更新 + +| 資料表 | 新增欄位 | 備註 | +| - | - | - | +| actitem | 加上 sort_order (int) 欄位位 | | +| activity_relating | 加上 has_yang_limit(bit) 欄位 | | +| activity_relating | 加上 has_chao_limit(bit) 欄位 | | +| activity_relating | 加上 yang_limit_count (int) 欄位 | | +| activity_relating | 加上 chao_limit_count (int) 欄位 | | +| company | 加上 last_auto_order_no (nvarchar(20)) 欄位 | | +| pro_order | 加上 au_num (int) 欄位 | 需建立 FK 限制 (見下方 SQL) | + +- 更新 actitem 資料表 +```language +ALTER TABLE actitem +ADD sort_order int NULL; +``` + +- 更新 activity_relating 資料表 +```language +ALTER TABLE activity_relating +ADD has_yang_limit bit NULL, + has_chao_limit bit NULL, + yang_limit_count int NULL, + chao_limit_count int NULL; +``` + +- 更新 company 資料表 +```language +ALTER TABLE company +ADD last_auto_order_no nvarchar(20) NULL; +``` + +- 更新 pro_order 資料表及外鍵限制 +```language +-- 新增欄位 +ALTER TABLE pro_order +ADD au_num int NULL; + +-- 建立外鍵限制 (FK_pro_order_auto_enroll) +ALTER TABLE pro_order +ADD CONSTRAINT FK_pro_order_auto_enroll +FOREIGN KEY (au_num) REFERENCES auto_enroll(num); +``` + +## 新增資料表 auto_enroll +| 欄位名稱 | 資料類型 | 允許 Null | 備註 | +| - | - | - | - | +| num | int | 否 | PK, 識別規格 (Identity) | +| f_num | int | 否 | FK (連至 followers.num) | +| start_date | date | 是 | | +| end_date | date | 是 | | +| receipt_title | nvarchar(MAX) | 是 | | +| receipt_address | nchar(200) | 否 | | + +- 建立資料表 auto_enroll +```language +CREATE TABLE [dbo].[auto_enroll] ( + [num] int IDENTITY(1,1) NOT NULL, + [f_num] int NOT NULL, + [start_date] date NULL, + [end_date] date NULL, + [receipt_title] nvarchar(MAX) NULL, + [receipt_address] nchar(200) NOT NULL, + CONSTRAINT [PK_auto_enroll] PRIMARY KEY CLUSTERED ([num] ASC) +); +``` + +- 設定外鍵限制 +```language +ALTER TABLE [dbo].[auto_enroll] +ADD CONSTRAINT FK_auto_enroll_followers +FOREIGN KEY (f_num) REFERENCES followers(num); +``` + +### 資料表相關設定 (SQL) +- 設定主鍵 +```language +ALTER TABLE [dbo].[auto_enroll] +ADD CONSTRAINT PK_auto_enroll PRIMARY KEY (num); +``` +- 設定外鍵 +```language +ALTER TABLE auto_enroll +ADD CONSTRAINT FK_auto_enroll_followers +FOREIGN KEY (f_num) REFERENCES followers(num); +``` +- Model.edmx 設定 + - num 識別規格設為 是 + - Model.edmx auto_enroll.num 屬性 StoreGeneratedPattern 設為 Identity \ No newline at end of file diff --git a/資料庫修改紀錄.txt b/資料庫修改紀錄.txt index b9c7f05..45423b9 100644 --- a/資料庫修改紀錄.txt +++ b/資料庫修改紀錄.txt @@ -1,8 +1,41 @@ -FK_act_bom_actItem1 刪除規則設為 cascade -FK_pro_order_followers 刪除規則設為 cascade -FK_pro_order_activity 刪除規則設為 cascade -FK_pro_order_detail_pro_order 刪除規則設為 cascade -FK_pro_order_detail_followers 刪除規則設為 沒有動作 -FK_activity_relating_activity 刪除規則設為 cascade +FK 規則更新 +FK_act_bom_actItem1 刪除規則設為 cascade +FK_pro_order_followers 刪除規則設為 cascade +FK_pro_order_activity 刪除規則設為 cascade +FK_pro_order_detail_pro_order 刪除規則設為 cascade +FK_pro_order_detail_followers 刪除規則設為 沒有動作 +FK_activity_relating_activity 刪除規則設為 cascade +FK_pro_order_auto_enroll 刪除規則設為 NULL +------------------------------------------------------------ +資料表欄位更新 +actitem 加上 sort_order(int) 欄位 +activity_relating 加上 has_yang_limit(bit) 欄位 +activity_relating 加上 has_chao_limit(bit) 欄位 +activity_relating 加上 yang_limit_count(int) 欄位 +activity_relating 加上 chao_limit_count(int) 欄位 +company 加上 last_auto_order_no(nvarchar(20)) 欄位 +pro_order 加上 au_num(int) 欄位 並加上 constraint: + ALTER TABLE pro_order + ADD CONSTRAINT FK_pro_order_auto_enroll + FOREIGN KEY (au_num) REFERENCES auto_enroll(num); +------------------------------------------------------------ +新增資料表 auto_enroll +num int 不允許 Null +f_num int 不允許 Null +start_date date 允許 Null +end_date date 允許 Null +receipt_title nvarchar(MAX) 允許 Null +receipt_address nchar(200) 不允許 Null -actitem 加上 sort_order(int) 欄位 \ No newline at end of file +設定主鍵 +ALTER TABLE [dbo].[auto_enroll] +ADD CONSTRAINT PK_auto_enroll PRIMARY KEY (num); + +設定外鍵 +ALTER TABLE auto_enroll +ADD CONSTRAINT FK_auto_enroll_followers +FOREIGN KEY (f_num) REFERENCES followers(num); + +Model.edmx 設定 +1. num 識別規格設為 是 +2. Model.edmx auto_enroll.num 屬性 StoreGeneratedPattern 設為 Identity \ No newline at end of file