[MVC 開發系列] 系統分析與設計實務 [設計一個員工請假資訊系統](2)

接續前一篇文章中,除了 View (UI)之外,我們完成了系統的(分析/設計)的部分,由這一篇我們繼續未完成的部分。接下來除了 View 的設計之外,緊接著就是 Coding 了。而系統分析、設計、開發的流程的領域也不是說絕對是如此....

接續前一篇文章中,除了 View (UI)之外,我們完成了系統的(分析/設計)的部分,由這一篇我們繼續未完成的部分。接下來除了 View 的設計之外,緊接著就是 Coding 了。

而系統分析、設計、開發的流程的領域也不是說絕對是如此,這不是在本篇文章可以說的完的,有機會的話,筆者真的很想撰寫一系列的文章。我們希開始進行 View 的設計工作。

View 的設計:

在前面的業務規則中說明了如下幾點需求,我們依序加以再次的分析:

1. 員工可以向公司內向直屬主管請假,直屬主管必須核可後,員工方可請假成功。

分析:

必須有[員工請假作業]功能,根據基本業務規則與 Class Diagram ,員工請假作業需要下面欄位

  • 員工ID
  • 員工姓名
  • 請假開始時間
  • 請假結束時間
  • 假別
  • 代理人

2. 員工必須有設定代理人才可以請假。

分析:

這個功能會在員工請假功能中做掉。

3. 主管可以查詢部門內當日的請假狀況。

分析:

與 4 點相同的功能。可先跳至第 4 點,再回頭來看這裡。

主管若要查詢自己部門的請假狀況,系統要可以判定目前登入者身分為主管。因此在第一篇的[主管可以查詢部門內當日的請假狀況]的 Sequence Diagram 也要增加 CheckIsBoss(EmployessID)  方法。

4. 員工也可以查詢自己的請假狀況,年度共休幾天、剩餘多少特休天數等。

分析:

雖然在需求中並未交代是員工在請寄假的狀況清單畫面終點選請假,或是執行請假完畢後才跳回主清單畫面。這時我們可能需要再與使用者確認需求,通常,在 Prototype 中就可以確認這一類的情況。

假設使用者希望在每一個員工進入請假系統時秀一個個人的清單顯示個人的請假狀況,點選[請假]按鈕後才進入請假的功能畫面。

接著進行清單的欄位分析:

我們必須思考,員工想要查看自己到目前為止的請假狀況清單,不外乎想要知道自己何時請過假、是否已經核准等等。很明顯的清單要有

  • 員工ID
  • 員工姓名
  • 請假開始時間
  • 請假結束時間
  • 假別
  • 代理人
  • 狀態

剛好比請假畫面多一個欄位,依此來說,主管核准請假時除了如上欄位之外,萬一主管想簽[不核准],系統應該要有一個不核准原因供輸入才對,此時的分析便發現在整體的設計中我們少了[不核准原因]與[請假原因],這時我們就必須回去 Update 一下 Class Diagram 與 ER-Model 與 View Model (如果View Model 也設計好了的話)。筆者這裡就不再重複相同的圖了,假設我們回頭 Update 完成,並依照需求完成 vLeaveModel 與關欄位如下:

vLeaveModel

  • EmployessId
  • EmployessName
  • StartDate
  • EndDate
  • LeaveType
  • AgentName
  • LeaveStatus
  • LeaveReason
  • Notes

分析與設計到此後我們是不是也發現到了,系統如果要知道目前要查詢的是誰的請假狀況,應該還會需要基本的登入機制,系統才可以例用目前登入者的身分來查詢目前的請假狀況。所以整個系統應該還需要一個 Login View ,因為員工如果要可以查詢自己的請假狀況時,系統得要知道目前登入的身分為何,系統才可以知道目前要查出誰的請假狀況!vLoginModel 與屬性如下:

vLoginModel

  • LoginID
  • Password

