Index: cprs/branches/foia-cprs/CPRS-Chart/Orders/fODDiet.pas
===================================================================
--- cprs/branches/foia-cprs/CPRS-Chart/Orders/fODDiet.pas	(revision 459)
+++ cprs/branches/foia-cprs/CPRS-Chart/Orders/fODDiet.pas	(revision 460)
@@ -96,4 +96,11 @@
     cmdOPRemove: TButton;
     chkOPCancelTubefeeding: TCheckBox;
+    calOPTFStart: TORDateBox;
+    lblOPTFStart: TLabel;
+    lblOPAOStart: TLabel;
+    calOPAOStart: TORDateBox;
+    cboOPAORecurringMeals: TORComboBox;
+    cboOPTFRecurringMeals: TORComboBox;
+    cboOPELRecurringMeals: TORComboBox;
     procedure nbkDietChanging(Sender: TObject;
       var AllowChange: Boolean);
@@ -137,7 +144,4 @@
     procedure FormKeyDown(Sender: TObject; var Key: Word;
       Shift: TShiftState);
-   //  Outpatient meal additions
-    procedure cboOPDietAvailNeedData(Sender: TObject;
-      const StartFrom: String; Direction, InsertAt: Integer);
     procedure cboOPDietAvailMouseClick(Sender: TObject);
     procedure cboOPDietAvailExit(Sender: TObject);
@@ -149,4 +153,6 @@
     procedure grpOPMealClick(Sender: TObject);
     procedure cmdOPRemoveClick(Sender: TObject);
+    procedure cboOPDietAvailKeyDown(Sender: TObject; var Key: Word;
+      Shift: TShiftState);
   private
     FNextCol: Integer;
@@ -177,6 +183,8 @@
     function TFStrengthCode(const x: string): Integer;
    //  Outpatient meal additions
+    function  FMDOW(AnFMDate: TFMDateTime): integer;
+    function  FMDays(AStart, AEnd: TFMDateTime): string;
     function  GetOPDaysOfWeek: string;
-    procedure SetEnableOPDOW(AllowUse: Boolean);
+    procedure SetEnableOPDOW(AllowUse: Boolean; OneTimeDay: integer; DaysToCheck: string = '');
     procedure ResetControlsOP;
     procedure SetValuesFromResponsesOP;
@@ -184,4 +192,5 @@
     procedure OPDietCheckForNPO;
     procedure OPDietCheckForTF;
+    function PatientHasRecurringMeals(var MealList: TStringList; MealType: string = ''): boolean;
   protected
     procedure InitDialog; override;
@@ -195,4 +204,5 @@
   uDialogName: string;
   uFHAUTH: boolean;
+  uRecurringMealList: TStringList;
 
 implementation
@@ -200,5 +210,5 @@
 {$R *.DFM}
 
-uses uCore, rODBase, rODDiet, rCore, rOrders, fODDietLT, uAccessibleStringGrid;
+uses uCore, rODBase, rODDiet, rCore, rOrders, fODDietLT, uAccessibleStringGrid, DateUtils;
 
 const
@@ -209,6 +219,5 @@
   TX_DIET_PRC = 'This diet conflicts with ';
   TC_DIET_ERR = 'Unable to Add Diet';
-  TX_INPT_ONLY = 'Diets may be entered for inpatients only.';
-  //TX_INPT_ONLY = 'This type of diet may be entered for inpatients only.';
+  TX_INPT_ONLY = 'This type of diet may be entered for inpatients only.';
   TC_INPT_ONLY = 'Ordering Restriction';
   TX_CANCEL_TF = 'Cancel the current tubefeeding order?' + CRLF + CRLF;
@@ -221,7 +230,7 @@
   TX_TFQTY  = 'A quantity must be entered for ';
   TX_TFAMT  = 'The quantity is invalid for ';
-  TX_TF5000 = 'The total quantity ordered may not exceed 5000cc.';
+  TX_TF5000 = 'The total quantity ordered may not exceed 5000ml.';
   TX_HLPQTY = CRLF + 'The following may be entered for quantity:' + CRLF +
-              '  Units may be K for Kcals, C for cc''s, O for oz. or U for units (e.g. cans).' + CRLF +
+              '  Units may be K for Kcals, C for cc''s, M for ml, O for oz. or U for units (e.g. cans).' + CRLF +
               '  Frequency may be DAY, HOUR, QD, QH, BID, TID, QID, Q2H, Q3H, Q4H, or Q6H.' + CRLF +
               '  May also input 100CC/HR X 16 for 16 hours.  Valid quantity for powder form' + CRLF +
@@ -242,4 +251,6 @@
   TX_AONONE      = 'Text for additional order has not been entered.';
   TX_ACCEPT      = 'Accept the following order?' + CRLF + CRLF;
+  TX_CONTINUE    = 'Continue editing the following order?' + CRLF + CRLF;
+  TX_DISCARD     = CRLF + CRLF + 'Answering NO will discard all changes.';
   TC_ACCEPT      = 'Unsaved Order';
   TX_EL_SAVE_ERR    = 'An error occurred while saving this late tray order.';
@@ -274,4 +285,17 @@
                     'coordinator enters times for E/L trays for this location.';
   TC_NO_PARAMS    = 'Unable to Order Early/Late Tray';
