lp136764 Split Hours Of Operation
authorKyle Huckins <khuckins@catalyte.io>
Wed, 19 Jan 2022 03:41:30 +0000 (03:41 +0000)
committerTerran McCanna <tmccanna@georgialibraries.org>
Thu, 17 Mar 2022 18:29:07 +0000 (14:29 -0400)
- sql upgrade files
- Introduce optional secondary set of hours for aouhoo object
- Update Angular UI to cover split hours
- Display secondary hours on OPAC

Signed-off-by: Kyle Huckins <khuckins@catalyte.io>
Signed-off-by: Terran McCanna <tmccanna@georgialibraries.org>
Open-ILS/examples/fm_IDL.xml
Open-ILS/src/eg2/src/app/staff/admin/server/org-unit.component.html
Open-ILS/src/eg2/src/app/staff/admin/server/org-unit.component.ts
Open-ILS/src/perlmods/lib/OpenILS/Application/Storage/CDBI/actor.pm
Open-ILS/src/sql/Pg/005.schema.actors.sql
Open-ILS/src/sql/Pg/upgrade/XXXX-lp1396764-split-hours-of-operation.sql [new file with mode: 0644]
Open-ILS/src/templates-bootstrap/opac/parts/library/hours.tt2

index 1e379ed..eccb001 100644 (file)
@@ -3701,6 +3701,20 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
                        <field name="dow_5_open" />
                        <field name="dow_6_close" />
                        <field name="dow_6_open" />
+                       <field name="dow_0_close_2" />
+                       <field name="dow_0_open_2" />
+                       <field name="dow_1_close_2" />
+                       <field name="dow_1_open_2" />
+                       <field name="dow_2_close_2" />
+                       <field name="dow_2_open_2" />
+                       <field name="dow_3_close_2" />
+                       <field name="dow_3_open_2" />
+                       <field name="dow_4_close_2" />
+                       <field name="dow_4_open_2" />
+                       <field name="dow_5_close_2" />
+                       <field name="dow_5_open_2" />
+                       <field name="dow_6_close_2" />
+                       <field name="dow_6_open_2" />
                        <field name="id" reporter:datatype="id" />
                        <field name="org_unit" oils_persist:virtual="true" reporter:datatype="org_unit"/>
                </fields>
index 294d62c..f169fb4 100644 (file)
         [disabled]="currentOrg().isnew()">
         <ng-template ngbTabContent>
           <div class="mt-2 common-form striped-even">
-            <div class="row font-weight-bold mb-2">
-              <div class="col-lg-3 offset-lg-2" i18n>Open Time</div>
-              <div class="col-lg-3" i18n>Close Time</div>
+            <div class="row align-self-center font-weight-bold mb-2">
+              <div class="col-lg-2 offset-lg-1" i18n>
+                <div class="row justify-content-center">
+                  Split Hours?
+                </div>
+              </div>
+              <div class="col-lg-2" i18n>Open Time</div>
+              <div class="col-lg-2" i18n>Close Time</div>
+              <!--div class="col-lg-3 offset-lg-1" i18n>Note</div-->
             </div>
             <div class="row mb-2" *ngFor="let dow of [0,1,2,3,4,5,6]">
-              <div class="col-lg-2" [ngSwitch]="dow">
+              <div class="col-lg-1" [ngSwitch]="dow">
                 <span *ngSwitchCase="0" i18n>Monday</span>
                 <span *ngSwitchCase="1" i18n>Tuesday</span>
                 <span *ngSwitchCase="2" i18n>Wednesday</span>
                 <span *ngSwitchCase="5" i18n>Saturday</span>
                 <span *ngSwitchCase="6" i18n>Sunday</span>
               </div>
-              <div class="col-lg-3">
+              <div class="col-lg-2">
+                <div class="row justify-content-center">
+                <input type="checkbox" [(ngModel)]="dowArray[dow].isSplit"
+                [checked]="hasSplitHours(dow)" (ngModelChange)="clearSplitHours(dow, $event)"/>
+                </div>
+              </div>
+              <div class="col-lg-2">
                 <input class="form-control" type='time' step="60" 