這裡為了方便展示,LoginID 就等於 Employess 的 Name。還有,由於一般員工請假時只會輸入 LeaveReason ,而外的資訊(Leave Notes ) 不會在那個時候 Enabled 出來,也就是說,主管若對價單有任何意見,系統就將其訊息存放在 Notes 欄位中。

設計完成的 View 如下:

image

在 View 設計完成之後,接著,開始實際設計 vLoginModel 的畫面。

還有,再開始設計 View 之前,我們需要再從新整理 SD 的規畫,前面我們再程式碼的架構部分套用 Repository Pattern 來實作,因為前一篇文章筆者其實有點偷懶,在 Repository 的注入部分直接注入 EDM 的 Context ,也就是我這裡範例專案的 LeaveSystemModelContainer1,這麼一來 DB 無法被更換或抽離,因而被 Clark 大抓包XD,那…我還是將程式碼改一下吧~噗。

因從新整理、設計後的 Repository Pattern 如下 (以 Employess 為例):

image

在原先的 Repository<T> 不動的情下,我再多拉一層出來,也就是 SqlEmployessRepositoryProvider 並在再繼續實作 EDM 實體的存取部分。而原先繼承 Repository<T> 的 EmployessRepository<T>就改實作繼承 IRepository<T> ,這時EmployessRepository<T> 的程式碼如下:

   1:  //------------------------------------------------------------------------------
   2:  // <auto-generated>
   3:  //     This code was generated by a tool.
   4:  //     Changes to this file will be lost if the code is regenerated.
   5:  // </auto-generated>
   6:  //------------------------------------------------------------------------------
   7:  using System;
   8:  using System.Collections.Generic;
   9:  using System.Linq;
  10:  using System.Text;
  11:  using MvcLeaveSystemApplication1.Models;
  12:  using System.Data.Objects;
  13:  
  14:  public class EmployeesRepository : IRepository<Employess>
  15:  {
  16:      private readonly IRepository<Employess> _employessRepository = null;
  17:  
  18:      public EmployeesRepository(IRepository<Employess> employessRepositoryProvider)
  19:      {
  20:          _employessRepository = employessRepositoryProvider;
  21:      }
  22:  
  23:      #region IRepository<Employess> 成員
  24:  
  25:      public Employess GetById(object id)
  26:      {
  27:          return _employessRepository.GetById(id);
  28:      }
  29:  
  30:      public void Add(Employess entity)
  31:      {
  32:          _employessRepository.Add(entity);
  33:      }
  34:  
  35:      public IEnumerable<Employess> GetAll()
  36:      {
  37:          return _employessRepository.GetAll();
  38:      }
  39:  
  40:      public void Remove(Employess entity)
  41:      {
  42:          _employessRepository.Remove(entity);
  43:      }
  44:  
  45:      public Employess GetByName(string Name)
  46:      {
  47:          return _employessRepository.GetByName(Name);
  48:      } 
  49:  
  50:      public void SaveChanges()
  51:      {
  52:          _employessRepository.SaveChanges();
  53:      }
  54:  
  55:      #endregion
  56:  }
  57:  

 

 

 

 

我們新增的 SqlEmployessRepositoryProvider 如下:

   1:  using System;
   2:  using System.Collections.Generic;
   3:  using System.Linq;
   4:  using System.Web;
   5:  using System.Data.Objects;
   6:  
   7:  namespace MvcLeaveSystemApplication1.Models.Provider
   8:  {
   9:      public class SqlEmployessRepositoryProvider: Repository<Employess>
  10:      {
  11:          private LeaveSystemModelContainer1 _leaveContext = new LeaveSystemModelContainer1();
  12:  
  13:          public SqlEmployessRepositoryProvider()
  14:          {
  15:              this._objectSet = _leaveContext.CreateObjectSet<Employess>();
  16:              this._context = _leaveContext;
  17:          }
  18:  
  19:          public SqlEmployessRepositoryProvider(ObjectContext context): base(context)
  20:          {
  21:          }
  22:  
  23:          #region IRepository<Employess> 成員
  24:  
  25:          public IObjectSet<Employess> ObjectSet
  26:          {
  27:              get { return this._objectSet; }
  28:          }
  29:  
  30:          public ObjectContext Context
  31:          {
  32:              get { return this._context; }
  33:          }
  34:          public override Employess GetById(object id)
  35:          {
  36:              var result = _objectSet.Where(c => c.ID == (int)id);
  37:              return result.FirstOrDefault<Employess>();
  38:          }
  39:  
  40:          public void Remove(Employess entity)
  41:          {
  42:              var result = ObjectSet.Where(c => c.ID==entity.ID);
  43:              Employess emp = result.FirstOrDefault<Employess>();
  44:              if (emp != null)
  45:              {
  46:                  Context.DeleteObject(emp);
  47:                  SaveChanges();
  48:              }
  49:          }
  50:  
  51:          public override Employess GetByName(string Name)
  52:          {
  53:              var result = _objectSet.Where(c => c.Name == Name);
  54:              return result.FirstOrDefault<Employess>();
  55:          }
  56:  
  57:          #endregion
  58:      }
  59:  }

 

 

 

 