+  TX_NOSTART   = 'A valid start date must be entered.';
+  TC_NOSTART   = 'Start date required';
+  TX_NOT_THIS_LOC = 'This location has not been configured to' + CRLF +
+                    'allow ordering of meals for outpatients.' + CRLF + CRLF +
+                    'Please contact your IRM diet package coordinator.';
+  TC_NOT_THIS_LOC = 'Unable to order from this location';
+  TX_NO_OUTPT_ORDERS = 'Diet orders may only be entered for inpatients.';
+  TC_NO_OUTPT_ORDERS = 'Ordering Restriction';
+  TX_NO_MEALS_DEFINED = 'No diet types have been defined to be orderable for outpatients.' + CRLF + CRLF +
+                        'Please contact your IRM diet package coordinator.';
+  TC_NO_MEALS_DEFINED = 'Unable to order outpatient meals';
+
+  FMDayLetters: array[1..7] of string[1] = ('M', 'T', 'W', 'R', 'F', 'S', 'X');
 
 type
@@ -290,4 +314,6 @@
 begin
   inherited;
+  AbortOrder := False;
+  uRecurringMealList := TStringList.Create;
   if OrderForInpatient then
     begin
@@ -302,6 +328,6 @@
   else                                         // this block will go away after FH patch installed everywhere
     begin
-      InfoBox(TX_INPT_ONLY, TC_INPT_ONLY, MB_OK);
-      Close;
+      InfoBox(TX_NO_OUTPT_ORDERS, TC_NO_OUTPT_ORDERS, MB_OK);
+      AbortOrder := True;
       Exit;
     end;
@@ -313,23 +339,30 @@
   if StrToIntDef(ALocation, 0) < 1 then
     ALocation := IntToStr(Encounter.Location);
-  LoadDietParams(uDietParams, ALocation);
-  if pgeOutPt.TabVisible then
-    with uDietParams, cboOPDelivery do
-    begin
-      if Tray      then Items.Add('T^Tray');
-      if Cafeteria then Items.Add('C^Cafeteria');
-      if DiningRm  then Items.Add('D^Dining Room');
-      //if Bagged    then Items.Add('B^Bagged');  // ????
-      ItemIndex := 0;
-      chkBagged.Visible := uDietParams.Bagged;    // ????
+  if (not OrderForInpatient) and OutpatientPatchInstalled and (not OutpatientLocationConfigured(ALocation)) then
+    begin
+      InfoBox(TX_NOT_THIS_LOC, TC_NOT_THIS_LOC, MB_OK or MB_ICONINFORMATION);
+      AbortOrder := True;
     end
   else
-    with uDietParams, cboDelivery do
-    begin
-      if Tray      then Items.Add('T^Tray');
-      if Cafeteria then Items.Add('C^Cafeteria');
-      if DiningRm  then Items.Add('D^Dining Room');
-      ItemIndex := 0;
-      chkBagged.Visible := uDietParams.Bagged;
+    begin
+      LoadDietParams(uDietParams, ALocation);
+      if pgeOutPt.TabVisible then
+        with uDietParams, cboOPDelivery do
+        begin
+          if Tray      then Items.Add('T^Tray');
+          if Cafeteria then Items.Add('C^Cafeteria');
+          if DiningRm  then Items.Add('D^Dining Room');
+          ItemIndex := 0;
+          chkBagged.Visible := uDietParams.Bagged;
+        end
+      else
+        with uDietParams, cboDelivery do
+        begin
+          if Tray      then Items.Add('T^Tray');
+          if Cafeteria then Items.Add('C^Cafeteria');
+          if DiningRm  then Items.Add('D^Dining Room');
+          ItemIndex := 0;
+          chkBagged.Visible := uDietParams.Bagged;
+        end;
     end;
   TAccessibleStringGrid.WrapControl(grdSelected);
@@ -340,4 +373,5 @@
   TAccessibleStringGrid.UnwrapControl(grdSelected);
   TFClearGrid;
+  uRecurringMealList.Free;
   inherited;
 end;
@@ -350,5 +384,5 @@
     ColWidths[1] := Canvas.TextWidth('XFULLX') + GetSystemMetrics(SM_CXVSCROLL);
     ColWidths[2] := Canvas.TextWidth('100 GRAMS/HOUR X 24');
-    ColWidths[3] := Canvas.TextWidth('55000cc');
+    ColWidths[3] := Canvas.TextWidth('55000ml');
     ColWidths[0] := ClientWidth - ColWidths[1] - ColWidths[2] - ColWidths[3] - 3;
     lblTFStrength.Left := Left + ColWidths[0] + 3;
@@ -368,4 +402,5 @@
 procedure TfrmODDiet.SetupDialog(OrderAction: Integer; const ID: string);
 begin
+  if AbortOrder then exit;
   inherited;
   uDialogName := ExternalName(DialogIEN, 101.41);
@@ -396,4 +431,9 @@
        end;
   'T': begin
+         if (not OrderForInpatient) and (not PatientHasRecurringMeals(uRecurringMealList)) then
+         begin
+           Close;
+           Exit;
+         end;
          nbkDiet.ActivePage := pgeTubefeeding;
          nbkDietChange(Self);
@@ -401,4 +441,9 @@
        end;
   'E': begin
+         if (not OrderForInpatient) and (not PatientHasRecurringMeals(uRecurringMealList)) then
+         begin
+           Close;
+           Exit;
+         end;
          nbkDiet.ActivePage := pgeEarlyLate;
          nbkDietChange(Self);
