package Ada_Store.PoST.Application.Operations

with Ada_Store.PoST.Input_Queue;
with Ada_Store.Trading.Item;
with Ada_Store.Trading.Transaction.Sale;
with Ada_Store.User;

private package Ada_Store.PoST.Application.Operations is

   procedure Initialise;
   procedure Finalise;

   type Input_Allowed is array(Positive range ) 
      of Input_Queue.Input_Action;

   function  Get_Input
     (Allow	     : in Input_Allowed;
      Must_Have_Text : in Boolean	     := False;
      Prompt	     : in String	     := "")
      return Input_Queue.Message_Ptr;

   procedure User_Sign_On
     (Current_User   : in out User.Instance;
      User_As_String : in     String);

   procedure User_Sign_Off
     (Current_User   : in out User.Instance);

   procedure Display_Welcome;

   procedure Error
     (Error_Text  : in String;
      Alarm_Sound : in Boolean := True);

   procedure Transaction_New
     (The_Sale : in out Trading.Transaction.Sale.Instance);

   procedure Transaction_Item
     (Sales_Transaction	: in out Trading.Transaction.Sale.Instance;
      Item_As_String	: in     String);

   procedure Transaction_Department
     (Sales_Transaction	: in out Trading.Transaction.Sale.Instance;
      Dept_As_String	: in     String);

   procedure Transaction_SubTotal
     (Sales_Transaction : in out Trading.Transaction.Sale.Instance);

   procedure Transaction_Pay
     (Sales_Transaction	   : in out Trading.Transaction.Sale.Instance;
      Amount_As_String	   : in     String;
      Payment_Key	   : in     Input_Queue.Input_Action;
      Transaction_Complete :    out Boolean);

   procedure Transaction_Complete
     (Sales_Transaction : in out Trading.Transaction.Sale.Instance);

   procedure Transaction_Void 
     (Sales_Transaction : in out Trading.Transaction.Sale.Instance);

   procedure Price_Enquiry
     (Item_As_String    : in String);

end Ada_Store.PoST.Application.Operations;

with Ada.Strings;
with Ada.Strings.Fixed;
with Ada.Text_IO.Editing;