現在開始撰寫 Login 的 HomeController 程式:

 

 

 

 

   1:          public ActionResult Login()
   2:          {
   3:              return View();
   4:          }
   5:  
   6:          [AcceptVerbs(HttpVerbs.Post)]
   7:          public ActionResult Login(vLoginModel login)
   8:          {
   9:              if (ModelState.IsValid)
  10:              {
  11:                  Session["vLoginModel"] = login;
  12:  
  13:                  SqlEmployessRepositoryProvider sqlEmpProvider = new SqlEmployessRepositoryProvider();
  14:                  EmployeesRepository empRepository = new EmployeesRepository(sqlEmpProvider);
  15:                  Employess emp = empRepository.GetByName(login.LoginID);
  16:                  if(emp!=null)
  17:                  {
  18:                       return RedirectToAction("Index");
  19:                 }
  20:              }
  21:              return View();
  22:          }

 

 

 

 

在撰寫 Login 的 Controller 時筆者發現,少了一個 GetByName() 的方法,因為我們還是需要檢核一下 LoginID 是否存在於 Employess 中。這個 GetByName() 方法很簡單,以 Employess 的 Name 來取得 Employess 物件,如下:

   1:      public Employess GetByName(string Name)
   2:      {
   3:          var result = _objectSet.Where(c => c.Name==Name);
   4:          return result.FirstOrDefault<Employess>();
   5:      }

 

 

 

 

登入的 vLoginModel 的 View 筆者設計如下:

   1:  @model MvcLeaveSystemApplication1.vLoginModel
   2:   
   3:  @{
   4:      ViewBag.Title = "Login";
   5:  }
   6:   
   7:  <h2>Login</h2>
   8:   
   9:  <script src="@Url.Content("~/Scripts/jquery.validate.min.js")"></script>
  10:  <script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")"></script>
  11:   
  12:  @using (Html.BeginForm()) {
  13:      @Html.ValidationSummary(true)
  14:   
  15:      <fieldset>
  16:          <legend>vLogin</legend>
  17:   
  18:          <div class="editor-label">
  19:              @Html.LabelFor(model => model.LoginID)
  20:          </div>
  21:          <div class="editor-field">
  22:              @Html.EditorFor(model => model.LoginID)
  23:              @Html.ValidationMessageFor(model => model.LoginID)
  24:          </div>
  25:   
  26:          <div class="editor-label">
  27:              @Html.LabelFor(model => model.Password)
  28:          </div>
  29:          <div class="editor-field">
  30:              @Html.PasswordFor(model => model.Password)
  31:              @Html.ValidationMessageFor(model => model.Password)
  32:          </div>
  33:   
  34:          <p>
  35:              <input type="submit" value="Login" />
  36:          </p>
  37:      </fieldset>
  38:  }

 

 

 

 