@@ -411,4 +456,9 @@
        end;
   'A': begin
+         if (not OrderForInpatient) and (not PatientHasRecurringMeals(uRecurringMealList)) then
+         begin
+           Close;
+           Exit;
+         end;
          nbkDiet.ActivePage := pgeAdditional;
          nbkDietChange(Self);
@@ -442,4 +492,5 @@
         nbkDietChange(Self);
         if OrderAction <> ORDER_NEW then SetValuesFromResponsesDO;
+        ActiveControl := cboOPDietAvail;
       end;
   end;
@@ -517,16 +568,21 @@
     end;
     if Sum > 5000 then SetError(TX_TF5000);
+    if not OrderForInpatient then
+      if not calOPTFStart.IsValid      then SetError(TX_BAD_START);
   end;
   if nbkDiet.ActivePage = pgeEarlyLate then
   begin
     if grpMeal.ItemIndex = 3                                   then SetError(TX_ELMEAL);
-    if GetMealTime = ''                                        then SetError(TX_ELTIME);
     if not calELStart.IsValid                                  then SetError(TX_ELNOSTART);
-    if not calELStop.IsValid                                   then SetError(TX_ELNOSTOP);
     if calELStart.FMDateTime < FMToday                         then SetError(TX_ELSTARTLT);
-    if calELStop.FMDateTime < FMToday                          then SetError(TX_ELSTOPLT);
-    if calELStop.FMDateTime < calELStart.FMDateTime            then SetError(TX_ELSTOPSTART);
     if calELStart.FMDateTime > FMDateTimeOffsetBy(FMToday, 30) then SetError(TX_ELSTART30);
-    if calELStop.FMDateTime > FMDateTimeOffsetBy(FMToday, 30)  then SetError(TX_ELSTOP30);
+    if OrderForInpatient then
+    begin
+      if GetMealTime = ''                                        then SetError(TX_ELTIME);
+      if not calELStop.IsValid                                   then SetError(TX_ELNOSTOP);
+      if calELStop.FMDateTime < FMToday                          then SetError(TX_ELSTOPLT);
+      if calELStop.FMDateTime < calELStart.FMDateTime            then SetError(TX_ELSTOPSTART);
+      if calELStop.FMDateTime > FMDateTimeOffsetBy(FMToday, 30)  then SetError(TX_ELSTOP30);
+    end;
     if grpDOW.Enabled and (GetDaysOfWeek = '')                 then SetError(TX_ELDOW);
     if MealTimePassed                                          then SetError(TX_ELPAST);
@@ -539,6 +595,7 @@
   begin
     if not ContainsVisibleChar(txtAOComment.Text)              then SetError(TX_AONONE);
-  end;
-{ TODO -oRich V. -cOutpatient Meals : Add any required Outpatient Meals validation code here }
+    if not OrderForInpatient then
+      if not calOPAOStart.IsValid                              then SetError(TX_BAD_START);
+  end;
   if nbkDiet.ActivePage = pgeOutPt then
   begin
@@ -580,13 +637,30 @@
   FTabChanging := True;
   if Length(memOrder.Text) > 0 then
-    if InfoBox(TX_ACCEPT + memOrder.Text, TC_ACCEPT, MB_YESNO) = ID_YES then
-    begin
-      cmdAcceptClick(Self);
-      AllowChange := AcceptOK;
-    end else
-    begin
-      memOrder.Text := '';
-      memOrder.Lines.Clear;
-      Responses.Clear;
+    begin
+      if nbkDiet.ActivePage = pgeOutpt then
+        begin
+          if InfoBox(TX_CONTINUE + memOrder.Text + TX_DISCARD, TC_ACCEPT, MB_YESNO) = ID_YES then
+            begin
+              AllowChange := FALSE;
+            end else
+            begin
+              memOrder.Text := '';
+              memOrder.Lines.Clear;
+              Responses.Clear;
+            end;
+        end
+      else
+        begin
+          if InfoBox(TX_ACCEPT + memOrder.Text, TC_ACCEPT, MB_YESNO) = ID_YES then
+            begin
+              cmdAcceptClick(Self);
+              AllowChange := AcceptOK;
+            end else
+            begin
+              memOrder.Text := '';
+              memOrder.Lines.Clear;
+              Responses.Clear;
+            end;
+        end
     end;
   FTabChanging := False;
@@ -594,7 +668,22 @@
 
 procedure TfrmODDiet.nbkDietChange(Sender: TObject);
+var
+  x, CxMsg: string ;
+  i: integer;
+  AStringList: TStringList;
+const
+//  TX_CX_CUR = 'A new diet order will CANCEL and REPLACE this current diet:' + CRLF + CRLF;
+  TX_CX_CUR = 'A new diet order will CANCEL and REPLACE this current diet now unless' + CRLF +
+              'you specify a start date for when the new diet should replace the current' + CRLF +
+              'diet:' + CRLF + CRLF;
+  TX_CX_FUT = 'A new diet order with no expiration date will CANCEL and REPLACE these diets:' + CRLF + CRLF;
 begin
   inherited;
   // much of the logic here can be eliminated if ClearDialogControls starts clearing containers
+  if AbortOrder then
+  begin
+    cmdQuitClick(Self);
+    exit;
+  end;
   StatusText('Loading Dialog Definition');
   if Sender <> Self then Responses.Clear;