-                  [ngModel]="hours(dow, 'open')" min="00:00:00" max="23:59:59"
-                  (ngModelChange)="hours(dow, 'open', $event)"/>
+                  [ngModel]="hours(dow, 'open', false)" min="00:00:00" max="23:59:59"
+                  (ngModelChange)="hours(dow, 'open', false, $event)"/>
               </div>
-              <div class="col-lg-3">
+              <div class="col-lg-2">
                 <input  class="form-control" type='time' step="60"
-                  [ngModel]="hours(dow, 'close')" min="00:00:00" max="23:59:59"
-                  (ngModelChange)="hours(dow, 'close', $event)"/>
+                  [ngModel]="hours(dow, 'close', false)" min="00:00:00" max="23:59:59"
+                  (ngModelChange)="hours(dow, 'close', false, $event)"/>
               </div>
-              <div class="col-lg-2">
+              <div class="col-lg-1 mr-2">
                 <button class="btn btn-outline-dark" (click)="closedOn(dow)" 
                   [disabled]="isClosed(dow)" i18n>Closed</button>
               </div>
+              <!--div class="col-lg-3">
+                <div class="input-group">
+                  <input  class="form-control" [ngModel]="addNote(dow)">
+                  <div class="input-group-append">
+                    <div class="input-group-text">
+                      <input type="checkbox" class="mr-2">Public?
+                    </div>
+                  </div>
+                </div>
+              </div-->
+              <div class="col-lg-2 offset-lg-3 mt-2" *ngIf="dowArray[dow].isSplit">
+                <input class="form-control" type='time' step="60"
+                  [ngModel]="hours(dow, 'open', true)" min="00:00:00" max="23:59:59"
+                  (ngModelChange)="hours(dow, 'open', true, $event)"/>
+              </div>
+              <div class="col-lg-2 mt-2" *ngIf="dowArray[dow].isSplit">
+                <input  class="form-control" type='time' step="60"
+                  [ngModel]="hours(dow, 'close', true)" min="00:00:00" max="23:59:59"
+                  (ngModelChange)="hours(dow, 'close', true, $event)"/>
+              </div>
             </div>
             <div class="row d-flex justify-content-end">
               <div class="alert alert-warning mr-2 p-1" 