在設計到此的時候,筆者發現,GetLeaveByDateRange() 應該改為 GetLeaveByEmployessId() 會比較適用目前的情況。而原先的 GetLeaveByDateRange() 方法我就先不刪除,直接在新增 GetLeaveByEmployessId 方法,並回頭 Update 一下 Sequence Diagram 以及 Class Diagram ,然後!接著,開始撰寫 GetLeaveByEmployessID() 方法,取得目前員工自己的請假狀況。如下:

   1:      /// <summary>
   2:      /// 取得目前員工自己的請假狀況
   3:      /// </summary>
   4:      /// <param name="EmployessID"></param>
   5:      /// <returns></returns>
   6:      public IQueryable<Leave> GetLeaveByEmployessID(int EmployessID)
   7:      {
   8:          var result = this._objectSet.Where(c => c.EmployeesID==EmployessID);
   9:          return result;
  10:      }

 

 

 

 

這個方法撰寫完成之後,我們就可以開始實作請假資訊系統的主畫面的 Controller 了,

 

 

 

 

   1:          public ActionResult Index()
   2:          {
   3:              vLoginModel login = (vLoginModel)Session["vLoginModel"];
   4:  
   5:              //LeaveSystemModelContainer1 context = new LeaveSystemModelContainer1();
   6:              LeaveRepository leaveRepository = new LeaveRepository(new SqlLeaveRepositoryProvider());
   7:              EmployeesRepository empRepository = new EmployeesRepository(new SqlEmployessRepositoryProvider());
   8:              LeaveService leaveService = new LeaveService(leaveRepository);
   9:              IQueryable<Leave> leave = leaveService.GetLeaveByEmployessID(empRepository.GetByName(login.LoginID).ID);
  10:              
  11:              List<vLeaveModel> vLeaveList = new List<vLeaveModel>();
  12:              foreach (var leaveResult in leave.ToList<Leave>())
  13:              {
  14:                  vLeaveModel v = this.ConvertModel<Leave, vLeaveModel>(leaveResult);
  15:                  v.LeaveId = leaveResult.ID;
  16:                  v.EmployessId = leaveResult.EmployeesID;
  17:                  v.EmployessName = empRepository.GetById(leaveResult.EmployeesID).Name;
  18:                  v.StartDateTime = leaveResult.StartDateTime;
  19:                  v.EndDateTime = leaveResult.EndDateTime;
  20:                  vLeaveList.Add(v);
  21:              }
  22:              return View(vLeaveList);
  23:          }

 

 

 

 

在這個 Controller 撰寫完畢之後,目前已經有一個登入畫面以及請假狀況可供查詢了。如下執行畫面:

image

在我們先大概建幾筆測試資料的情形下:

應該要可以查出如下的請假資訊結果:

image

目前程式可以查詢出目前登入的使用者的請假資訊,但實際的情況沒這麼簡單的,我們希望畫面流程可以這麼跑:

首先、(判別登入者身分)

1. 如果是一般員工

只查詢出自己的請假紀錄。

2. 如果是主管

要查出該主管所屬部門底下所有員工的請假紀錄。

而且只有主管才可以看見 Approve,因此很明顯的先前的分析當中,我們缺少權限控管的部分,我們應該在系統登入時判斷部前登入者身分為主管或是一般員工,照常理 Class Diagram 應該要有一個 Login 物件,但筆者為了不讓此範例過於複雜不好解說,將 CheckIsBoss() 方法放置在 EmployessRepository 物件中也是可以的。