with Ada_Store.PoST.Device.Display; 
with Ada_Store.PoST.Device.Printer; 
with Ada_Store.PoST.Device.Scanner; 
with Ada_Store.PoST.Device.Keyboard; 
use  Ada_Store.PoST.Device;
with Ada_Store.PoST.Configuration;
use  Ada_Store.PoST.Configuration;
with Ada_Store.PoST.Input_Queue;
use  Ada_Store.PoST.Input_Queue;
with Ada_Store.Support.Screen;
with Ada_Store.Support.Trace;
with Ada_Store.Trading.Department;
with Ada_Store.Trading.Tender;
with Ada_Store.PoST.Device.Alarm;
with Ada.Characters.Latin_1;
package body Ada_Store.PoST.Application.Operations is

   -- public

   package Screen renames Ada_Store.Support.Screen;

   package Editing renames Ada.Text_IO.Editing;
   package Currency_EO is new Editing.Decimal_Output(Num => Currency,
						     Default_Currency => String'(1..1=>Ada.Characters.Latin_1.Pound_Sign));
   Currency_Pic_Str : constant String := "$$$$_$$9.99";
   Currency_Pic : Editing.Picture := Editing.To_Picture(Currency_Pic_Str);

   Key_Sign_On  : Device.Keyboard.Function_Info := ("Sign  ", "On    ", Input_Queue.Sign_On);
   Key_Sign_Off : Device.Keyboard.Function_Info := ("Sign  ", "Off   ", Input_Queue.Sign_Off);
   Key_Close_Dn : Device.Keyboard.Function_Info := ("Close ", "Down  ", Input_Queue.Close_Down);
   Key_Item_Reg : Device.Keyboard.Function_Info := ("Item  ", "Sale  ", Input_Queue.Item_Sale);
   Key_Dept_Reg : Device.Keyboard.Function_Info := ("Dept  ", "Sale  ", Input_Queue.Department_Sale);
   Key_Item_Enq : Device.Keyboard.Function_Info := ("Item  ", "Enq.  ", Input_Queue.Price_Enquiry);
   Key_Item_Sub : Device.Keyboard.Function_Info := ("Item  ", "Subtr.", Input_Queue.Subtract_Line);
   Key_Sub_Total: Device.Keyboard.Function_Info := ("Sub   ", "Total ", Input_Queue.Sub_Total);
   Key_PCash    : Device.Keyboard.Function_Info := ("Cash  ", "      ", Input_Queue.Cash_Payment);
   Key_PCheque  : Device.Keyboard.Function_Info := ("Cheque", "      ", Input_Queue.Cheque_Payment);
   Key_PCard    : Device.Keyboard.Function_Info := ("Card  ", "      ", Input_Queue.Card_Payment);
   Key_FCancel  : Device.Keyboard.Function_Info := ("Cancel", "      ", Input_Queue.Cancel);
   Key_FEnter   : Device.Keyboard.Function_Info := ("Accept", "      ", Input_Queue.Enter);

   procedure Initialise is
      Stage          	: Integer := 1;
      
      procedure Feedback is
      begin
	 Display.Write(Displays(Cashier), 1, "PLEASE WAIT", true);
	 Display.Write(Displays(Cashier), 2, "LOADING" & Integer'Image(Stage));
	 Stage := Stage + 1;
      end Feedback;
      
   begin
      Screen.Lock_Exclusive;
      Screen.Clear;
      Screen.Set_Cursor((1, 30));
      Screen.Put("Ada-Store Point of Sale");
      
      Screen.HLine(2);
      Screen.HLine(22);
      Screen.Unlock;

      -- Configure devices
      for Unit in Displays'Range loop

	 Device.Open(Device.Instance'Class(Displays(Unit)), 
		     Device.Unit(Display_Units'Pos(Unit) + 1));
	 Display.Clear(Displays(Unit));
      end loop;

      Feedback;

      for Unit in Printers'Range loop

	 Device.Open(Device.Instance'Class(Printers(Unit)), 
		     Device.Unit(Printer_Units'Pos(Unit) + 1));
      end loop;

      Feedback;
      
      for Unit in Scanners'Range loop

	 Device.Open(Device.Instance'Class(Scanners(Unit)), 
		     Device.Unit(Scanner_Units'Pos(Unit) + 1));

	 Scanner.Flush(Scanners(Unit), 
		       Ada_Store.PoST.Device.Input);
      end loop;

      Feedback;

      Device.Open(Device.Instance'Class(Keyboard0), 
		  Device.Unit(1));

      Keyboard.Flush(Keyboard0, 
		     Ada_Store.PoST.Device.Input);

      Feedback;
   end Initialise;
   
   procedure Finalise is
   begin
      Display.Clear(Displays(Customer));
      Display.Write(Displays(Customer), 1, "SORRY LANE", true);
      Display.Write(Displays(Customer), 2, "CLOSED", true);
      
      Display.Clear(Displays(Cashier));
      Display.Write(Displays(Cashier), 1, "LANE CLOSED DOWN");

      for Unit in Displays'Range loop

	 Device.Close(Device.Instance'Class(Displays(Unit)));
      end loop;

      for Unit in Printers'Range loop

	 Device.Close(Device.Instance'Class(Printers(Unit)));
      end loop;

      for Unit in Scanners'Range loop

	 Device.Close(Device.Instance'Class(Scanners(Unit)));
      end loop;

      Device.Close(Device.Instance'Class(Keyboard0));
   end Finalise;
	
   function  Get_Input
     (Allow	     : in Input_Allowed;
      Must_Have_Text : in Boolean	:= False;
      Prompt	     : in String	:= "")
      return Input_Queue.Message_Ptr is

      Inp_Msg  : Input_Queue.Message_Ptr;
      Inp_MsgT : Input_Queue.Message_Ptr;
      F_Keys   : Keyboard.Function_Key_Array := (others => Keyboard.Null_Function);
   begin
      for I in Allow'Range loop
	 case Allow(I) is
	    when Unknown =>
	       null;

	    -- Control block (1 .. 3)
	    when Sign_On =>
	       F_Keys(1)  := Key_Sign_On;
	       
	    when Sign_Off =>
	       F_Keys(1)  := Key_Sign_Off;
	       
	    when Close_Down =>
	       F_Keys(2)  := Key_Close_Dn;

	    -- Main block (4 .. 7)
	    when Item_Sale =>
	       F_Keys(4)  := Key_Item_Reg;

	    when Department_Sale =>
	       F_Keys(5)  := Key_Dept_Reg;
	       
	    when Price_Enquiry =>
	       F_Keys(6)  := Key_Item_Enq;
	       
	    when Subtract_Line =>
	       F_Keys(7)  := Key_Item_Sub;
	       
	    when Cash_Payment =>
	       F_Keys(4)  := Key_PCash;

	    when Cheque_Payment =>
	       F_Keys(5)  := Key_PCheque;

	    when Card_Payment =>
	       F_Keys(6)  := Key_PCard;

	    when Sub_Total =>
	       F_Keys(8)  := Key_Sub_Total;
	       
	    -- Final Block (9 .. 10)
	    when Cancel =>
	       F_Keys(9)  := Key_FCancel;

	    when Enter =>
	       F_Keys(10) := Key_FEnter;

	 end case;
      end loop;

      Keyboard.Set_Function_Keys(Keyboard0, F_Keys);
      
      loop
	 if Prompt /= "" then
	    Display.Write(Displays(Cashier), 2, Prompt);
	 end if;

	 Inp_Msg := Input_Queue.Get;

	 for I in Allow'Range loop

	   if Inp_Msg.Action = Allow(I) then

	      if Inp_Msg.Length = 0 and Must_Have_Text then

		 Inp_MsgT := Get_Input((1 => Enter), False);

		 Inp_Msg.Input  := Inp_MsgT.Input;
		 Inp_Msg.Length := Inp_MsgT.Length;
	      end if;

	      return Inp_Msg;
	   end if;
	 end loop;
	 Error("INVALID INPUT");
      end loop;
   end Get_Input;

   procedure User_Sign_On 
     (Current_User   : in out User.Instance;
      User_As_String : in String) is

      User_ID : User.Identifier;
      Inp_Msg : Input_Queue.Message_Ptr;
      Input   : Input_Allowed := (Enter, Cancel);
   begin
      User_ID := User.Identifier'Value(User_As_String);
      
      Current_User := User.Lookup(User_ID);
      
      Keyboard.Set_Function_Keys(Keyboard0, (9 => Key_FCancel,
					     10 => Key_FEnter,
					     others => Keyboard.Null_Function));
      
      Inp_Msg := Get_Input(Input, True, "PASSWORD");
      
      if Inp_Msg.Action = Cancel then

	 raise User.Invalid_Identifier;
	 -- I know it isnt really.
      end if;
      
      User.Sign_On(Current_User,
		   Inp_Msg.Input(1 .. Inp_Msg.Length));
   exception
      when User.Invalid_Identifier =>
	 Error("INVALID USER");
	 raise;
   end User_Sign_On;

   procedure User_Sign_Off
     (Current_User   : in out User.Instance) is
   begin
      User.Sign_Off(Current_User);
   end User_Sign_Off;

   procedure Display_Welcome is
   begin
      Display.Clear(Displays(Customer));
      Display.Write(Displays(Customer), 1, "SORRY LANE", true);
      Display.Write(Displays(Customer), 2, "CLOSED", true);
      
      Display.Clear(Displays(Cashier));
      Display.Write(Displays(Cashier), 1, "SIGNED OFF");
   end Display_Welcome;

   procedure Error
     (Error_Text  : in String;
      Alarm_Sound : in Boolean := True) is
   begin
      Ada_Store.PoST.Device.Alarm.Sound(Alarm0, Alarm.Error);
      Display.Write(Displays(Cashier), 1, Error_Text);
   end Error;

   procedure Transaction_New
     (The_Sale : in out Trading.Transaction.Sale.Instance) is
   begin
      Display.Clear(Displays(Customer));
      Display.Write(Displays(Customer), 1, "WELCOME", true);
      Display.Write(Displays(Customer), 2, "NEXT CUSTOMER", true);
      
      Display.Clear(Displays(Cashier));
      Display.Write(Displays(Cashier), 1, "ITEM");
      
      Printer.Write(Printers(Epson), Printer.Receipt, "          Welcome to Ada Store");
      Printer.Write(Printers(Epson), Printer.Receipt, "          ====================");
      Printer.Write(Printers(Epson), Printer.Receipt, "");
   end Transaction_New;

   procedure Transaction_Item
     (Sales_Transaction : in out Trading.Transaction.Sale.Instance;
      Item_As_String    : in String) is

      An_Item  : Trading.Item.Instance;
      Item_No  : Trading.Item.Identifier;
      Line_Out : String(1 .. 20) := (others => ' ');
      Line_Prn : String(1 .. 40) := (others => ' ');
   begin
      Item_No  := Trading.Item.Identifier'Value(Item_As_String);
      An_Item  := Trading.Item.Lookup(Item_No);

      declare
	 Price : String := Currency_EO.Image(Trading.Item.Price(An_Item), 
					     Currency_Pic);
	 Description : String := String(Trading.Item.Display_Description(An_Item));
      begin
	 Trading.Transaction.Sale.Add_Item(Sales_Transaction,
					   An_Item);
	 
	 Display.Clear(Displays(Customer));
	 Display.Write(Displays(Customer), 1, Description);
	 Ada.Strings.Fixed.Replace_Slice(Line_Out, 21 - Price'Length, 20, Price);
	 Display.Write(Displays(Customer), 2, Line_Out);
	 
	 Display.Clear(Displays(Cashier));
	 Ada.Strings.Fixed.Move(Source	=> Description,
				Target	=> Line_Out,
				Justify	=> Ada.Strings.Left);
	 Ada.Strings.Fixed.Replace_Slice(Line_Out, 21 - Price'Length, 20, Price);
	 Display.Write(Displays(Cashier), 2, Line_Out);
      
	 Ada.Strings.Fixed.Move(Source	=> Description,
				Target	=> Line_Prn,
				Justify	=> Ada.Strings.Left);
	 
	 Ada.Strings.Fixed.Replace_Slice(Line_Prn, 41 - Price'Length, 40, Price);
	 Printer.Write(Printers(Epson), Printer.Receipt, Line_Prn);

	 Display.Write(Displays(Cashier), 1, "NEXT ITEM");
      end ;
   exception 
      when Trading.Item.Invalid_Identifier =>
	 Error("INVALID ITEM");
   end Transaction_Item;

   procedure Transaction_Department
     (Sales_Transaction : in out Trading.Transaction.Sale.Instance;
      Dept_As_String    : in String) is
   begin
      null;
   end Transaction_Department;

   procedure Transaction_SubTotal
     (Sales_Transaction : in out Trading.Transaction.Sale.Instance) is

      Line_Out : String(1 .. 20) := (others => ' ');
      Line_Prn : String(1 .. 40) := (others => ' ');
      Items    : Natural  := Trading.Transaction.Sale.Total_Items(Sales_Transaction);
      Items_Str: String   := Natural'Image(Items);
      Value    : Currency := Trading.Transaction.Sale.Total_Value(Sales_Transaction);
      Value_Str: String   := Currency_EO.Image(Value, Currency_Pic);
   begin
      Ada.Strings.Fixed.Move(Source	=> Items_Str & " ITEMS",
			     Target	=> Line_Out,
			     Justify	=> Ada.Strings.Left);
      Ada.Strings.Fixed.Replace_Slice(Line_Out, 21 - Value_Str'Length, 20, Value_Str);

      Display.Clear(Displays(Customer));
      Display.Write(Displays(Customer), 1, "SUB TOTAL");
      Display.Write(Displays(Customer), 2, Line_Out);
      
      Display.Clear(Displays(Cashier));
      Display.Write(Displays(Cashier), 1, "SUB TOTAL" & Value_Str);
      
      Printer.Write(Printers(Epson), Printer.Receipt, "");
      Ada.Strings.Fixed.Move(Source	=> "ITEMS",
	Target	=> Line_Prn,
	  Justify	=> Ada.Strings.Left);
      Ada.Strings.Fixed.Replace_Slice(Line_Prn, 41 - Items_Str'Length, 40, Items_Str);
      Printer.Write(Printers(Epson), Printer.Receipt, Line_Prn);

      Ada.Strings.Fixed.Move(Source	=> "SUB TOTAL",
    	                     Target	=> Line_Prn,
	                     Justify	=> Ada.Strings.Left);
      Ada.Strings.Fixed.Replace_Slice(Line_Prn, 41 - Value_Str'Length, 40, Value_Str);
      Printer.Write(Printers(Epson), Printer.Receipt, Line_Prn);
      Printer.Write(Printers(Epson), Printer.Receipt, "");
   end Transaction_SubTotal;

   procedure Transaction_Pay
     (Sales_Transaction : in out Trading.Transaction.Sale.Instance;
      Amount_As_String  : in String;
      Payment_Key       : in Input_Queue.Input_Action;
      Transaction_Complete : out Boolean) is

      A_Tender  : Trading.Tender.Instance;
      Amount    : Currency;
      Change    : Currency;
      Line_Out  : String(1 .. 20) := (others => ' ');
      Line_Prn  : String(1 .. 40) := (others => ' ');
   begin
      Transaction_Complete := False;

      case Payment_Key is
	 when Input_Queue.Cash_Payment =>
	    A_Tender  := Trading.Tender.Lookup(1);
	 when Input_Queue.Cheque_Payment =>
	    A_Tender  := Trading.Tender.Lookup(2);
	 when Input_Queue.Card_Payment =>
	    A_Tender  := Trading.Tender.Lookup(3);
	 when others =>
	    raise Trading.Tender.Invalid_Identifier;
      end case;

      Amount := Currency'Value(Amount_As_String);

      if Trading.Tender.Authorise(A_Tender, Amount) then
	 
	 declare
	    Amount_Str : String := Currency_EO.Image(Amount, 
						     Currency_Pic);
	 begin
	    Trading.Transaction.Sale.Add_Payment(Sales_Transaction,
						 A_Tender,
						 Amount,
						 Change);
	    
	    Display.Clear(Displays(Customer));
	    Display.Write(Displays(Customer), 1, "CASH");
	    Ada.Strings.Fixed.Replace_Slice(Line_Out, 21 - Amount_Str'Length, 20, Amount_Str);
	    Display.Write(Displays(Customer), 2, Line_Out);
	    
	    Display.Clear(Displays(Cashier));
	    Ada.Strings.Fixed.Move(Source	=> "CASH",
				   Target	=> Line_Out,
				   Justify	=> Ada.Strings.Left);
	    Ada.Strings.Fixed.Replace_Slice(Line_Out, 21 - Amount_Str'Length, 20, Amount_Str);
	    Display.Write(Displays(Cashier), 2, Line_Out);
	    
	    Ada.Strings.Fixed.Move(Source	=> "CASH",
				   Target	=> Line_Prn,
				   Justify	=> Ada.Strings.Left);
	    
	    Ada.Strings.Fixed.Replace_Slice(Line_Prn, 41 - Amount_Str'Length, 40, Amount_Str);
	    Printer.Write(Printers(Epson), Printer.Receipt, Line_Prn);
	    
	    if Change = 0.00 then
	       Transaction_Complete := True;
	    elsif Change > 0.00 then
	       
	       declare
		  Change_Str : String := Currency_EO.Image(Change, 
							   Currency_Pic);
	       begin
		  Ada.Strings.Fixed.Move(Source	=> "CHANGE",
					 Target	=> Line_Prn,
					 Justify	=> Ada.Strings.Left);
		  
		  Ada.Strings.Fixed.Replace_Slice(Line_Prn, 41 - Change_Str'Length, 40, Change_Str);
		  Printer.Write(Printers(Epson), Printer.Receipt, Line_Prn);
	       end ;
	       Transaction_Complete := True;
	    elsif Change <0.00 then
	       declare
		  Balance_Str : String := Currency_EO.Image(-Change, 
							    Currency_Pic);
	       begin
		  Display.Clear(Displays(Customer));
		  Display.Write(Displays(Customer), 1, "BALANCE");
		  Display.Write(Displays(Customer), 2, Balance_Str);
      
		  Display.Clear(Displays(Cashier));
		  Display.Write(Displays(Cashier), 1, "BALANCE" & Balance_Str);
	       end ;
	    end if;
	 end ;
      else
	 Error("AUTH FAILED");
      end if;
   exception 
      when Trading.Tender.Invalid_Identifier =>
	 Error("INVALID TENDER");
   end Transaction_Pay;

   procedure Transaction_Complete
     (Sales_Transaction : in out Trading.Transaction.Sale.Instance) is
   begin
      Printer.Write(Printers(Epson), Printer.Receipt, "     ==============================");
      Printer.Write(Printers(Epson), Printer.Receipt, "     Thank You For Shopping With Us");
      Printer.Write(Printers(Epson), Printer.Receipt, "");
      Printer.Cut_Paper(Printers(Epson), Printer.Receipt);
   end Transaction_Complete;

   procedure Transaction_Void
     (Sales_Transaction : in out Trading.Transaction.Sale.Instance) is
   begin
      Printer.Write(Printers(Epson), Printer.Receipt, "          ===================");
      Printer.Write(Printers(Epson), Printer.Receipt, "          ***** V O I D *****");
      Printer.Write(Printers(Epson), Printer.Receipt, "          ===================");
      Printer.Write(Printers(Epson), Printer.Receipt, "");
	 
      Trading.Transaction.Sale.Void(Sales_Transaction);
	 
      Printer.Cut_Paper(Printers(Epson), Printer.Receipt);
   end Transaction_Void;

   procedure Price_Enquiry
     (Item_As_String    : in String) is

      An_Item  : Trading.Item.Instance;
      Item_No  : Trading.Item.Identifier;
      Line_Out : String(1 .. 20) := (others => ' ');
      Inp_Msg  : Input_Queue.Message_Ptr;
      Input    : Input_Allowed := (1 => Enter);
   begin
      Item_No  := Trading.Item.Identifier'Value(Item_As_String);
      An_Item  := Trading.Item.Lookup(Item_No);
      
      declare
         Price : String := Currency_EO.Image(Trading.Item.Price(An_Item), 
					     Currency_Pic);
	 Description : String := String(Trading.Item.Display_Description(An_Item));
      begin
	 Display.Clear(Displays(Customer));
	 Display.Write(Displays(Customer), 1, Description);
	 Ada.Strings.Fixed.Move(Source	=> "ENQUIRY",
				Target	=> Line_Out,
			     Justify	=> Ada.Strings.Left);
	 Ada.Strings.Fixed.Replace_Slice(Line_Out, 21 - Price'Length, 20, Price);
	 Display.Write(Displays(Customer), 2, Line_Out);
      
	 Display.Clear(Displays(Cashier));
	 Ada.Strings.Fixed.Move(Source	=> Description,
				Target	=> Line_Out,
				Justify	=> Ada.Strings.Left);
	 Ada.Strings.Fixed.Replace_Slice(Line_Out, 21 - Price'Length, 20, Price);
	 Display.Write(Displays(Cashier), 2, Line_Out);
	 
	 Display.Write(Displays(Cashier), 1, "ACCEPT TO CONTINUE");
	 Inp_Msg := Get_Input(Input);
	 Display.Write(Displays(Cashier), 1, "ITEM");
      end ;
   exception 
      when Trading.Item.Invalid_Identifier =>
	 Error("INVALID ITEM");
   end Price_Enquiry;

end Ada_Store.PoST.Application.Operations;

Contents Page

Copyright © 1996 Simon Johnston &
Addison Wesley Longman