index ff5a184..15c7b0b 100644 (file)
@@ -19,6 +19,7 @@ export class OrgUnitComponent implements OnInit {
 
     tree: Tree;
     selected: TreeNode;
+    dowArray: Array<Object>;
     @ViewChild('editString', { static: true }) editString: StringComponent;
     @ViewChild('errorString', { static: true }) errorString: StringComponent;
     @ViewChild('delConfirm', { static: true }) delConfirm: ConfirmDialogComponent;
@@ -34,8 +35,16 @@ export class OrgUnitComponent implements OnInit {
 
 
     ngOnInit() {
+        this.dowArray = [this.dowObj(0), this.dowObj(1), this.dowObj(2), this.dowObj(3), this.dowObj(4), this.dowObj(5), this.dowObj(6)]
         this.loadAouTree(this.org.root().id());
     }
+    
+    dowObj(dow) {
+        return {
+            id: dow,
+            isSplit: false
+        };
+    }
 
     tabChanged(evt: NgbTabChangeEvent) {
         const tab = evt.nextId;
@@ -121,9 +130,9 @@ export class OrgUnitComponent implements OnInit {
         hours.id(org.id());
         hours.isnew(true);
 
-        [0, 1, 2, 3, 4, 5, 6].forEach(dow => {
-            this.hours(dow, 'open', '09:00:00', hours);
-            this.hours(dow, 'close', '17:00:00', hours);
+        this.dowArray.forEach(dow => {
+            this.hours(dow['id'], 'open', false, '09:00:00', hours);
+            this.hours(dow['id'], 'close', false, '17:00:00', hours);
         });
 
         org.hours_of_operation(hours);
@@ -132,29 +141,61 @@ export class OrgUnitComponent implements OnInit {
     // if a 'value' is passed, it will be applied to the optional
     // hours-of-operation object, otherwise the hours on the currently
     // selected org unit.
-    hours(dow: number, which: 'open' | 'close', value?: string, hoo?: IdlObject): string {
+    hours(dow: number, which: 'open' | 'close', isSecondary: boolean, value?: string, hoo?: IdlObject): string {
         if (!hoo && !this.selected) { return null; }
 
         const hours = hoo || this.selected.callerData.orgUnit.hours_of_operation();
 
-        if (value) {
-            hours[`dow_${dow}_${which}`](value);
-            hours.ischanged(true);
+        if (isSecondary) {
+            if (value) {
+                hours[`dow_${dow}_${which}_2`](value);
+                hours.ischanged(true);
+            }
+            return hours[`dow_${dow}_${which}_2`]();
+        } else {
+            if (value) {
+                hours[`dow_${dow}_${which}`](value);
+                hours.ischanged(true);
+            }
+            return hours[`dow_${dow}_${which}`]();
         }
+    }
+    
+    addNote(dow: number, value?: string, hoo?: IdlObject): string {
+        if (!hoo && !this.selected) { return null; }
 
-        return hours[`dow_${dow}_${which}`]();
+        const hours = hoo || this.selected.callerData.orgUnit.hours_of_operation();
+        console.log(hours);
+        //if (hours.note()) return hours.note()[dow];
     }
 
     isClosed(dow: number): boolean {
         return (
-            this.hours(dow, 'open') === '00:00:00' &&
-            this.hours(dow, 'close') === '00:00:00'
+            this.hours(dow, 'open', false) === '00:00:00' &&
+            this.hours(dow, 'close', false) === '00:00:00'
         );
     }
 
     closedOn(dow: number) {
-        this.hours(dow, 'open', '00:00:00');
-        this.hours(dow, 'close', '00:00:00');
+        this.hours(dow, 'open', false, '00:00:00');
+        this.hours(dow, 'close', false, '00:00:00');
+    }
+    
+    hasSplitHours(dow: number) {
+        this.dowArray.forEach(dow => {
+            if (this.hours(dow['id'], 'open', true) !== '00:00:00') dow['isSplit'] = true;
+            if (this.hours(dow['id'], 'close', true) !== '00:00:00') dow['isSplit'] = true;
+        });
+    }
+    
+    clearSplitHours(dow: number, ticked: boolean) {
+        if (!ticked) {
+            this.hours(this.dowArray[dow]['id'], 'open', true, '00:00:00');
+            this.hours(this.dowArray[dow]['id'], 'close', true, '00:00:00');
+        } else {
+            this.hours(this.dowArray[dow]['id'], 'open', true, '00:00:00');
+            this.hours(this.dowArray[dow]['id'], 'close', true, '00:00:00');            
+        }
     }
 
     saveHours() {
index 6bf0481..1089355 100644 (file)
@@ -92,7 +92,9 @@ __PACKAGE__->table( 'actor_hours_of_operation' );
 __PACKAGE__->columns( Primary => qw/id/);
 __PACKAGE__->columns( Essential => qw/dow_0_open dow_0_close dow_1_open dow_1_close dow_2_open dow_2_close
                     dow_3_open dow_3_close dow_4_open dow_4_close dow_5_open dow_5_close
-                    dow_6_open dow_6_close/);
+                    dow_6_open dow_6_close dow_0_open_2 dow_0_close_2 dow_1_open_2 dow_1_close_2 dow_2_open_2 dow_2_close_2
+                    dow_3_open_2 dow_3_close_2 dow_4_open_2 dow_4_close_2 dow_5_open_2 dow_5_close_2
+                    dow_6_open_2 dow_6_close_2/);
 
 #-------------------------------------------------------------------------------
 package actor::org_unit::closed_date;
index 9a42e05..47c49f2 100644 (file)
@@ -465,7 +465,22 @@ CREATE TABLE actor.hours_of_operation (
        dow_5_open      TIME    NOT NULL DEFAULT '09:00',
        dow_5_close     TIME    NOT NULL DEFAULT '17:00',
        dow_6_open      TIME    NOT NULL DEFAULT '09:00',
-       dow_6_close     TIME    NOT NULL DEFAULT '17:00'
+       dow_6_close     TIME    NOT NULL DEFAULT '17:00',
+    dow_0_close_2 TIME  NOT NULL DEFAULT '00:00',
+    dow_0_open_2 TIME   NOT NULL DEFAULT '00:00',
+    dow_1_close_2 TIME  NOT NULL DEFAULT '00:00',
+    dow_1_open_2 TIME   NOT NULL DEFAULT '00:00',
+    dow_2_close_2 TIME  NOT NULL DEFAULT '00:00',
+    dow_2_open_2 TIME   NOT NULL DEFAULT '00:00',
+    dow_3_close_2 TIME  NOT NULL DEFAULT '00:00',
+    dow_3_open_2 TIME   NOT NULL DEFAULT '00:00',
+    dow_4_close_2 TIME  NOT NULL DEFAULT '00:00',
+    dow_4_open_2 TIME   NOT NULL DEFAULT '00:00',
+    dow_5_close_2 TIME  NOT NULL DEFAULT '00:00',
+    dow_5_open_2 TIME   NOT NULL DEFAULT '00:00',
+    dow_6_close_2 TIME  NOT NULL DEFAULT '00:00',
+    dow_6_open_2 TIME   NOT NULL DEFAULT '00:00'
+
 );
 COMMENT ON TABLE actor.hours_of_operation IS $$
 When does this org_unit usually open and close?  (Variations
diff --git a/Open-ILS/src/sql/Pg/upgrade/XXXX-lp1396764-split-hours-of-operation.sql b/Open-ILS/src/sql/Pg/upgrade/XXXX-lp1396764-split-hours-of-operation.sql
new file mode 100644 (file)
index 0000000..1327b9a
--- /dev/null
@@ -0,0 +1,21 @@
+BEGIN;
+
+SELECT evergreen.upgrade_deps_block_check('XXXX', :eg_version);
+
+ALTER TABLE actor.hours_of_operation
+    ADD COLUMN dow_0_close_2 TIME NOT NULL DEFAULT '00:00',
+    ADD COLUMN dow_0_open_2 TIME NOT NULL DEFAULT '00:00',
+    ADD COLUMN dow_1_close_2 TIME NOT NULL DEFAULT '00:00',
+    ADD COLUMN dow_1_open_2 TIME NOT NULL DEFAULT '00:00',
+    ADD COLUMN dow_2_close_2 TIME NOT NULL DEFAULT '00:00',
+    ADD COLUMN dow_2_open_2 TIME NOT NULL DEFAULT '00:00',
+    ADD COLUMN dow_3_close_2 TIME NOT NULL DEFAULT '00:00',
+    ADD COLUMN dow_3_open_2 TIME NOT NULL DEFAULT '00:00',
+    ADD COLUMN dow_4_close_2 TIME NOT NULL DEFAULT '00:00',
+    ADD COLUMN dow_4_open_2 TIME NOT NULL DEFAULT '00:00',
+    ADD COLUMN dow_5_close_2 TIME DEFAULT '00:00',
+    ADD COLUMN dow_5_open_2 TIME DEFAULT '00:00',
+    ADD COLUMN dow_6_close_2 TIME DEFAULT '00:00',
+    ADD COLUMN dow_6_open_2 TIME DEFAULT '00:00'
+
+COMMIT;
\ No newline at end of file
index 9ff96dd..2329859 100755 (executable)
 <div class="opening-hours" property="openingHoursSpecification" typeof="OpeningHoursSpecification"><link property="dayOfWeek" href="http://purl.org/goodrelations/v1#Monday" />[%
     l('Monday: [_1] - [_2]', '<time property="opens" content="' _ date.format(open, format => '%H:%M:%S') _ '">' _ date.format(open) _ '</time>',
      '<time property="closes" content="' _ date.format(close, format => '%H:%M:%S') _ '">' _ date.format(close) _ '</time>') -%]
+[%-
+    open_2 = today _ ctx.hours.dow_0_open_2;
+    close_2 = today _ ctx.hours.dow_0_close_2;
+    IF open_2 != close_2;
+%]
+[%
+    l('; [_1] - [_2]', '<time property="opens" content="' _ date.format(open_2, format => '%H:%M:%S') _ '">' _ date.format(open_2) _ '</time>',
+     '<time property="closes" content="' _ date.format(close_2, format => '%H:%M:%S') _ '">' _ date.format(close_2) _ '</time>') -%]
+[%- END %]
 </div>
+
+
 [%- END %]
 
 [%-
 <div class="opening-hours" property="openingHoursSpecification" typeof="OpeningHoursSpecification"><link property="dayOfWeek" href="http://purl.org/goodrelations/v1#Tuesday" />[%
     l('Tuesday: [_1] - [_2]', '<time property="opens" content="' _ date.format(open, format => '%H:%M:%S') _ '">' _ date.format(open) _ '</time>',
      '<time property="closes" content="' _ date.format(close, format => '%H:%M:%S') _ '">' _ date.format(close) _ '</time>') -%]
+
+
+[%-
+    open_2 = today _ ctx.hours.dow_1_open_2;
+    close_2 = today _ ctx.hours.dow_1_close_2;
+    IF open_2 != close_2;
+%]
+[%
+    l('; [_1] - [_2]', '<time property="opens" content="' _ date.format(open_2, format => '%H:%M:%S') _ '">' _ date.format(open_2) _ '</time>',
+     '<time property="closes" content="' _ date.format(close_2, format => '%H:%M:%S') _ '">' _ date.format(close_2) _ '</time>') -%]
+[%- END %]
 </div>
 [%- END %]
 
 <div class="opening-hours" property="openingHoursSpecification" typeof="OpeningHoursSpecification"><link property="dayOfWeek" href="http://purl.org/goodrelations/v1#Wednesday" />[%
     l('Wednesday: [_1] - [_2]', '<time property="opens" content="' _ date.format(open, format => '%H:%M:%S') _ '">' _ date.format(open) _ '</time>',
      '<time property="closes" content="' _ date.format(close, format => '%H:%M:%S') _ '">' _ date.format(close) _ '</time>') -%]
+[%-
+    open_2 = today _ ctx.hours.dow_2_open_2;
+    close_2 = today _ ctx.hours.dow_2_close_2;
+    IF open_2 != close_2;
+%]
+[%
+    l('; [_1] - [_2]', '<time property="opens" content="' _ date.format(open_2, format => '%H:%M:%S') _ '">' _ date.format(open_2) _ '</time>',
+     '<time property="closes" content="' _ date.format(close_2, format => '%H:%M:%S') _ '">' _ date.format(close_2) _ '</time>') -%]
+[%- END %]
 </div>
 [%- END %]
 
 <div class="opening-hours" property="openingHoursSpecification" typeof="OpeningHoursSpecification"><link property="dayOfWeek" href="http://purl.org/goodrelations/v1#Thursday" />[%
     l('Thursday: [_1] - [_2]', '<time property="opens" content="' _ date.format(open, format => '%H:%M:%S') _ '">' _ date.format(open) _ '</time>',
      '<time property="closes" content="' _ date.format(close, format => '%H:%M:%S') _ '">' _ date.format(close) _ '</time>') -%]
+[%-
+    open_2 = today _ ctx.hours.dow_3_open_2;
+    close_2 = today _ ctx.hours.dow_3_close_2;
+    IF open_2 != close_2;
+%]
+[%
+    l('; [_1] - [_2]', '<time property="opens" content="' _ date.format(open_2, format => '%H:%M:%S') _ '">' _ date.format(open_2) _ '</time>',
+     '<time property="closes" content="' _ date.format(close_2, format => '%H:%M:%S') _ '">' _ date.format(close_2) _ '</time>') -%]
+[%- END %]
 </div>
 [%- END %]
 
 <div class="opening-hours" property="openingHoursSpecification" typeof="OpeningHoursSpecification"><link property="dayOfWeek" href="http://purl.org/goodrelations/v1#Friday" />[%
     l('Friday: [_1] - [_2]', '<time property="opens" content="' _ date.format(open, format => '%H:%M:%S') _ '">' _ date.format(open) _ '</time>',
      '<time property="closes" content="' _ date.format(close, format => '%H:%M:%S') _ '">' _ date.format(close) _ '</time>') -%]
+[%-
+    open_2 = today _ ctx.hours.dow_4_open_2;
+    close_2 = today _ ctx.hours.dow_4_close_2;
+    IF open_2 != close_2;
+%]
+[%
+    l('; [_1] - [_2]', '<time property="opens" content="' _ date.format(open_2, format => '%H:%M:%S') _ '">' _ date.format(open_2) _ '</time>',
+     '<time property="closes" content="' _ date.format(close_2, format => '%H:%M:%S') _ '">' _ date.format(close_2) _ '</time>') -%]
+[%- END %]
 </div>
 [%- END %]
 
 <div class="opening-hours" property="openingHoursSpecification" typeof="OpeningHoursSpecification"><link property="dayOfWeek" href="http://purl.org/goodrelations/v1#Saturday" />[%
     l('Saturday: [_1] - [_2]', '<time property="opens" content="' _ date.format(open, format => '%H:%M:%S') _ '">' _ date.format(open) _ '</time>',
      '<time property="closes" content="' _ date.format(close, format => '%H:%M:%S') _ '">' _ date.format(close) _ '</time>') -%]
+[%-
+    open_2 = today _ ctx.hours.dow_5_open_2;
+    close_2 = today _ ctx.hours.dow_5_close_2;
+    IF open_2 != close_2;
+%]
+[%
+    l('; [_1] - [_2]', '<time property="opens" content="' _ date.format(open_2, format => '%H:%M:%S') _ '">' _ date.format(open_2) _ '</time>',
+     '<time property="closes" content="' _ date.format(close_2, format => '%H:%M:%S') _ '">' _ date.format(close_2) _ '</time>') -%]
+[%- END %]
 </div>
 [%- END %]
 
 <div class="opening-hours" property="openingHoursSpecification" typeof="OpeningHoursSpecification"><link property="dayOfWeek" href="http://purl.org/goodrelations/v1#Sunday" />[%
     l('Sunday: [_1] - [_2]', '<time property="opens" content="' _ date.format(open, format => '%H:%M:%S') _ '">' _ date.format(open) _ '</time>',
      '<time property="closes" content="' _ date.format(close, format => '%H:%M:%S') _ '">' _ date.format(close) _ '</time>') -%]
+
+[%-
+    open_2 = today _ ctx.hours.dow_6_open_2;
+    close_2 = today _ ctx.hours.dow_6_close_2;
+    IF open_2 != close_2;
+%]
+[%
+    l('; [_1] - [_2]', '<time property="opens" content="' _ date.format(open_2, format => '%H:%M:%S') _ '">' _ date.format(open_2) _ '</time>',
+     '<time property="closes" content="' _ date.format(close_2, format => '%H:%M:%S') _ '">' _ date.format(close_2) _ '</time>') -%]
+[%- END %]
 </div>
 [%- END %]
 </div>
\ No newline at end of file