同樣的,回頭 Update 一下 Sequence Diagram 以及 Class Diagram ,接著撰寫 CheckIsBoss() 方法。而在撰寫 CheckIsBoss() 之前,我們必須先完成  BossRepository 的實作,如下:

   1:  //------------------------------------------------------------------------------
   2:  // <auto-generated>
   3:  //     This code was generated by a tool.
   4:  //     Changes to this file will be lost if the code is regenerated.
   5:  // </auto-generated>
   6:  //------------------------------------------------------------------------------
   7:  using System;
   8:  using System.Collections.Generic;
   9:  using System.Linq;
  10:  using System.Text;
  11:  using System.Data.Objects;
  12:  using MvcLeaveSystemApplication1.Models;
  13:  using MvcLeaveSystemApplication1.Models.Provider;
  14:  
  15:  public class BossRepository
  16:  {
  17:      private readonly IRepository<Boss> _bossRepository = null;
  18:  
  19:      public BossRepository(IRepository<Boss> bossRepository)
  20:      {
  21:          _bossRepository = bossRepository;
  22:      }
  23:  
  24:      private DepartmentRepository _departments = null;
  25:      /// <summary>
  26:      /// 部門物件
  27:      /// </summary>
  28:      public virtual DepartmentRepository Departments
  29:      {
  30:          get
  31:          {
  32:              if (_departments == null)
  33:                  _departments = new DepartmentRepository(new SqlDepartmentRepositoryProvider());
  34:              return _departments;
  35:          }
  36:          set { _departments = value; }
  37:      }
  38:  
  39:      public IEnumerable<Boss> GetAll()
  40:      {
  41:          return _bossRepository.GetAll();
  42:      }
  43:  
  44:      public Boss GetById(object id)
  45:      {
  46:          return _bossRepository.GetById(id);
  47:      }
  48:  
  49:      public Boss GetByName(string Name)
  50:      {
  51:          throw new NotImplementedException();
  52:      }
  53:  }
  54:  

 

 

 

 

接著,我們的 Login 的 Controller 也要稍做修改,因為主管與員工所看到的 View 不太相同,加入 CheckIsBoss() 的判斷加以區分。使可以到不同的 View 檢視。修改過後的 Login() 的 Controller 如下:

 

 

 

 

   1:          [AcceptVerbs(HttpVerbs.Post)]
   2:          public ActionResult Login(vLoginModel login)
   3:          {
   4:              if (ModelState.IsValid)
   5:              {
   6:                  Session["vLoginModel"] = login;
   7:  
   8:                  SqlEmployessRepositoryProvider sqlEmpProvider = new SqlEmployessRepositoryProvider();
   9:                  EmployeesRepository empRepository = new EmployeesRepository(sqlEmpProvider);
  10:                  EmployessService employessService = new EmployessService(empRepository);
  11:                  Employess emp = empRepository.GetByName(login.LoginID);
  12:                  if(emp!=null)
  13:                  {
  14:                      if (employessService.CheckIsBoss(emp.ID))
  15:                      {
  16:                          return RedirectToAction("IndexBoss");
  17:                      }
  18:                      else
  19:                      {
  20:                          return RedirectToAction("Index");
  21:                      }
  22:                 }
  23:              }
  24:              return View();
  25:          }

 

 

 

 

並加入主管的 View 且取名為 IndexBoss。如上程式中當CheckIsBoss(emp.ID) 等於 true 時的 IndexBoss 的檢視中,筆者將最底下的 ActionLink 修改為 [核可] 與 [不核可] ,如下:

image

這時我們程式已經可以來試著 Run 看看了。當然,首先在 Boss 的 Table 裡建一筆資料,表示等於 1 的 EmployessId 為 台灣開發一部 的主管,如下:

image

程式執行時,果然如同我們預期的,當登入者身分為主管,登入後會進入到 IndexBoss 的 View 。如果是員工,則進入一般 Index 頁面中。如下執行畫面:

image

而在 Approve (核准) 的部分,要能正常的作業,筆者先完成了如下 Approve 的 Controller 程式碼:

 

 

 

 

   1:          public ActionResult Approve(int id)
   2:          {
   3:              SqlLeaveRepositoryProvider sqlLeaveRepositoryProvider = new SqlLeaveRepositoryProvider();
   4:              LeaveRepository leaveRepository = new LeaveRepository(sqlLeaveRepositoryProvider);
   5:              var leave = leaveRepository.GetById(id);
   6:              vLeaveModel vLeave = this.ConvertModel<Leave, vLeaveModel>(leave);
   7:              vLeave.LeaveId = id;
   8:              return View(vLeave);
   9:          }
  10:  
  11:          [AcceptVerbs(HttpVerbs.Post)]
  12:          public ActionResult Approve(vLeaveModel vLeave)
  13:          {
  14:              Leave leave = this.ConvertModel<vLeaveModel, Leave>(vLeave);
  15:              SqlLeaveRepositoryProvider sqlLeaveRepositoryProvider = new SqlLeaveRepositoryProvider();
  16:              LeaveRepository leaveRepository = new LeaveRepository(sqlLeaveRepositoryProvider);
  17:              LeaveService service = new LeaveService(leaveRepository);
  18:              service.ApproveLeave(leave, true);
  19:              return RedirectToAction("IndexBoss");
  20:          }

 

 

 

 

