L’oggetto di quest’articolo, prosecuzione del precedente in cui abbiamo iniziato la costruzione dell’applicazione con il metodo  MVC Ajax.BeginForm(), è la costruzione della pagina parziale (Partial View) che contiene la risposta all’input dell’utente attraverso l’utilizzo di un View Model (modello per la vista).
L’utente potrà selezionare la data di partenza e di arrivo oltre che il numero di posti letto richiesto. A seguito di questa selezione verranno proposte tutte le tipologie di stanze disponibili, indicando il numero minimo e massimo di persone in stanza, suddiviso eventualmente fra adulti e bambini. Dovrà essere aggiunto anche la possibilità per ogni tipologia di stanza di ospitare dei bebè (culla aggiunta). Per ultimo ci sarà anche la possibilità di variare il prezzo in base al trattamento.

Disegno Model View
In una programmazione orientata agli oggetti, ogni informazione che viene gestita è incapsulata in oggetti (istanze di classe). Tipicamente un oggetto contiene metodi che definiscono il suo comportamento in base a particolari input. Il View Model, o Modello della vista, incapsula “solamente” le informazioni attraverso le proprietà di una classe che la vista si aspetta come prima riga di codice grazie al marcatore “@model“.
Per gestire le informazioni del nostro sistema di booking on line definiamo la classe che ha il compito di farci da View Model:

    public class AvailabilityResponse
    {
        public RoomType AvailRoomType { get; set; }
        public List CompositionsPrices { get; set; }
        public AvailabilityResponse()
        {
            this.AvailRoomType = new RoomType();
            this.CompositionsPrices = new List();
        }
    }

Le classi che la compongono sono:

public class RoomType
    {
        public string Code { get; set; }
        public string Description { get; set; }
        public int MinPersonsIn { get; set; }
        public int MaxPersonsIn { get; set; }
        public int MaxAdultCapablity { get; set; }
        public int EnfantCapability { get; set; }
        public double EnfantCost { get; set; }
        public int MaxAgeForChildren { get; set; }
        public double MinPrice { get; set; }
        public double MaxPrice { get; set; }
        public RoomType()
        {
            this.Code = "";
            this.Description = "";
            this.MinPersonsIn = 1;
            this.MaxPersonsIn = 1;
            this.EnfantCapability = 0;
            this.EnfantCost = 0;
            this.MaxAgeForChildren = 0;
            this.MaxAdultCapablity = 1;
            this.MinPrice = 0;
            this.MaxPrice = 0;
        }

    }

Questa classe include tutte le informazioni “di testata” per la tipologia di stanza.

public class PriceByConposition
{
    public int OccupantsNumber { get; set; }
    public int AdultsNumber { get; set; }
    public int EnfatsNumber { get; set; }
    public int Children { get; set; }
    public double Price { get; set; }
    public List CostBySupplements { get; set; }
}

Questa classe definisce il prezzo in base agli occupanti e alla loro composizione. Attraverso la lista CostBySupplements definisce anche il costo dei supplementi per quella particolare composizione:

public class CostAddedForSupplemets
{
    public int Code { get; set; }
    public string Description { get; set; }
    public double Price { get; set; }
}

Questa composizione di oggetti per il View Model permette molta flessibilità. L’unico limite è che nella solita stanza gli occupanti devono scegliere il solito trattamento.
A seguito di queste definizione è possibile ora immaginare un metodo di un’apposita classe che abbia lo scopo di fornire le risposte all’input dell’utente. Tipicamente questo “livello” di oggetti è indicato come Business Logic Layer (livello di logica Business) e a tale nomenclatura ci uniformiamo:

Struttura codice

 

 

Seguendo questo logica, ci uniformiano anche nel nome stesso della classe: public class AvailabilityBLL

Il metodo, nome a parte, dovrà avere in input i dati che l’utente ha “comunicato” al server: data arrivo, data partenza e numero di persone. La sua risposta sarà una “lista” di AvailabilityResponse.

Poiché i dati della risposta non sono per ora veramente gestiti, sottolineeremo la provvisorietà del metodo con la parola test nel nome stesso:

private List<AvailabilityResponse> getAvailabilityTest(DateTime FromDate, DateTime ToDate, int PersonsNumber)
{
    List oRet = new List();
 
    return oRet;
}

La visibilità è marcata come privata perché questo metodo,in questa fase di debug, farà da supporto a quello reale e MAI vorremmo che entri realmente in gioco per dimenticanze dettate dalla fretta dello sviluppo. Fatte queste premesse il codice BLL diventa:

public List<AvailabilityResponse> getAvailability(DateTime FromDate,DateTime ToDate,int PersonsNumber)
{
    List oRet = new List();
    //temp
    oRet = this.getAvailabilityTest(FromDate, ToDate, PersonsNumber);
    //end temp
    return oRet;
}

A questo punto, per poter testare la nostra vista, implementiamo il metodo di supporto con dati fittizi ma realistici usando solo due combinazione che coprano però tutti i casi possibili, anche per l’impaginazione di test oggetto dei prossimi articoli:

        
        private List <AvailabilityResponse> getAvailabilityTest(DateTime FromDate, DateTime ToDate, int PersonsNumber)
        {
            List oRet = new List();
            AvailabilityResponse firstRoomType = new AvailabilityResponse();
            firstRoomType.AvailRoomType = new RoomType();
            firstRoomType.AvailRoomType.Code = "XYZ";
            firstRoomType.AvailRoomType.Description = "Tipo Stanza XYZ";
            firstRoomType.AvailRoomType.EnfantCapability = 1;
            firstRoomType.AvailRoomType.MaxAgeForChildren = 14;
            firstRoomType.AvailRoomType.MaxPersonsIn = 4;
            firstRoomType.AvailRoomType.MinPersonsIn = 1;
            firstRoomType.AvailRoomType.MaxAdultCapablity = 2;
            firstRoomType.AvailRoomType.MaxPrice = 165;
            firstRoomType.AvailRoomType.MinPrice = 75;
            firstRoomType.AvailRoomType.EnfantCost = 10;
            firstRoomType.CompositionsPrices = new List();
            //un adulto in stanza
            PriceByConposition firstRoomPzo1 = new PriceByConposition();
            firstRoomPzo1.AdultsNumber = 1;
            firstRoomPzo1.Children = 0;
            firstRoomPzo1.EnfatsNumber = 0;
            firstRoomPzo1.OccupantsNumber = 1;
            firstRoomPzo1.Price = 75;
            firstRoomPzo1.CostBySupplements = new List();
            CostAddedForSupplemets cost11 = new CostAddedForSupplemets();
            cost11.Code = 1;
            cost11.Description = "Bed and breakfast";
            cost11.Price = 0;
            CostAddedForSupplemets cost12 = new CostAddedForSupplemets();
            cost12.Code = 2;
            cost12.Description = "Mezza pensione";
            cost12.Price = 20;
            firstRoomPzo1.CostBySupplements.Add(cost11);
            firstRoomPzo1.CostBySupplements.Add(cost12);
            //due adulti in stanza
            PriceByConposition firstRoomPzo2 = new PriceByConposition();
            firstRoomPzo2.AdultsNumber = 2;
            firstRoomPzo2.Children = 0;
            firstRoomPzo2.EnfatsNumber = 0;
            firstRoomPzo2.OccupantsNumber = 2;
            firstRoomPzo2.Price = 90;
            firstRoomPzo2.CostBySupplements = new List();
            CostAddedForSupplemets cost21 = new CostAddedForSupplemets();
            cost21.Code = 2;
            cost21.Description = "Bed and breakfast";
            cost21.Price = 0;
            CostAddedForSupplemets cost22 = new CostAddedForSupplemets();
            cost22.Code = 2;
            cost22.Description = "Mezza pensione";
            cost22.Price = 40;
            firstRoomPzo2.CostBySupplements.Add(cost21);
            firstRoomPzo2.CostBySupplements.Add(cost22);
            //due adulti + un bambino in stanza
            PriceByConposition firstRoomPzo3 = new PriceByConposition();
            firstRoomPzo3.AdultsNumber = 2;
            firstRoomPzo3.Children = 1;
            firstRoomPzo3.EnfatsNumber = 0;
            firstRoomPzo3.OccupantsNumber = 3;
            firstRoomPzo3.Price = 95;
            firstRoomPzo3.CostBySupplements = new List();
            CostAddedForSupplemets cost31 = new CostAddedForSupplemets();
            cost31.Code = 2;
            cost31.Description = "Bed and breakfast";
            cost31.Price = 0;
            CostAddedForSupplemets cost32 = new CostAddedForSupplemets();
            cost32.Code = 2;
            cost32.Description = "Mezza pensione";
            cost32.Price = 50;
            firstRoomPzo3.CostBySupplements.Add(cost31);
            firstRoomPzo3.CostBySupplements.Add(cost32);
            //due adulti + due bambini in stanza
            PriceByConposition firstRoomPzo4 = new PriceByConposition();
            firstRoomPzo4.AdultsNumber = 2;
            firstRoomPzo4.Children = 2;
            firstRoomPzo4.EnfatsNumber = 0;
            firstRoomPzo4.OccupantsNumber = 4;
            firstRoomPzo4.Price = 100;
            firstRoomPzo4.CostBySupplements = new List();
            CostAddedForSupplemets cost41 = new CostAddedForSupplemets();
            cost41.Code = 2;
            cost41.Description = "Bed and breakfast";
            cost41.Price = 0;
            CostAddedForSupplemets cost42 = new CostAddedForSupplemets();
            cost42.Code = 2;
            cost42.Description = "Mezza pensione";
            cost42.Price = 60;
            firstRoomPzo4.CostBySupplements.Add(cost41);
            firstRoomPzo4.CostBySupplements.Add(cost42);
            firstRoomType.CompositionsPrices.Add(firstRoomPzo1);
            firstRoomType.CompositionsPrices.Add(firstRoomPzo2);
            firstRoomType.CompositionsPrices.Add(firstRoomPzo3);
            firstRoomType.CompositionsPrices.Add(firstRoomPzo4);
            oRet.Add(firstRoomType);
            AvailabilityResponse secondRoomType = new AvailabilityResponse();
            secondRoomType.AvailRoomType = new RoomType();
            secondRoomType.AvailRoomType.Code = "XXX";
            secondRoomType.AvailRoomType.Description = "Tipo Stanza XXX";
            secondRoomType.AvailRoomType.EnfantCapability = 0;
            secondRoomType.AvailRoomType.MaxAgeForChildren = 0;
            secondRoomType.AvailRoomType.MaxPersonsIn = 2;
            secondRoomType.AvailRoomType.MinPersonsIn = 1;
            secondRoomType.AvailRoomType.MaxAdultCapablity = 2;
            secondRoomType.AvailRoomType.MaxPrice = 125;
            secondRoomType.AvailRoomType.MinPrice = 75;
            secondRoomType.CompositionsPrices = new List();
            //un adulto in stanza
            PriceByConposition secondRoomPzo1 = new PriceByConposition();
            secondRoomPzo1.AdultsNumber = 1;
            secondRoomPzo1.Children = 0;
            secondRoomPzo1.EnfatsNumber = 0;
            secondRoomPzo1.OccupantsNumber = 1;
            secondRoomPzo1.Price = 75;
            secondRoomPzo1.CostBySupplements = new List();
            CostAddedForSupplemets cost111 = new CostAddedForSupplemets();
            cost111.Code = 1;
            cost111.Description = "Bed and breakfast";
            cost111.Price = 0;
            CostAddedForSupplemets cost121 = new CostAddedForSupplemets();
            cost121.Code = 2;
            cost121.Description = "Mezza pensione";
            cost121.Price = 20;
            secondRoomPzo1.CostBySupplements.Add(cost111);
            secondRoomPzo1.CostBySupplements.Add(cost121);
            //due adult1 in stanza
            PriceByConposition secondRoomPzo2 = new PriceByConposition();
            secondRoomPzo2.AdultsNumber = 2;
            secondRoomPzo2.Children = 0;
            secondRoomPzo2.EnfatsNumber = 0;
            secondRoomPzo2.OccupantsNumber = 1;
            secondRoomPzo2.Price = 85;
            secondRoomPzo2.CostBySupplements = new List();
            CostAddedForSupplemets cost112 = new CostAddedForSupplemets();
            cost112.Code = 1;
            cost112.Description = "Bed and breakfast";
            cost112.Price = 0;
            CostAddedForSupplemets cost122 = new CostAddedForSupplemets();
            cost122.Code = 2;
            cost122.Description = "Mezza pensione";
            cost122.Price = 40;
            secondRoomPzo2.CostBySupplements.Add(cost112);
            secondRoomPzo2.CostBySupplements.Add(cost122);
            secondRoomType.CompositionsPrices.Add(secondRoomPzo1);
            secondRoomType.CompositionsPrices.Add(secondRoomPzo2);
            oRet.Add(secondRoomType);
            return oRet;
        }

Impostati questi valori per il test, il controller diventa:

[HttpPost]
public ActionResult CheckAvailability(FormCollection frm)
{
    Models.BLL.AvailabilityBLL oAvailabilityBLL = new Models.BLL.AvailabilityBLL(Session.SessionID);
    DateTime _start = Convert.ToDateTime(frm["startDate"]);
    DateTime _end = Convert.ToDateTime(frm["endDate"]);
    int _persons = Convert.ToInt32(frm["PersonsNumber"]);
    return PartialView("_AvailabilityResult",oAvailabilityBLL.getAvailability(_start,_end,_persons));
}

Dove la “partial view” avrà quindi il riferimento alla classe direttamente nel modello:
@model IEnumerable<BookingSystem.Models.AvailabilityResponse>

A seguire l’implementazione grafica funzionale della vista.