@@ -603,5 +692,36 @@
   begin
     AllowQuickOrder := True;
-    OrderMessage(CurrentDietText);
+    x := CurrentDietText;
+    if Piece(x, #13, 1) <> 'Current Diet:  ' then
+    begin
+      AStringList := TStringList.Create;
+      try
+        AStringList.Text := x;
+        CxMsg := TX_CX_CUR + #9 + Piece(AStringList[0], ':', 1) + ':' + CRLF + CRLF
+                 + #9 + Copy(AStringList[0], 16, 99) + CRLF;
+        if AStringList.Count > 1 then
+        begin
+          CxMsg := CxMsg + CRLF + CRLF +
+                   TX_CX_FUT + #9 + Piece(AStringList[1], ':', 1) + ':' + CRLF + CRLF
+                   + #9 + Copy(AStringList[1], 22, 99) + CRLF;
+          if AStringList.Count > 2 then
+          for i := 2 to AStringList.Count - 1 do
+            CxMsg := CxMsg + #9 + TrimLeft(AStringList[i]) + CRLF;
+        end;
+      finally
+        AStringList.Free;
+      end;
+    end;
+    if CxMsg <> '' then
+    begin
+      if InfoBox(CxMsg + CRLF +
+                'Are you sure?', 'Confirm', MB_ICONWARNING or MB_YESNO) = ID_NO then
+      begin
+        AbortOrder := True;
+        cmdQuitClick(Self);
+        exit;
+      end;
+    end;
+    OrderMessage(x);
     Responses.Dialog := 'FHW1';                            // Diet Order
     DisplayGroup := DisplayGroupForDialog('FHW1');
@@ -615,12 +735,19 @@
   if nbkDiet.ActivePage = pgeTubefeeding then
   begin
-{ TODO -oRich V. -cOutpatient Meals : Prompt for which recurring meal(s) to apply this order against }
     if not OrderForInpatient then
     begin
-      // get list of existing OP recurring meals
-      // if none, then exit with message
-      // if some, display and allow selection of multiple dates/times
-      // set different dialog/display group?
-    end;
+      if not PatientHasRecurringMeals(uRecurringMealList) then
+        begin
+          Changing := False;
+          nbkDiet.ActivePage := pgeOutPt;
+          nbkDietChange(nbkDiet);
+          Exit;
+          end
+        else
+          cboOPTFRecurringMeals.Items.Assign(uRecurringMealList);
+    end;
+    cboOPTFRecurringMeals.Visible := not OrderForInpatient;
+    calOPTFStart.Visible := False;
+    lblOPTFStart.Visible := not OrderForInpatient;
     AllowQuickOrder := True;
     if Length(uDietParams.CurTF) > 0
@@ -644,19 +771,32 @@
   if nbkDiet.ActivePage = pgeEarlyLate then
   begin
-{ TODO -oRich V. -cOutpatient Meals : Prompt for which recurring meal to apply this order against }
     if not OrderForInpatient then
-    begin
-      // get list of existing OP recurring meals
-      // if none, then exit with message
-      // if some, display and allow selection of one and only one
-      // set different dialog/display group?
-    end
+      begin
+        if not PatientHasRecurringMeals(uRecurringMealList) then
+          begin
+            Changing := False;
+            nbkDiet.ActivePage := pgeOutPt;
+            nbkDietChange(nbkDiet);
+            Exit;
+          end
+        else
+          cboOPELRecurringMeals.Items.Assign(uRecurringMealList);
+      end
     else if (StrToIntDef(uDietParams.EarlyIEN, 0) = 0) or (StrToIntDef(uDietParams.LateIEN, 0) = 0) then
-    begin
-      InfoBox(TX_NO_PARAMS, TC_NO_PARAMS, MB_ICONERROR or MB_OK);
-      if pgeEarlyLate <> nil then
-        nbkDiet.SelectNextPage(False);
-      Exit;
-    end;
+      begin
+        InfoBox(TX_NO_PARAMS, TC_NO_PARAMS, MB_ICONERROR or MB_OK);
+        if pgeEarlyLate <> nil then
+          nbkDiet.SelectNextPage(False);
+        Changing := False;
+        Exit;
+      end;
+    cboOPELRecurringMeals.Visible := not OrderForInpatient;
+    cboOPELRecurringMeals.TabStop := not OrderForInpatient;
+    calELStart.Visible := OrderForInpatient;
+    calELStart.TabStop := OrderForInpatient;
+    calELStop.Visible := OrderForInpatient;
+    lblELStop.Visible := OrderForInpatient;
+    grpDOW.Visible := OrderForInpatient;
+    grpDOW.Enabled := OrderForInpatient;
     AllowQuickOrder := False;
     OrderMessage('');
@@ -678,12 +818,19 @@
   if nbkDiet.ActivePage = pgeAdditional then
   begin
-{ TODO -oRich V. -cOutpatient Meals : Prompt for which recurring meal(s) to apply this order against }
-    if not OrderForInpatient then
-    begin
-      // get list of existing OP recurring meals
-      // if none, then exit with message
-      // if some, display and allow selection of multiple dates/times
-      // set different dialog/display group?
-    end;
+  if not OrderForInpatient then
+    begin
+      if not PatientHasRecurringMeals(uRecurringMealList) then
+        begin
+          Changing := False;
+          nbkDiet.ActivePage := pgeOutPt;
+          nbkDietChange(nbkDiet);
+          Exit;
+        end
+      else
+        cboOPAORecurringMeals.Items.Assign(uRecurringMealList);
+    end;
+    cboOPAORecurringMeals.Visible := not OrderForInpatient;
+    calOPAOStart.Visible := False;  //not OrderForInpatient;
+    lblOPAOStart.Visible := not OrderForInpatient;
     AllowQuickOrder := False;
     OrderMessage('');
@@ -694,25 +841,18 @@
   if nbkDiet.ActivePage = pgeOutPt then
   begin
-    OrderMessage(CurrentDietText);
+    x := CurrentDietText;
+    if Length(Piece(x, #$D, 1)) > Length('Current Diet:  ') then
+      OrderMessage(x)
+    else
+      OrderMessage('');
+    if (uDialogName <> 'FHW SPECIAL MEAL') and (uDialogName <> 'FHW OP MEAL') then
+      uDialogName := 'FHW OP MEAL';
     Responses.Dialog := uDialogName;
     DisplayGroup := DisplayGroupForDialog(uDialogName);
-    if uDialogName = 'FHW OP MEAL' then                          // Recurring meal
-      begin
-       AllowQuickOrder := True;
-       ResetControlsOP;
-       LoadDietQuickList(cboOPDietAvail.Items, 'MEAL');              // use D.G. short name here
-       cboOPDietAvail.InsertSeparator;
-       cboOPDietAvail.InitLongList('');
-       { TODO -oRich V. -cOutpatient Meals : Need to DC Tubefeeding order for OP meals? }
-       chkOPCancelTubefeeding.State := cbGrayed;
-       chkOPCancelTubefeeding.Visible := False;
-       grpOPMeal.Caption := 'Recurring Meal';
-       SetEnableOPDOW(False);
-      end
-    else if uDialogName = 'FHW SPECIAL MEAL' then                 // Special meal
+    if uDialogName = 'FHW SPECIAL MEAL' then                 // Special meal
       begin
        AllowQuickOrder := False;
        ResetControlsOP;
-       cboOPDietAvail.InitLongList('');
+       cboOPDietAvail.Items.AddStrings(SubsetOfOPDiets);
        { TODO -oRich V. -cOutpatient Meals : Need to DC Tubefeeding order for OP meals? }
        chkOPCancelTubefeeding.State := cbGrayed;
@@ -723,6 +863,23 @@
        pgeAdditional.TabVisible := False;
        pgeEarlyLate.TabVisible := False;
-       cboOPDietAvail.SelectByIEN(uDietParams.RegIEN);
+       cboOPDietAvail.SelectByIEN(uDietParams.OPDefaultDiet);
        cboOPDietAvailMouseClick(Self);
+       Changing := False;
+      end
+    else if uDialogName = 'FHW OP MEAL' then                          // Recurring meal
+      begin
+       AllowQuickOrder := True;
+       ResetControlsOP;
+       LoadDietQuickList(cboOPDietAvail.Items, 'MEAL');              // use D.G. short name here
+       cboOPDietAvail.InsertSeparator;
+       cboOPDietAvail.Items.AddStrings(SubsetOfOPDiets);
+       cboOPDietAvail.SelectByIEN(uDietParams.OPDefaultDiet);
+       { TODO -oRich V. -cOutpatient Meals : Need to DC Tubefeeding order for OP meals? }
+       chkOPCancelTubefeeding.State := cbGrayed;
+       chkOPCancelTubefeeding.Visible := False;
+       grpOPMeal.Caption := 'Recurring Meal';
+       SetEnableOPDOW(False, -1);
+       cboOPDietAvailMouseClick(Self);
+       Changing := False;
       end;
   end;
@@ -802,4 +959,5 @@
           InfoBox(Piece(ADiet,'^',2), TC_DIET_ERR, MB_OK);
           cboDietAvail.ItemIndex := -1;
+          Changing := False;
           Exit;
         end;
@@ -935,4 +1093,5 @@
   TFClearGrid;
   chkCancelTrays.Checked := False;
+  calOPTFStart.Text := '';
   txtTFComment.Text := '';
 end;
@@ -973,4 +1132,9 @@
     AResponse := FindResponseByName('CANCEL', 1);
     if AResponse <> nil then chkCancelTrays.Checked := AResponse.IValue = '1';
+    if not OrderForInpatient then
+    begin
+      SetControl(cboOPTFRecurringMeals, 'DATETIME', 1);
+      SetControl(calOPTFStart, 'DATETIME', 1);
+    end;
     SetControl(txtTFComment, 'COMMENT',  1);
   end;
@@ -1114,5 +1278,5 @@
     begin
       grdSelected.Cells[2, ARow] := Piece(x, U, 2);
-      grdSelected.Cells[3, ARow] := Piece(x, U, 1) + 'cc';
+      grdSelected.Cells[3, ARow] := Piece(x, U, 1) + 'ml';
     end
     else grdSelected.Cells[3, ARow] := '';
@@ -1268,4 +1432,9 @@
     then Responses.Update('CANCEL', 1, '1', 'Yes')
     else Responses.Update('CANCEL', 1, '0', 'No');
+  if not OrderForInpatient then
+  begin
+    calOPTFStart.FMDateTime := StrToFloatDef(cboOPTFRecurringMeals.ItemID, 0);
+    Responses.Update('DATETIME', 1, FloatToStr(calOPTFStart.FMDateTime), calOPTFStart.Text);
+  end;
   memOrder.Text := Responses.OrderText;
 end;
@@ -1323,6 +1492,11 @@
       if radLT3.Caption = AResponse.IValue then radLT3.Checked := True;
     end;
-    SetControl(calELStart, 'START', 1);
-    SetControl(calELStop,  'STOP',  1);
+    if not OrderForInpatient then
+      SetControl(cboOPELRecurringMeals, 'START', 1)
+    else
+    begin
+      SetControl(calELStart, 'START', 1);
+      SetControl(calELStop,  'STOP',  1);
+    end;
     calELStopChange(Self);
     AResponse := FindResponseByName('SCHEDULE', 1);
@@ -1403,13 +1577,46 @@
     lblNoTimes.Visible := not HasTimes;
   end;
-
-begin
-  inherited;
+var
+  AMeal: string;
+begin
+  inherited;
+  Changing := True;
   case grpMeal.ItemIndex of
-    0: SetMealTimes(uDietParams.BTimes);
-    1: SetMealTimes(uDietParams.NTimes);
-    2: SetMealTimes(uDietParams.ETimes);
-  else SetMealTimes('');
-  end;
+    0: begin
+         SetMealTimes(uDietParams.BTimes);
+         AMeal := 'B';
+       end;
+    1: begin
+         SetMealTimes(uDietParams.NTimes);
+         AMeal := 'N';
+       end;
+    2: begin
+         SetMealTimes(uDietParams.ETimes);
+         AMeal := 'E';
+       end;
+  else
+    begin
+      SetMealTimes('');
+      AMeal := '';
+    end;
+  end;
+  if not OrderForInpatient then
+    begin
+      if AMeal = '' then
+      begin
+        uRecurringMealList.Clear;
+        cboOPELRecurringMeals.Clear;
+      end
+      else if not PatientHasRecurringMeals(uRecurringMealList, AMeal) then
+        begin
+          uRecurringMealList.Clear;
+          cboOPELRecurringMeals.Clear;
+          grpMeal.ItemIndex := 3;
+        end
+      else
+        cboOPELRecurringMeals.Items.Assign(uRecurringMealList);
+    end;
+  Changing := False;
+  ELChange(grpMeal);
 end;
 
@@ -1445,5 +1652,6 @@
 begin
   inherited;
-  if (Length(calELStop.Text) > 0) and (calELStop.Text = calELStart.Text)
+  if not OrderForInpatient then SetEnableDOW(False)
+  else if (Length(calELStop.Text) > 0) and (calELStop.Text = calELStart.Text)
     then SetEnableDOW(False)
     else SetEnableDOW(True);
@@ -1478,4 +1686,9 @@
       then Responses.Update('ORDERABLE', 1, uDietParams.EarlyIEN, 'EARLY TRAY')
       else Responses.Update('ORDERABLE', 1, uDietParams.LateIEN,  'LATE TRAY');
+  end;
+  if not OrderForInpatient then
+  begin
+    calELStart.FMDateTime := StrToFloatDef(cboOPELRecurringMeals.ItemID, 0);
+    calELStop.FMDateTime := calELStart.FMDateTime;
   end;
   with calELStart   do if Length(Text) > 0 then Responses.Update('START',     1, Text,   Text);
@@ -1525,4 +1738,5 @@
 begin
   txtAOComment.Text := '';
+  calOPAOStart.Text := '';
 end;
 
@@ -1532,4 +1746,6 @@
   ResetControlsAO;
   Responses.SetControl(txtAOComment, 'COMMENT', 1);
+  //Responses.SetControl(calOPAOStart, 'DATETIME', 1);
+  Responses.SetControl(cboOPAORecurringMeals, 'DATETIME', 1);
   Changing := False;
   AOChange(Self);
@@ -1542,15 +1758,14 @@
   with txtAOComment do if Text <> ''
     then Responses.Update('COMMENT', 1, Text, Text);
+  if not OrderForInpatient then
+    begin
+      calOPAOStart.FMDateTime := StrToFloatDef(cboOPAORecurringMeals.ItemID, 0);
+      Responses.Update('DATETIME', 1, FloatToStr(calOPAOStart.FMDateTime), calOPAOStart.Text);
+    end;
   memOrder.Text := Responses.OrderText;
 end;
 
+
 { Outpatient Meals Order tab ----------------------------------------------------------------- }
-
-procedure TfrmODDiet.cboOPDietAvailNeedData(Sender: TObject; const StartFrom: string;
-  Direction, InsertAt: Integer);
-begin
-  inherited;
-  cboOPDietAvail.ForDataUse(SubsetOfOPDiets(StartFrom, Direction));
-end;
 
 procedure TfrmODDiet.cboOPDietAvailMouseClick(Sender: TObject);
@@ -1566,4 +1781,10 @@
 begin
   inherited;
+  if cboOPDietAvail.Items.Count = 0 then
+    begin
+      InfoBox(TX_NO_MEALS_DEFINED, TC_NO_MEALS_DEFINED, MB_OK or MB_ICONINFORMATION);
+      AbortOrder := True;
+      exit;
+    end  ;
   if CharAt(cboOPDietAvail.ItemID, 1) = 'Q' then              // setup quick order
   begin
@@ -1592,6 +1813,6 @@
     OPChange(Sender);
   end; {if cboOPDietAvail}
+  OPChange(Sender);
   cboOPDietAvail.ItemIndex := -1;
-  OPChange(Sender);
 end;
 
@@ -1643,5 +1864,4 @@
 procedure TfrmODDiet.SetValuesFromResponsesOP;
 var
-  //AnInstance: Integer;
   AResponse: TResponse;
   ADiet: string;
@@ -1651,22 +1871,4 @@
   with Responses do
   begin
-(*    AnInstance := NextInstance('ORDERABLE', 0);
-    while AnInstance > 0 do
-    begin
-      AResponse := FindResponseByName('ORDERABLE', AnInstance);
-      if AResponse <> nil then
-      begin
-        ADiet := DietAttributes(StrToIntDef(AResponse.IValue,0));
-        if Piece(ADiet,'^',1)='0' then
-        begin
-          InfoBox(Piece(ADiet,'^',2), TC_OP_DIET_ERR, MB_OK);
-          cboOPDietAvail.ItemIndex := -1;
-          Exit;
-        end;
-        lstOPDietSelect.Items.Add(ADiet);
-      end;
-      AnInstance := NextInstance('ORDERABLE', AnInstance);
-    end; {while AnInstance - ORDERABLE}*)
-
     AResponse := FindResponseByName('ORDERABLE', 1);
     if AResponse <> nil then
@@ -1677,4 +1879,5 @@
         InfoBox(Piece(ADiet,'^',2), TC_OP_DIET_ERR, MB_OK);
         cboOPDietAvail.ItemIndex := -1;
+        Changing := False;
         Exit;
       end;
@@ -1721,4 +1924,5 @@
 begin
   inherited;
+  if Changing then exit;
   if FChangeStop then
     calOPStop.Text := calOPStart.Text
@@ -1727,18 +1931,67 @@
 end;
 
+function TfrmODDiet.FMDOW(AnFMDate: TFMDateTime): integer;
+var
+  WinDate: TDateTime;
+  x: integer;
+begin
+  WinDate := FMDateTimeToDateTime(AnFMDate);
+  x := DayOfTheWeek(WinDate);
+  Result := x;
+end;
+
+function TfrmODDiet.FMDays(AStart, AEnd: TFMDateTime): string;
+var
+  AWinStart, AWinEnd: TDateTime;
+  i: double;
+  Days: string;
+begin
+  AWinStart := FMDateTimeToDateTime(AStart);
+  AWinEnd := FMDateTimeToDateTime(AEnd);
+  i := AWinStart;
+  repeat
+    Days := Days + FMDayLetters[DayOfTheWeek(i)];
+    i := i + 1;
+  until i > AWinEnd;
+  Result := Days;
+end;
+
 procedure TfrmODDiet.calOPStartExit(Sender: TObject);
-begin
-  inherited;
-  if (Length(calOPStop.Text) > 0) and (calOPStop.Text = calOPStart.Text)
-    then SetEnableOPDOW(False)
-    else SetEnableOPDOW(True);
+var
+  Days: string;
+begin
+  inherited;
+  if not (calOPStart.FMDateTime > 0) then
+  begin
+    SetEnableOPDOW(False, -1);
+    Exit ;
+  end;
+  if (Length(calOPStop.Text) > 0) and (calOPStop.Text = calOPStart.Text) then
+    SetEnableOPDOW(False, FMDOW(calOPStart.FMDateTime))
+  else
+  begin
+    Days := FMDays(calOPStart.FMDateTime, calOPStop.FMDateTime);
+    SetEnableOPDOW(True, -1, Days);
+  end;
 end;
 
 procedure TfrmODDiet.calOPStopChange(Sender: TObject);
-begin
-  inherited;
-  if (Length(calOPStop.Text) > 0) and (calOPStop.FMDateTime = calOPStart.FMDateTime)
-    then SetEnableOPDOW(False)
-    else SetEnableOPDOW(True);
+var
+  Days: string;
+begin
+  inherited;
+  if Changing then exit;
+  if not (calOPStop.FMDateTime > 0) then
+  begin
+    SetEnableOPDOW(False, -1);
+    Exit ;
+  end;
+  if (Length(calOPStop.Text) > 0) and (calOPStop.FMDateTime = calOPStart.FMDateTime) then
+    SetEnableOPDOW(False, FMDOW(calOPStart.FMDateTime))
+  else
+  begin
+    Days := FMDays(calOPStart.FMDateTime, calOPStop.FMDateTime);
+    SetEnableOPDOW(True, -1, Days);
+  end;
   OPChange(Sender);
 end;
@@ -1752,5 +2005,5 @@
   if Changing then Exit;
   if Sender <> Self then Responses.Clear;       // Sender=Self when called from SetupDialog
-  // Per NFS, only one selection allowed from any of 5 available OP diets
+  // Per NFS, only one selection allowed from any of 10-15 available OP diets
   with lstOPDietSelect do if Items.Count > 0 then
     Responses.Update('ORDERABLE', 1, Piece(Items[0], U, 1), Piece(Items[0], U, 2));
@@ -1765,5 +2018,6 @@
     begin
       x := GetOPDaysOfWeek;
-      if Length(x) > 0 then Responses.Update('SCHEDULE', 1, x, x);
+      if Length(x) = 0 then x := 'ONCE';
+      Responses.Update('SCHEDULE', 1, x, x);
     end;
   with txtOPDietComment do {if Length(Text) > 0 then} Responses.Update('COMMENT',   1, Text,   Text);
@@ -1784,14 +2038,25 @@
 end;
 
-procedure TfrmODDiet.SetEnableOPDOW(AllowUse: Boolean);
-begin
+procedure TfrmODDiet.SetEnableOPDOW(AllowUse: Boolean; OneTimeDay: integer; DaysToCheck: string = '');
+var
+  i: integer;
+begin
+  if (not AllowUse) and (OneTimeDay > -1) then
+    begin
+      for i := 0 to grpOPDOW.ControlCount - 1 do
+      begin
+        if grpOPDOW.Controls[i] is TCheckBox then
+          TCheckBox(grpOPDOW.Controls[i]).Checked := False;
+      end;
+      //TCheckBox(grpOPDOW.Controls[OneTimeDay - 1]).Checked := True;  CQ #8305
+    end;
   grpOPDOW.Enabled       := AllowUse;
-  chkOPMonday.Enabled    := AllowUse;
-  chkOPTuesday.Enabled   := AllowUse;
-  chkOPWednesday.Enabled := AllowUse;
-  chkOPThursday.Enabled  := AllowUse;
-  chkOPFriday.Enabled    := AllowUse;
-  chkOPSaturday.Enabled  := AllowUse;
-  chkOPSunday.Enabled    := AllowUse;
+  chkOPMonday.Enabled    := AllowUse and (Pos('M', DaysToCheck) > 0);
+  chkOPTuesday.Enabled   := AllowUse and (Pos('T', DaysToCheck) > 0);
+  chkOPWednesday.Enabled := AllowUse and (Pos('W', DaysToCheck) > 0);
+  chkOPThursday.Enabled  := AllowUse and (Pos('R', DaysToCheck) > 0);
+  chkOPFriday.Enabled    := AllowUse and (Pos('F', DaysToCheck) > 0);
+  chkOPSaturday.Enabled  := AllowUse and (Pos('S', DaysToCheck) > 0);
+  chkOPSunday.Enabled    := AllowUse and (Pos('X', DaysToCheck) > 0);
 end;
 
@@ -1896,5 +2161,5 @@
     // check if late tray should be ordered
     AResponse := Responses.FindResponseByName('ORDERABLE', 1);
-    if (AResponse <> nil) and (Copy(AResponse.EValue, 1, 3) <> 'NPO') then
+    if (Self.EvtID = 0) and (AResponse <> nil) and (Copy(AResponse.EValue, 1, 3) <> 'NPO') then
     begin
       AResponse := Responses.FindResponseByName('START', 1);
@@ -1915,5 +2180,5 @@
     // check if late tray should be ordered
     AResponse := Responses.FindResponseByName('ORDERABLE', 1);
-    if (AResponse <> nil) and (Copy(AResponse.EValue, 1, 3) <> 'NPO') then
+    if (Self.EvtID = 0) and (AResponse <> nil) and (Copy(AResponse.EValue, 1, 3) <> 'NPO') then
     begin
       AResponse := Responses.FindResponseByName('START', 1);
@@ -1930,7 +2195,14 @@
     if NewOrder.ID <> '' then
     begin
-      if (Encounter.Provider = User.DUZ) and User.CanSignOrders
-        then CanSign := CH_SIGN_YES
-        else CanSign := CH_SIGN_NA;
+      if OrderForInpatient then
+        begin
+          if (Encounter.Provider = User.DUZ) and User.CanSignOrders
+            then CanSign := CH_SIGN_YES
+            else CanSign := CH_SIGN_NA;
+        end
+      else
+        begin
+          CanSign := CH_SIGN_NA;
+        end;
       Changes.Add(CH_ORD, NewOrder.ID, NewOrder.Text, '', CanSign);
       SendMessage(Application.MainForm.Handle, UM_NEWORDER, ORDER_NEW, Integer(NewOrder))
@@ -1955,4 +2227,29 @@
 end;
 
+procedure TfrmODDiet.cboOPDietAvailKeyDown(Sender: TObject; var Key: Word;
+  Shift: TShiftState);
+begin
+  inherited;
+  if Key = VK_RETURN then cboOPDietAvailMouseClick(Self);
+end;
+
+function TfrmODDiet.PatientHasRecurringMeals(var MealList: TStringList; MealType: string = ''): boolean;
+const
+  TX_NO_RECURRING_MEALS = 'For outpatients, this type of order requires association with an existing recurring' + CRLF +
+                          'meal order.  There are currently no active recurring meal orders for this patient.' + CRLF + CRLF +
+                          'Those orders must be signed and released before they can be linked to this item.'; 
+  TC_NO_RECURRING_MEALS = 'Unable to order ' ;
+begin
+  MealList.Clear;
+  GetCurrentRecurringOPMeals(MealList, MealType);
+  if MealList.Count = 0 then
+    begin
+      InfoBox(TX_NO_RECURRING_MEALS, TC_NO_RECURRING_MEALS + nbkDiet.ActivePage.Caption, MB_OK);
+      Result := False;
+    end
+  else
+    Result := True;
+end;
+
 end.
 