實際寫在 LeaveService 的核准的部分的程式碼如下:

   1:          public virtual void ApproveLeave(Leave leave, bool Approve)
   2:          {
   3:              var result = _leaveRepositoryProvider.ObjectSet.Where(c => c.ID == leave.ID);
   4:              Leave leaveResult = result.FirstOrDefault<Leave>();
   5:              leaveResult.LeaveStatus = Approve ? "2" : "1";
   6:              EntityKey key = leaveResult.EntityKey;
   7:              Leave obj = _leaveRepositoryProvider.Context.GetObjectByKey(key) as Leave;
   8:              try
   9:              {
  10:                  _leaveRepositoryProvider.Context.ObjectStateManager.ChangeObjectState(obj, EntityState.Modified);
  11:                  _leaveRepositoryProvider.Context.SaveChanges();
  12:              }
  13:              catch (Exception ex)
  14:              {
  15:                  throw ex;
  16:              }
  17:          }

 

 

 

 

 

基本上主要核心的部分其實都完成了,接下來是剩下員工實際進行請假時的 CallLeave() 方法的實作的部分,還有假單的編輯、刪除等功能。在分析與實作 CallLeave() 時,筆者發現一個較為大條的缺失,就是需求當中,員工在進行請假時,系統可以查詢其剩餘的請假天數,所以員工必須有一個地方設定其假期的天數設定部分。重新檢視 Class Diagram ,補上 LeaveSetting 這個類別,儲存員工目前剩餘的假期天數。如下:

image

到最後,林林總總,我們所加入的類別與相關的屬性、以及最後我們進行套用的 Repository Pattern 之後的整個類別圖的現況如下,有點小複雜,由於有一點龐大,筆者不得不稍微縮小一番,有興趣的讀者可以下載 Sample Code 自行瞧瞧。

image

接下來是實作剩下員工實際進行請假時的 CallLeave() 方法的實作的部分,由於 CallLeave() 會叫用到檢查剩餘休假天數的 CheckFreeLeaveDays() 方法,因此我們必須先在 LeaveService 先撰寫  方法,程式碼如下:

   1:          /// <summary>
   2:          /// 檢核目前剩下多少假期(天數)
   3:          /// </summary>
   4:          public virtual int CheckFreeLeaveDays(Employess emp)
   5:          {
   6:              LeaveSettingRepository leaveSetting = new LeaveSettingRepository(new SqlLeaveSettingRepositoryProvider());
   7:              var result = from setting in leaveSetting.GetAll().AsEnumerable()
   8:                           where setting.EmployeesId == emp.ID
   9:                           select setting;
  10:              var leave = result.FirstOrDefault<LeaveSetting>();
  11:              if (leave != null)
  12:                  return leave.LeaveDays;
  13:              return 0;
  14:          }

 

 

 

 

畫面上的設計,是由上方的 Create Leave 連結進入到請假申請畫面:

image

輸入相關資訊後,點選下方的 Create 便執行請假作業:

image

而我們要先把 LeaveService 所需提供的 ExecLeave() 與 CallLeave() 等相關方法完成,包括主管核可 ApproveLeave(),這也是 LeaveService 應該提供的服務,筆者就直接將整個 LeaveService.cs 程式碼先撰寫完成,最後 Finall 的 LeaveService 完整程式碼如下:

   1:  using System;
   2:  using System.Collections.Generic;
   3:  using System.Linq;
   4:  using System.Web;
   5:  using MvcLeaveSystemApplication1.Models.Provider;
   6:  using System.Data;
   7:  
   8:  namespace MvcLeaveSystemApplication1.Models.Services
   9:  {
  10:      public class LeaveService
  11:      {
  12:          private LeaveRepository _leaveRepository = null;
  13:          private SqlLeaveRepositoryProvider _leaveRepositoryProvider = null;
  14:          public LeaveService (LeaveRepository leaveRepository)
  15:          {
  16:              _leaveRepository = leaveRepository;
  17:              _leaveRepositoryProvider = new SqlLeaveRepositoryProvider();
  18:          }
  19:  
  20:          public virtual void ApproveLeave(Leave leave, bool Approve)
  21:          {
  22:              var result = _leaveRepositoryProvider.ObjectSet.Where(c => c.ID == leave.ID);
  23:              Leave leaveResult = result.FirstOrDefault<Leave>();
  24:              leaveResult.LeaveStatus = Approve ? "2" : "1";
  25:              EntityKey key = leaveResult.EntityKey;
  26:              Leave obj = _leaveRepositoryProvider.Context.GetObjectByKey(key) as Leave;
  27:              try
  28:              {
  29:                  _leaveRepositoryProvider.Context.ObjectStateManager.ChangeObjectState(obj, EntityState.Modified);
  30:                  _leaveRepositoryProvider.Context.SaveChanges();
  31:              }
  32:              catch (Exception ex)
  33:              {
  34:                  throw ex;
  35:              }
  36:          }
  37:  
  38:          public virtual void CallLeave(vLeaveModel emp)
  39:          {
  40:              SqlEmployessRepositoryProvider sqlEmpProvider = new SqlEmployessRepositoryProvider();
  41:              EmployeesRepository empRepository = new EmployeesRepository(sqlEmpProvider);
  42:              Employess employess = empRepository.GetById(emp.EmployessId);
  43:              int haveDays = CheckFreeLeaveDays(employess);
  44:              if (haveDays > 0)
  45:              {
  46:                  TimeSpan leaveDays = emp.EndDateTime - emp.StartDateTime;
  47:                  if (leaveDays.Days >= haveDays)
  48:                  {
  49:                      ExecLeave(emp);
  50:                      _leaveRepositoryProvider.Context.SaveChanges();
  51:                  }
  52:              }
  53:          }
  54:  
  55:          public virtual IQueryable<Leave> GetLeaveByDateRange(DateTime StartDate, DateTime EndDate)
  56:          {
  57:              var result = _leaveRepositoryProvider.ObjectSet.Where(c => c.StartDateTime <= StartDate && c.EndDateTime >= EndDate);
  58:              return result;
  59:          }
  60:  
  61:          /// <summary>
  62:          /// 取得目前員工自己的請假狀況
  63:          /// </summary>
  64:          /// <param name="EmployessID"></param>
  65:          /// <returns></returns>
  66:          public IQueryable<Leave> GetLeaveByEmployessID(int EmployessID)
  67:          {
  68:              var result = _leaveRepositoryProvider.ObjectSet.Where(c => c.EmployeesID == EmployessID);
  69:              return result;
  70:          }
  71:  
  72:          public virtual IQueryable<Leave> GetLeaveListByDepartment(int DepartmentID)
  73:          {
  74:              throw new System.NotImplementedException();
  75:          }
  76:  
  77:          /// <summary>
  78:          /// 檢核目前剩下多少假期(天數)
  79:          /// </summary>
  80:          public virtual int CheckFreeLeaveDays(Employess emp)
  81:          {
  82:              LeaveSettingRepository leaveSetting = new LeaveSettingRepository(new SqlLeaveSettingRepositoryProvider());
  83:              var result = from setting in leaveSetting.GetAll().AsEnumerable()
  84:                           where setting.EmployeesId == emp.ID
  85:                           select setting;
  86:              var leave = result.FirstOrDefault<LeaveSetting>();
  87:              if (leave != null)
  88:                  return leave.LeaveDays;
  89:              return 0;
  90:          }
  91:  
  92:          /// <summary>
  93:          /// 執行請假作業
  94:          /// </summary>
  95:          /// <param name="emp"></param>
  96:          public virtual void ExecLeave(vLeaveModel emp)
  97:          {
  98:              AgentRepository agentRepository = new AgentRepository(new SqlAgentRepositoryProvider());
  99:              AgentService agentService = new AgentService(agentRepository);
 100:              if (agentService.GetAgentByName(emp.AgentName) != null)
 101:              {
 102:                  Leave leave = new Leave();
 103:                  leave.EmployeesID = emp.EmployessId;
 104:                  leave.AgentID = agentService.GetAgentByName(emp.AgentName).ID;
 105:                  leave.StartDateTime = emp.StartDateTime;
 106:                  leave.EndDateTime = emp.EndDateTime;
 107:                  leave.LeaveStatus = emp.LeaveStatus;
 108:                  leave.LeaveType = emp.LeaveType;
 109:                  _leaveRepository.Add(leave);
 110:              }
 111:          }
 112:      }
 113:  }

 

 

 

 

完成最主要的核心 LeaveService 後,就可以撰寫 Create 的 Controller 的部分,Controller 的部分就比較簡單,直接列出程式碼:

   1:          public ActionResult Create()
   2:          {
   3:              vLeaveModel v = new vLeaveModel();
   4:              vLoginModel vlogin= (vLoginModel)Session["vLoginModel"];
   5:              EmployeesRepository empRepository = new EmployeesRepository(new SqlEmployessRepositoryProvider());
   6:              Employess e = empRepository.GetByName(vlogin.LoginID);
   7:              v.EmployessId = e.ID;
   8:              v.EmployessName = e.Name;
   9:              v.StartDateTime = DateTime.Now;
  10:              v.EndDateTime = new DateTime(DateTime.Now.Year, DateTime.Now.Month, DateTime.Now.Day, 18, 0, 0);
  11:              return View(v);
  12:          }
  13:  
  14:          [AcceptVerbs(HttpVerbs.Post)]
  15:          public ActionResult Create(vLeaveModel vleave)
  16:          {
  17:              if (ModelState.IsValid)
  18:              {
  19:                  LeaveRepository leaveRepository = new LeaveRepository(new SqlLeaveRepositoryProvider());
  20:                  LeaveService leaveService = new LeaveService(leaveRepository);
  21:                  leaveService.CallLeave(vleave);
  22:                  return RedirectToAction("Index");
  23:              }
  24:              return View();
  25:          }

 

 

 

 

最後,當員工的假單出去之後,主管就要進行核准的作業,這個也是 LeaveService 所提供的服務之一,也已經列在剛剛的 LeaveService 的完整程式碼中了。

 

結語:

到這裡,基本請假資訊系統大至底定了,雖然有點攏長,不要緊,練功有時就是如此,沒有真正的自己走過一遍,又怎麼能夠說我有真的實作過這個系統的經驗呢?真的 Run 過一遍之後,您會發現,所學到的東西都是你的,這麼一來功力也才會真的有所提升。

細部的微調就留給各位讀者了。可以照著做到這裡的讀者,相信剩下來的工作並不難。原始碼的部分,請使用下面連結下載。

Sample Code Download

ASP.NET MVC Sample Code download

 

 


 

簽名:

學習是一趟奇妙的旅程

這當中,有辛苦、有心酸、也有成果。有時也會有瓶頸。要能夠繼續勇往直前就必須保有一顆最熱誠的心。

軟體開發之路(FB 社團)https://www.facebook.com/groups/361804473860062/

Gelis 程式設計訓練營(粉絲團)https://www.facebook.com/gelis.dev.learning/


 

如果文章對您有用,幫我點一下讚,或是點一下『我要推薦,這會讓我更有動力的為各位讀者撰寫下一篇文章。

非常謝謝各位的支持與愛護,小弟在此位各位說聲謝謝!!! ^_^