├── .gitignore
├── README.md
├── css
├── rooms_date_range_fields.css
├── rooms_modal.css
├── rooms_options_widget.css
└── rooms_ui.css
├── images
├── bg-shade-light.png
└── close.png
├── includes
├── rooms.calendar.inc
├── rooms.calendar_interface.inc
├── rooms.event.inc
└── rooms.event_interface.inc
├── js
├── rooms_date_popup.js
└── rooms_fullcalendar_singlerowmonth.js
├── modules
├── rooms_availability
│ ├── css
│ │ ├── fullcalendar.theme.css
│ │ ├── rooms_availability.css
│ │ └── rooms_three_month_calendar.css
│ ├── includes
│ │ ├── rooms_availability.booking_event.inc
│ │ ├── rooms_availability.booking_event_interface.inc
│ │ ├── rooms_availability.unit_calendar.inc
│ │ └── rooms_availability.unit_calendar_interface.inc
│ ├── js
│ │ ├── rooms_availability.js
│ │ ├── rooms_availability_full_day.js
│ │ ├── rooms_color.js
│ │ ├── rooms_unit_management.js
│ │ └── rooms_unit_management_full_day.js
│ ├── rooms_availability.api.php
│ ├── rooms_availability.info
│ ├── rooms_availability.install
│ └── rooms_availability.module
├── rooms_availability_reference
│ ├── css
│ │ └── rooms_availability_reference_calendar.css
│ ├── js
│ │ ├── rooms_availability_reference.js
│ │ └── rooms_availability_reference_full_day.js
│ ├── rooms_availability_field_calendar.tpl.php
│ ├── rooms_availability_reference.info
│ ├── rooms_availability_reference.install
│ └── rooms_availability_reference.module
├── rooms_booking
│ ├── css
│ │ └── rooms_booking.css
│ ├── includes
│ │ ├── rooms_booking.availability_agent.inc
│ │ └── rooms_booking.availability_agent_filter.inc
│ ├── js
│ │ └── rooms_booking.js
│ ├── rooms_booking-extra-data.tpl.php
│ ├── rooms_booking.admin.inc
│ ├── rooms_booking.api.php
│ ├── rooms_booking.info
│ ├── rooms_booking.install
│ ├── rooms_booking.module
│ ├── rooms_booking.tpl.php
│ ├── rooms_booking_type.admin.inc
│ └── views
│ │ ├── rooms_booking.views.inc
│ │ ├── rooms_booking_handler_booking_operations_field.inc
│ │ ├── rooms_booking_handler_booking_type_field.inc
│ │ ├── rooms_booking_handler_date_field.inc
│ │ ├── rooms_booking_handler_date_filter.inc
│ │ ├── rooms_booking_handler_delete_link_field.inc
│ │ ├── rooms_booking_handler_edit_link_field.inc
│ │ ├── rooms_booking_handler_field_booking_status.inc
│ │ ├── rooms_booking_handler_filter_booking_status.inc
│ │ ├── rooms_booking_handler_link_field.inc
│ │ ├── rooms_booking_handler_nights_field.inc
│ │ ├── rooms_booking_handler_unit_field.inc
│ │ └── rooms_booking_handler_unit_filter.inc
├── rooms_booking_manager
│ ├── css
│ │ ├── rooms_booking_search.css
│ │ └── rooms_sticky_booking_legend.css
│ ├── includes
│ │ └── rooms_booking_manager.fields.inc
│ ├── js
│ │ ├── rooms_booking_manager_checked.js
│ │ └── rooms_sticky_booking_legend.js
│ ├── rooms_booking_email.tpl.php
│ ├── rooms_booking_enquiry_confirmation.tpl.php
│ ├── rooms_booking_manager.api.php
│ ├── rooms_booking_manager.availability_search.inc
│ ├── rooms_booking_manager.commerce.inc
│ ├── rooms_booking_manager.confirmation_override.inc
│ ├── rooms_booking_manager.info
│ ├── rooms_booking_manager.install
│ ├── rooms_booking_manager.module
│ ├── rooms_booking_manager.rules.inc
│ ├── rooms_booking_manager.rules_defaults.inc
│ ├── rooms_booking_manager.units_per_type_form.inc
│ ├── rooms_booking_manager.variable.inc
│ ├── rooms_booking_override_confirmation_page.tpl.php
│ ├── rooms_booking_results.tpl.php
│ └── views
│ │ └── rooms_booking_manager.views.inc
├── rooms_pricing
│ ├── css
│ │ └── rooms_pricing.css
│ ├── includes
│ │ ├── rooms_pricing.pricing_event.inc
│ │ ├── rooms_pricing.pricing_event_interface.inc
│ │ ├── rooms_pricing.unit_pricing_calendar.inc
│ │ └── rooms_pricing.unit_pricing_calendar_interface.inc
│ ├── js
│ │ ├── rooms_pricing.js
│ │ └── rooms_pricing_management.js
│ ├── modules
│ │ └── rooms_periodic_pricing
│ │ │ ├── css
│ │ │ └── rooms_periodic_pricing.css
│ │ │ ├── rooms_periodic_pricing.info
│ │ │ ├── rooms_periodic_pricing.install
│ │ │ └── rooms_periodic_pricing.module
│ ├── rooms_pricing.api.php
│ ├── rooms_pricing.info
│ ├── rooms_pricing.install
│ └── rooms_pricing.module
└── rooms_unit
│ ├── css
│ ├── rooms_unit.css
│ └── rooms_unit_type.css
│ ├── js
│ └── rooms_unit.js
│ ├── rooms_unit-extra-data.tpl.php
│ ├── rooms_unit.admin.inc
│ ├── rooms_unit.features.inc
│ ├── rooms_unit.info
│ ├── rooms_unit.install
│ ├── rooms_unit.migrate.inc
│ ├── rooms_unit.module
│ ├── rooms_unit.tpl.php
│ ├── rooms_unit_type.admin.inc
│ └── views
│ ├── rooms_unit.views.inc
│ ├── rooms_unit_handler_delete_link_field.inc
│ ├── rooms_unit_handler_edit_link_field.inc
│ ├── rooms_unit_handler_link_field.inc
│ ├── rooms_unit_handler_unit_operations_field.inc
│ └── rooms_unit_handler_unit_type_field.inc
├── rooms.api.php
├── rooms.info
├── rooms.install
├── rooms.make
├── rooms.module
├── rooms.variable.inc
├── rooms_three_month_calendar.tpl.php
├── rooms_ui.info
├── rooms_ui.module
├── test
├── composer.json
├── default.behat.yml
└── features
│ ├── availability.feature
│ ├── availability_constraints.feature
│ ├── availability_filter.feature
│ ├── availability_reference.feature
│ ├── booking.feature
│ ├── bootstrap
│ └── FeatureContext.php
│ ├── example.feature
│ ├── installation.feature
│ ├── package.feature
│ ├── pricing.feature
│ ├── unit.feature
│ └── unit_options.feature
└── translations
└── it.po
/.gitignore:
--------------------------------------------------------------------------------
1 | #ignore environment specific behat files
2 | test/behat.yml
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ROOMS 7.x-1.x
2 | -------------
3 | Rooms is a family of modules that allow you to manage bookings primarily for the accommodation industry it is suitable for hotels, B&Bs, vacation rentals and agencies that manage multiple properties.
4 |
5 | If you are looking to create a fully customized booking solution for scenarios such as the ones above from scratch install Rooms on a vanilla Drupal site with all its dependencies. You will be able to use standard Drupal techniques to customize further.
6 |
7 | We have updated documetation on Rooms 1.9 and over here:
8 | [General Documentation](http://docs.roomify.us)
9 |
10 |
11 | If instead you are looking to get a head start checkout out roomify.us for access to our open-source ready made solutions for:
12 |
13 | Vacation Rentals - [Casa](https://roomify.us/casa-vacation-rental-websites)
14 |
15 | Hotels and B&Bs - [Locanda](https://roomify.us/locanda-hotel-website)
16 |
17 | Multiple Properties - [Agency](https://roomify.us/roomify-agency-for-multiple-property-rentals)
18 |
--------------------------------------------------------------------------------
/css/rooms_date_range_fields.css:
--------------------------------------------------------------------------------
1 | /* Theming for rooms date range fields. */
2 |
3 | .rooms-date-range .start-date,
4 | .rooms-date-range .end-date {
5 | display: inline-block;
6 | clear: none;
7 | margin: 0;
8 | }
9 |
10 | .rooms-date-range .start-date {
11 | margin-right: 20px; /* LTR */
12 | }
13 |
14 |
15 | /* Start and end date fields */
16 | .js .rooms-date-range .description {
17 | display: none;
18 | }
19 | .rooms-date-range .form-text {
20 | width: 10em;
21 | }
22 | .rooms-date-range .form-item {
23 | margin-right: 0;
24 | }
25 | .rooms-date-range .container-inline-date > .form-item {
26 | margin-right: 0;
27 | display: block;
28 | }
29 | .rooms-date-range .container-inline-date .form-item .form-item {
30 | float: none;
31 | }
32 | .rooms-date-range .container-inline-date .form-item input {
33 | margin-right: 0;
34 | width: 10em;
35 | }
36 | .rooms-date-range .form-type-textfield label {
37 | display: none;
38 | }
39 | .rooms-date-range .date-padding,
40 | .rooms-date-range .container-inline-date .date-padding {
41 | padding: 0;
42 | float: none;
43 | }
44 |
--------------------------------------------------------------------------------
/css/rooms_modal.css:
--------------------------------------------------------------------------------
1 | /* When modals are enabled, add hover effect to calendar */
2 | .fc-event:hover {
3 | cursor: pointer;
4 | }
5 | .fc-widget-content:hover {
6 | cursor: default;
7 | background: rgba(230,230,230, 0.2);
8 | }
9 |
10 | /* Make modals responsive */
11 | .page-admin-rooms #modalContent,
12 | .page-admin-rooms #modalContent .ctools-modal-content,
13 | .page-admin-rooms #modalContent .ctools-modal-content .modal-content {
14 | max-width: 100% !important;
15 | }
16 |
17 | /* Account for the extra div coming from ctools_modal_form_render() */
18 | .page-admin-rooms .messages div.messages {
19 | background: none;
20 | border: none;
21 | margin: 0;
22 | padding: 0;
23 | -webkit-border-radius: 0;
24 | -moz-border-radius: 0;
25 | border-radius: 0;
26 | }
27 | .page-admin-rooms .ctools-modal-content {
28 | font-size: 12px;
29 | border: solid 1px #ddd;
30 | -webkit-border-radius: 0.5em;
31 | -moz-border-radius: 0.5em;
32 | border-radius: 0.5em;
33 | -webkit-box-shadow: -1em 1em 1em rgba(0, 0, 0, 0.5);
34 | -moz-box-shadow: -1em 1em 1em rgba(0, 0, 0, 0.5);
35 | box-shadow: -1em 1em 1em rgba(0, 0, 0, 0.5);
36 | background: #FFF;
37 | }
38 | .page-admin-rooms .ctools-modal-content .modal-header {
39 | background: #fff url('../images/bg-shade-light.png') repeat-x bottom left;
40 | color: #777;
41 | display: block;
42 | font-weight: 700;
43 | letter-spacing: normal;
44 | padding: 0.25em 1em;
45 | -webkit-border-radius: 0.5em 0.5em 0 0;
46 | -moz-border-radius: 0.5em 0.5em 0 0;
47 | border-radius: 0.5em 0.5em 0 0;
48 | }
49 | .page-admin-rooms .ctools-modal-content .modal-title {
50 | font-size: 120%;
51 | font-weight: bold;
52 | text-shadow: #fff 1px 1px 1px;
53 | color: #555;
54 | }
55 | .page-admin-rooms .ctools-modal-content .modal-content {
56 | width: 96% !important;
57 | padding: 15px 2%;
58 | -webkit-box-sizing: content-box;
59 | -moz-box-sizing: content-box;
60 | box-sizing: content-box;
61 | }
62 | .page-admin-rooms .ctools-modal-content a.close {
63 | color: #666;
64 | font-weight: normal;
65 | padding-left: 1.6em;
66 | background: url('../images/close.png') no-repeat 0 50%;
67 | }
68 | .page-admin-rooms .ctools-modal-content a.close img {
69 | display: none;
70 | }
71 | /** modal forms CSS **/
72 | .page-admin-rooms .ctools-modal-content .form-item label {
73 | width: 100%;
74 | float: none;
75 | clear: both;
76 | }
77 | .page-admin-rooms .ctools-modal-content .resizable-textarea {
78 | width: 100%;
79 | margin-left: 0;
80 | margin-right: 0;
81 | }
82 |
83 | /* Override rooms form layouts when they appear inside CTools modals */
84 | .page-admin-rooms .modal-content .rooms-management-form fieldset,
85 | .page-admin-rooms .modal-content .rooms-management-form .form-wrapper {
86 | float: none !important;
87 | width: 100% !important;
88 | max-width: 100% !important;
89 | margin-right: 0 !important;
90 | }
91 | .page-admin-rooms .modal-content .rooms-management-form .form-item label {
92 | float: none;
93 | width: auto;
94 | }
95 | .page-admin-rooms .modal-content .rooms-management-form .form-type-select,
96 | .page-admin-rooms .modal-content .rooms-management-form .form-item-operation,
97 | .page-admin-rooms .modal-content .rooms-management-form .form-item-amount,
98 | .page-admin-rooms .modal-content .rooms-management-form .form-actions {
99 | float: none;
100 | margin: 0;
101 | clear: both;
102 | }
103 | .page-admin-rooms .modal-content .rooms-management-form .rooms-date-range,
104 | .page-admin-rooms .modal-content .rooms-management-form .form-item-data-group-size,
105 | .page-admin-rooms .modal-content .rooms-management-form .rooms-booking-group-size-children-container {
106 | float: left !important;
107 | margin-right: 4% !important;
108 | width: 45% !important;
109 | max-width: 45% !important;
110 | min-width: 125px !important;
111 | clear: none;
112 | }
113 |
--------------------------------------------------------------------------------
/css/rooms_options_widget.css:
--------------------------------------------------------------------------------
1 | .field-widget-rooms-options-combined .field-multiple-table .form-item {
2 | float: left;
3 | margin-right: 20px;
4 | }
5 |
6 | .field-widget-rooms-options-combined .rooms-option--remove-button {
7 | clear: both;
8 | float: right;
9 | }
10 |
11 | .field-widget-rooms-options-combined .ajax-progress {
12 | float: right;
13 | margin: 5px 10px 0 0;
14 | }
15 |
--------------------------------------------------------------------------------
/css/rooms_ui.css:
--------------------------------------------------------------------------------
1 | /* Some Rooms admin pages use tables for layout, so let's kill this default. */
2 | tbody {
3 | border-top: none;
4 | }
5 |
6 | /* General styles for all Rooms management forms */
7 | .rooms-management-form:after {
8 | content: ".";
9 | display: block;
10 | height: 0;
11 | clear: both;
12 | visibility: hidden;
13 | }
14 |
15 | .rooms-management-form .form-item {
16 | padding: 0;
17 | margin-top: 0;
18 | margin-bottom: 0;
19 | }
20 | .rooms-management-form .form-item label {
21 | margin: 0;
22 | display: block;
23 | }
24 | .rooms-management-form .form-type-item label {
25 | display: inline;
26 | }
27 |
28 | .rooms-management-form .form-type-radio label,
29 | .rooms-management-form .form-type-checkbox label {
30 | display: inline;
31 | }
32 |
33 | .rooms-management-form .form-item-name .form-text {
34 | width: 100%;
35 | }
36 |
37 | .rooms-management-form .form-type-select,
38 | .rooms-management-form .form-item-operation,
39 | .rooms-management-form .form-item-amount,
40 | .rooms-management-form .rooms-date-range,
41 | .rooms-management-form .form-actions {
42 | float: left; /* LTR */
43 | margin: 0 20px 0 0; /* LTR */
44 | clear: none;
45 | }
46 |
47 | .rooms-management-form .form-actions {
48 | padding-top: 1.6em;
49 | }
50 |
51 | /* Fieldsets are floated by default, but if its collapsible, dont float it*/
52 | .rooms-management-form fieldset {
53 | padding: 0;
54 | margin: 0;
55 | border: none;
56 | float: left; /* LTR */
57 | width: auto;
58 | }
59 | .rooms-management-form fieldset.collapsible {
60 | float: none;
61 | clear: both;
62 | padding: 0;
63 | margin: 20px 0;
64 | }
65 | .rooms-management-form .fieldset-legend,
66 | .rooms-management-form .fieldset-wrapper {
67 | margin: 0;
68 | padding: 0;
69 | position: relative;
70 | text-transform: none;
71 | }
72 | .rooms-management-form .fieldset-description {
73 | padding: 15px 0;
74 | }
75 |
76 | /* Fix for floated fieldsets around vertical tabs */
77 | .rooms-management-form .vertical-tabs,
78 | .rooms-management-form .field-group-tab-wrapper {
79 | clear: both;
80 | }
81 |
82 | .rooms-month-manager .unit-name,
83 | .rooms-month-manager .unit-days {
84 | border-bottom: 1px solid #ccc !important;
85 | }
86 |
87 | /* Booking */
88 | .view-booking-cart-form table,
89 | .view-booking-checkout-form table,
90 | .commerce-checkout-form-review table {
91 | width: 100%;
92 | }
93 | .views-field-line-item-title,
94 | .views-field-line-item-label {
95 | width: 67%;
96 | }
97 | .page-bookings .views-field-commerce-total {
98 | text-align: right;
99 | padding-right: 1em;
100 | }
101 | .page-bookings .component-total {
102 | text-align: right;
103 | padding-right: 1em;
104 | }
105 | .page-bookings .views-field-commerce-unit-price,
106 | .page-bookings .component-title {
107 | padding-left: 1em;
108 | padding-right: 1em;
109 | }
110 | .commerce-line-item-actions {
111 | margin: 20px 1em 20px 0;
112 | }
113 |
--------------------------------------------------------------------------------
/images/bg-shade-light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Roomify/rooms/a51d50c2547b7d683af121917b144775c09c9723/images/bg-shade-light.png
--------------------------------------------------------------------------------
/images/close.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Roomify/rooms/a51d50c2547b7d683af121917b144775c09c9723/images/close.png
--------------------------------------------------------------------------------
/includes/rooms.calendar.inc:
--------------------------------------------------------------------------------
1 | monthDefined($event->startMonth(), $event->startYear())) {
41 | $partial_month_row = $this->preparePartialMonthArray($event);
42 | $update = db_update($this->base_table)
43 | ->condition('unit_id', $this->unit_id)
44 | ->condition('month', $event->startMonth())
45 | ->condition('year', $event->startYear())
46 | ->fields($partial_month_row)
47 | ->execute();
48 | }
49 | // Do an insert for a new month
50 | else {
51 | // Prepare the days array
52 | $days = $this->prepareFullMonthArray($event);
53 | $month_row = array(
54 | 'unit_id' => $this->unit_id,
55 | 'year' => $event->startYear(),
56 | 'month' => $event->startMonth(),
57 | );
58 | $month_row = array_merge($month_row, $days);
59 | $insert = db_insert($this->base_table)->fields($month_row);
60 | $insert->execute();
61 | }
62 | }
63 |
64 | /**
65 | * Given an event it prepares the entire month array for it
66 | * assuming no other events in the month and days where there
67 | * is no event get set to the default state.
68 | *
69 | * @param RoomsEventInterface $event
70 | * The event to process.
71 | *
72 | * @return array
73 | * The days of the month states processed array.
74 | */
75 | protected abstract function prepareFullMonthArray(RoomsEventInterface $event);
76 |
77 | /**
78 | * Given an event it prepares a partial array covering just the days
79 | * for which the event is involved
80 | *
81 | * @param RoomsEventInterface $event
82 | * The event to process.
83 | *
84 | * @return array
85 | * The days of the month states processed array.
86 | */
87 | protected abstract function preparePartialMonthArray(RoomsEventInterface $event);
88 |
89 | /**
90 | * {@inheritdoc}
91 | */
92 | public abstract function getEvents(DateTime $start_date, DateTime $end_date);
93 |
94 | /**
95 | * {@inheritdoc}
96 | */
97 | public abstract function getRawDayData(DateTime $start_date, DateTime $end_date);
98 |
99 | /**
100 | * {@inheritdoc}
101 | */
102 | public function monthDefined($month, $year) {
103 | $query = db_select($this->base_table, 'a');
104 | $query->addField('a', 'unit_id');
105 | $query->addField('a', 'year');
106 | $query->addField('a', 'month');
107 | $query->condition('a.unit_id', $this->unit_id);
108 | $query->condition('a.year', $year);
109 | $query->condition('a.month', $month);
110 | $result = $query->execute()->fetchAll(PDO::FETCH_ASSOC);
111 | if (count($result) > 0) {
112 | return TRUE;
113 | }
114 | return FALSE;
115 | }
116 |
117 | }
118 |
--------------------------------------------------------------------------------
/includes/rooms.calendar_interface.inc:
--------------------------------------------------------------------------------
1 | start_date->format($format);
30 | }
31 |
32 | /**
33 | * {@inheritdoc}
34 | */
35 | public function startMonth($format = 'n') {
36 | return $this->start_date->format($format);
37 | }
38 |
39 | /**
40 | * {@inheritdoc}
41 | */
42 | public function startYear($format = 'Y') {
43 | return $this->start_date->format($format);
44 | }
45 |
46 | /**
47 | * {@inheritdoc}
48 | */
49 | public function endDay($format = 'j') {
50 | return $this->end_date->format($format);
51 | }
52 |
53 | /**
54 | * {@inheritdoc}
55 | */
56 | public function endMonth($format = 'n') {
57 | return $this->end_date->format($format);
58 | }
59 |
60 | /**
61 | * {@inheritdoc}
62 | */
63 | public function endYear($format = 'Y') {
64 | return $this->end_date->format($format);
65 | }
66 |
67 | /**
68 | * {@inheritdoc}
69 | */
70 | public function diff() {
71 | $interval = $this->start_date->diff($this->end_date);
72 | return $interval;
73 | }
74 |
75 | /**
76 | * {@inheritdoc}
77 | */
78 | public function sameMonth() {
79 | if (($this->startMonth() == $this->endMonth()) && ($this->startYear() == $this->endYear())) {
80 | return TRUE;
81 | }
82 | return FALSE;
83 | }
84 |
85 | /**
86 | * {@inheritdoc}
87 | */
88 | public function sameYear() {
89 | if ($this->startYear() == $this->endYear()) {
90 | return TRUE;
91 | }
92 | return FALSE;
93 | }
94 |
95 | /**
96 | * {@inheritdoc}
97 | */
98 | public function transformToYearlyEvents() {
99 | // If same year return the event
100 | if ($this->sameYear()) {
101 | $sd = new DateTime();
102 | $sd->setDate($this->startYear(), $this->startMonth(), $this->startDay());
103 | $ed = new DateTime();
104 | $ed->setDate($this->endYear(), $this->endMonth(), $this->endDay());
105 | $be = $this->createEvent($sd, $ed);
106 | return array($be);
107 | }
108 |
109 | // Else split into years
110 | $events = array();
111 | for ($i = $this->startYear(); $i <= $this->endYear(); $i++) {
112 | $sd = new DateTime();
113 | $ed = new DateTime();
114 | if ($i == $this->startYear()) {
115 | $sd->setDate($i, $this->startMonth(), $this->startDay());
116 | $ed->setDate($i, 12, 31);
117 | $events[$i] = $this->createEvent($sd, $ed);
118 | }
119 | elseif ($i == $this->endYear()) {
120 | $sd->setDate($i, 1, 1);
121 | $ed->setDate($i, $this->endMonth(), $this->endDay());
122 | $events[$i] = $this->createEvent($sd, $ed);
123 | }
124 | else {
125 | $sd->setDate($i, 1, 1);
126 | $ed->setDate($i, 12, 31);
127 | $events[$i] = $this->createEvent($sd, $ed);
128 | }
129 | }
130 |
131 | return $events;
132 | }
133 |
134 | /**
135 | * {@inheritdoc}
136 | */
137 | public function transformToMonthlyEvents() {
138 | $events = array();
139 | //First we need to split into events in separate years
140 | if (!$this->sameYear()) {
141 | return FALSE;
142 | }
143 | if ($this->sameMonth()) {
144 | $sd = new DateTime();
145 | $sd->setDate($this->startYear(), $this->startMonth(), $this->startDay());
146 | $ed = new DateTime();
147 | $ed->setDate($this->endYear(), $this->endMonth(), $this->endDay());
148 | $be = $this->createEvent($sd, $ed);
149 | return array($be);
150 | }
151 | $months = rooms_end_of_month_dates($this->startYear());
152 |
153 | for ($i = $this->startMonth(); $i <= $this->endMonth(); $i++) {
154 | $sd = new DateTime();
155 | $ed = new DateTime();
156 | if ($i == $this->startMonth()) {
157 | $sd->setDate($this->startYear() , $i, $this->startDay());
158 | $ed->setDate($this->startYear(), $i, $months[$i]);
159 | $events[$i] = $this->createEvent($sd, $ed);
160 | }
161 | elseif ($i == $this->endMonth()) {
162 | $sd->setDate($this->startYear(), $i, 1);
163 | $ed->setDate($this->startYear(), $i, $this->endDay());
164 | $events[$i] = $this->createEvent($sd, $ed);
165 | }
166 | else{
167 | $sd->setDate($this->startYear(), $i, 1);
168 | $ed->setDate($this->startYear(), $i, $months[$i]);
169 | $events[$i] = $this->createEvent($sd, $ed);
170 | }
171 | }
172 | return $events;
173 | }
174 |
175 | /**
176 | * Creates a new event
177 | *
178 | * @param DateTime $start_date
179 | * The new event start date.
180 | * @param DateTime $end_date
181 | * The new event end date.
182 | *
183 | * @return RoomsEventInterface
184 | * The new event created.
185 | */
186 | protected abstract function createEvent(DateTime $start_date, DateTime $end_date);
187 |
188 | }
189 |
--------------------------------------------------------------------------------
/includes/rooms.event_interface.inc:
--------------------------------------------------------------------------------
1 | ').appendTo(dayGridContainerEl);
26 | this.el.find('.fc-body > tr > td').append(dayGridContainerEl);
27 |
28 | this.dayGrid.setElement(dayGridEl);
29 | this.dayGrid.renderDates(this.hasRigidRows());
30 | },
31 | });
32 |
33 | FC.views.singleRowMonth = singleRowMonth;
34 |
35 | })(jQuery);
36 |
--------------------------------------------------------------------------------
/modules/rooms_availability/css/fullcalendar.theme.css:
--------------------------------------------------------------------------------
1 | .fc table {
2 | margin: 0;
3 | }
4 | .fc td, .fc th {
5 | width: auto;
6 | }
7 |
8 | /* Header styles */
9 | .fc-header-title {
10 | text-align: center;
11 | }
12 | .fc-header-title h2 {
13 | font-size: 18px;
14 | font-weight: normal;
15 | margin: 0;
16 | }
17 | .fc-header {
18 | border: none;
19 | }
20 | .fc-header tbody,
21 | .fc-header tr,
22 | .fc-header th,
23 | .fc-header td {
24 | background-color: transparent;
25 | border: none !important;
26 | }
27 | .fc-header td {
28 | padding: 8px 0;
29 | }
30 | .fc-header .fc-state-default,
31 | .fc-header .ui-state-default {
32 | margin-bottom: 0;
33 | }
34 |
35 | /* Days of week */
36 | .fc-widget-header {
37 | font-weight: 100;
38 | font-size: 0.9em;
39 | color: #666;
40 | text-transform: none;
41 | background: transparent;
42 | }
43 |
44 | /* Table borders */
45 | .fc-border-separate {
46 | border: none;
47 | }
48 | .fc-border-separate th,
49 | .fc-border-separate th.fc-last {
50 | border-width: 0;
51 | }
52 | .fc-border-separate td.fc-last {
53 | border-width: 0 0 1px 1px;
54 | }
55 | .fc-border-separate tr.fc-last td {
56 | border-width: 0 0 0 1px;
57 | padding-bottom: 0;
58 | }
59 | .fc-border-separate td.fc-first {
60 | border-left: none;
61 | }
62 |
63 | /* Calendar content */
64 | .fc-widget-content {
65 | border-color: #f5f5f5;
66 | background: transparent;
67 | }
68 |
69 | /* Events */
70 | .fc-event,
71 | .fc-agenda .fc-event-time,
72 | .fc-event a {
73 | border-style: none;
74 | background-color: transparent;
75 | color: inherit;
76 | }
77 | .fc-event-default,
78 | .fc-event-default .fc-event-time,
79 | .fc-event-default a {
80 | border-color: #36c;
81 | border-style: solid;
82 | background-color: #36c;
83 | color: #fff;
84 | }
85 | .fc-event-skin {
86 | opacity: 0.8;
87 | }
88 | .fc-event-title {
89 | padding: 0 2px;
90 | display: block;
91 | }
92 |
93 | .fc-corner-left,
94 | .fc-corner-left .fc-event-inner {
95 | border-left-width: 0;
96 | }
97 | .fc-corner-right,
98 | .fc-corner-right .fc-event-inner {
99 | border-right-width: 0;
100 | }
101 | .fc-corner-left.fc-corner-right,
102 | .fc-corner-left.fc-corner-right .fc-event-inner {
103 | border-left-width: 0;
104 | border-right-width: 0;
105 | }
106 |
107 | /* Updated message */
108 | .fullcalendar-status {
109 | background: #ecf8f4;
110 | border: 1px solid #fff;
111 | color: #687;
112 | display: none;
113 | margin: 0 0 10px 0;
114 | padding: 15px;
115 | text-align: center;
116 | }
117 |
118 | /* Undo Drupal default theme link colors */
119 | .fc-content a:link,
120 | .fc-content a:visited {
121 | color: #fff;
122 | text-decoration: none;
123 | }
124 |
125 | /* Grid whitespace */
126 | .fc-grid .fc-day-number {
127 | text-align: right;
128 | padding: 1px 8% 0;
129 | cursor: default;
130 | }
131 | .fc-grid .fc-day-content {
132 | padding: 0 5% 0;
133 | }
134 |
135 | /* Visual separator between weeks in single-row-month */
136 | .fc-view-singleRowMonth th.fc-sun {
137 | border-left-width: 1px;
138 | }
139 | .fc-view-singleRowMonth th.fc-sun.fc-first {
140 | border-left-width: 0;
141 | }
142 |
143 | .fc-cell-overlay {
144 | background: rgb(0, 122, 255);
145 | opacity: .7;
146 | filter: alpha(opacity=70);
147 | }
148 |
149 | /* Hide plain text events when javascript is enabled */
150 | html.js .fullcalendar-content {
151 | display: none;
152 | }
153 |
--------------------------------------------------------------------------------
/modules/rooms_availability/css/rooms_availability.css:
--------------------------------------------------------------------------------
1 | /* Hide header on single-row month form display */
2 | .rooms-bulk-availability-form .fc-header {
3 | display: none;
4 | }
5 |
6 | /* Filter month form */
7 | .rooms-filter-month-form .form-item-month,
8 | .rooms-filter-month-form .form-item-year,
9 | .rooms-filter-month-form .form-item-type {
10 | float: left;
11 | margin-right: 20px;
12 | }
13 | .rooms-filter-month-form .form-item-month label,
14 | .rooms-filter-month-form .form-item-year label,
15 | .rooms-filter-month-form .form-item-type label {
16 | display: inline;
17 | margin-right: 4px;
18 | }
19 | .rooms-bulk-availability-form .fc-row:first-child .fc-content-skeleton table {
20 | margin-bottom: 0;
21 | }
22 |
23 | .fc-title {
24 | color: white;
25 | }
26 |
27 | .rooms-bulk-availability-form .fc-content-skeleton .fc-event-container a {
28 | border-radius: 0px;
29 | }
30 |
31 | .rooms-bulk-availability-form .fc-content-skeleton .fc-event-container .event-start {
32 | content: "";
33 | position: absolute;
34 | width: 0;
35 | height: 0;
36 | border-style: solid;
37 | border-color: transparent;
38 | border-bottom: 0;
39 | bottom: -8px;
40 | left: -1px;
41 | border-width: 7px;
42 | }
43 |
44 | .rooms-bulk-availability-form .fc-content-skeleton .fc-event-container .event-end {
45 | content: "";
46 | position: absolute;
47 | width: 0;
48 | height: 0;
49 | border-style: solid;
50 | border-color: transparent;
51 | border-bottom: 0;
52 | bottom: -10px;
53 | left: 0px;
54 | border-width: 7px;
55 | }
56 |
57 | .rooms-bulk-availability-form .fc-content-skeleton .fc-event-container .event-end {
58 | margin-bottom: 23px;
59 | transform: rotate(180deg);
60 | -ms-transform: rotate(180deg); /* IE 9 */
61 | -webkit-transform: rotate(180deg);
62 | }
63 | .rooms-month-manager .rooms-calendar-second-row-events {
64 | margin-top: -15px;
65 | }
66 |
67 | .page-admin-rooms-units{
68 | font: normal 81.3%/1.538em "Lucida Grande", "Lucida Sans Unicode", sans-serif;
69 | }
70 |
71 | /* Ensure that datepicker is visible in the modal popup. */
72 | #ui-datepicker-div {
73 | z-index: 1005 !important;
74 | }
75 |
--------------------------------------------------------------------------------
/modules/rooms_availability/css/rooms_three_month_calendar.css:
--------------------------------------------------------------------------------
1 | .rooms-three-month-calendar {
2 | margin-bottom: 20px;
3 | position: relative;
4 | overflow-x: hidden;
5 | }
6 | .rooms-three-month-calendar ::-moz-selection {
7 | color: inherit;
8 | background: inherit;
9 | }
10 | .rooms-three-month-calendar ::selection {
11 | color: inherit;
12 | background: inherit;
13 | }
14 | .rooms-three-month-calendar .ajax-progress {
15 | position: absolute;
16 | top: 0;
17 | right: 0;
18 | }
19 | .calendar-set,
20 | .calendar-navigation,
21 | .calendar-management-form {
22 | margin-bottom: 20px;
23 | }
24 | .rooms-three-month-calendar .month1,
25 | .rooms-three-month-calendar .month2,
26 | .rooms-three-month-calendar .month3 {
27 | float: left; /* LTR */
28 | width: 33%;
29 | padding: 0 15px;
30 | -webkit-box-sizing: border-box;
31 | -moz-box-sizing: border-box;
32 | box-sizing: border-box;
33 | }
34 | .rooms-three-month-calendar .month1 {
35 | padding-left: 0; /* LTR */
36 | }
37 | .rooms-three-month-calendar .month3 {
38 | padding-right: 0; /* LTR */
39 | }
40 | @media (max-width: 570px) {
41 | .rooms-three-month-calendar .month1,
42 | .rooms-three-month-calendar .month2,
43 | .rooms-three-month-calendar .month3 {
44 | width: 100%;
45 | padding: 0 0 15px;
46 | -webkit-box-sizing: border-box;
47 | -moz-box-sizing: border-box;
48 | box-sizing: border-box;
49 | }
50 | }
51 |
52 | .calendar-back,
53 | .calendar-current,
54 | .calendar-forward {
55 | float: left; /* LTR */
56 | width: 33%;
57 | -webkit-box-sizing: border-box;
58 | -moz-box-sizing: border-box;
59 | box-sizing: border-box;
60 | }
61 | .calendar-back {
62 | text-align: left; /* LTR */
63 | }
64 | .calendar-current {
65 | text-align: center;
66 | }
67 | .calendar-forward {
68 | text-align: right; /* LTR */
69 | }
70 |
71 | .page-admin-rooms-units{
72 | font: normal 81.3%/1.538em "Lucida Grande", "Lucida Sans Unicode", sans-serif;
73 | }
74 | .rooms-three-month-calendar .fc-content-skeleton .fc-event-container a {
75 | border-radius: 0px;
76 | }
77 |
78 | .rooms-three-month-calendar .fc-content-skeleton .fc-event-container .event-start {
79 | content: "";
80 | position: absolute;
81 | width: 0;
82 | height: 0;
83 | border-style: solid;
84 | border-color: transparent;
85 | border-bottom: 0;
86 | bottom: -8px;
87 | left: 0px;
88 | border-width: 8px;
89 | }
90 |
91 | .rooms-three-month-calendar .fc-content-skeleton .fc-event-container .event-end {
92 | content: "";
93 | position: absolute;
94 | width: 0;
95 | height: 0;
96 | border-style: solid;
97 | border-color: transparent;
98 | border-bottom: 0;
99 | bottom: -12px;
100 | left: 0px;
101 | border-width: 8px;
102 | }
103 |
104 | .rooms-three-month-calendar .fc-content-skeleton .fc-event-container .event-end {
105 | margin-bottom: 26px;
106 | transform: rotate(180deg);
107 | -ms-transform: rotate(180deg); /* IE 9 */
108 | -webkit-transform: rotate(180deg);
109 | }
110 |
111 | .rooms-three-month-calendar .rooms-calendar-second-row-events {
112 | margin-top: -15px;
113 | }
114 |
--------------------------------------------------------------------------------
/modules/rooms_availability/includes/rooms_availability.booking_event.inc:
--------------------------------------------------------------------------------
1 | unit_id = $unit_id;
31 | $this->id = $event_id;
32 | $this->start_date = $start_date;
33 | $this->end_date = $end_date;
34 | }
35 |
36 | /**
37 | * {@inheritdoc}
38 | */
39 | protected function createEvent(DateTime $start_date, DateTime $end_date) {
40 | return new BookingEvent($this->unit_id, $this->id, $start_date, $end_date);
41 | }
42 |
43 | /**
44 | * {@inheritdoc}
45 | */
46 | public function lock() {
47 | // Check that the event is not already locked.
48 | $query = db_select('rooms_booking_locks', 'l');
49 | $query->addField('l', 'unit_id');
50 | $query->addField('l', 'state');
51 | $query->addField('l', 'locked');
52 | $query->condition('l.unit_id', $this->unit_id);
53 | $query->condition('l.state', $this->id);
54 | $query->condition('l.locked', 1);
55 | $result = $query->execute()->fetchAll(PDO::FETCH_ASSOC);
56 |
57 | if (count($result) == 1) {
58 | return FALSE;
59 | }
60 | else {
61 | $fields = array(
62 | 'unit_id' => $this->unit_id,
63 | 'state' => $this->id,
64 | 'locked' => 1,
65 | );
66 | $lock = db_insert('rooms_booking_locks')->fields($fields);
67 | $lock->execute();
68 | }
69 | return TRUE;
70 | }
71 |
72 | /**
73 | * {@inheritdoc}
74 | */
75 | public function unlock() {
76 | db_delete('rooms_booking_locks')
77 | ->condition(db_or()->condition('state', $this->id)->condition('state', -($this->id)))
78 | ->execute();
79 | }
80 |
81 | /**
82 | * {@inheritdoc}
83 | */
84 | public function formatJson($style = ROOMS_AVAILABILITY_ADMIN_STYLE, $unit_name = '') {
85 | $event = array(
86 | 'id' => $this->id,
87 | 'start' => $this->startYear() . '-' . $this->startMonth('m') . '-' . $this->startDay('d') . 'T13:00:00',
88 | 'end' => $this->endYear() . '-' . $this->endMonth('m') . '-' . $this->endDay('d') . 'T13:00:00',
89 | 'title' => $this->id,
90 | );
91 |
92 | // Check if we are dealing with a booking.
93 | if ($this->id > 10 || $this->id < -10) {
94 | // Get the actual booking id.
95 | $booking_id = rooms_availability_return_id($this->id);
96 | $booking = rooms_booking_load($booking_id);
97 | if ($style == ROOMS_AVAILABILITY_ADMIN_STYLE) {
98 | $name = (isset($booking->name) && !empty($booking->name)) ? $booking->name : t('Booking') . ': ' . $booking->booking_id;
99 | $interval = $this->diff();
100 | if ((strlen($name) > 7) && ($interval->d < 1)) {
101 | $event['title'] = substr($name, 0, 6) . '...';
102 | }
103 | else {
104 | $event['title'] = $name;
105 | }
106 | }
107 | elseif ($style == ROOMS_AVAILABILITY_GENERIC_STYLE) {
108 | $this->id = ROOMS_NOT_AVAILABLE;
109 | $event['id'] = ROOMS_NOT_AVAILABLE;
110 | }
111 | }
112 |
113 | $view_unit_name = array_filter(variable_get('rooms_view_unit_name', array('')));
114 |
115 | // Set the color.
116 | switch ($this->id) {
117 | case ROOMS_NOT_AVAILABLE:
118 | $event['color'] = variable_get('rooms_not_available_color', '#CC2727');
119 | $event['borderColor'] = variable_get('rooms_not_available_color',
120 | '#CC2727');
121 | $event['title'] = variable_get('rooms_not_available_text', 'N/A');
122 | break;
123 |
124 | case ROOMS_AVAILABLE:
125 | $event['color'] = variable_get('rooms_available_color', '#8BA175');
126 | $event['borderColor'] = '#8BA175';
127 | $event['title'] = variable_get('rooms_available_text', 'AV');
128 | break;
129 |
130 | case ROOMS_ON_REQUEST:
131 | $event['color'] = variable_get('rooms_on_request_color', '#C5C5C5');
132 | $event['title'] = variable_get('rooms_on_request_text', 'ON-REQ');
133 | break;
134 |
135 | case ($this->id < 0):
136 | $event['color'] = variable_get('rooms_unconfirmed_booking_color', '#6D8C9C');
137 | $event['title'] = variable_get('rooms_unconfirmed_booking_text', 'UNCONF');
138 | break;
139 |
140 | case ROOMS_ANON_BOOKED:
141 | if ($style == ROOMS_AVAILABILITY_ADMIN_STYLE) {
142 | $event['color'] = variable_get('rooms_anon_booking_color', '#8C6A5A');
143 | $event['title'] = variable_get('rooms_anon_booking_text', 'A-B');
144 | }
145 | elseif ($style == ROOMS_AVAILABILITY_GENERIC_STYLE) {
146 | $event['color'] = variable_get('rooms_not_available_color',
147 | '#910a1c');
148 | $event['title'] = variable_get('rooms_not_available_text', 'N/A');
149 | }
150 | break;
151 |
152 | default:
153 | $event['color'] = '#017eba';
154 | break;
155 | }
156 |
157 | if (!empty($view_unit_name)) {
158 | $event['title'] = $unit_name;
159 | }
160 |
161 | return $event;
162 | }
163 |
164 | }
165 |
--------------------------------------------------------------------------------
/modules/rooms_availability/includes/rooms_availability.booking_event_interface.inc:
--------------------------------------------------------------------------------
1 | id] == ROOMS_UPDATED) {
26 | $unit_affected = rooms_unit_load($event->unit_id);
27 | }
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/modules/rooms_availability/rooms_availability.info:
--------------------------------------------------------------------------------
1 | name = Rooms Availability
2 | description = Manages availability for Rooms.
3 | core = 7.x
4 |
5 | package = Rooms
6 |
7 | files[] = includes/rooms_availability.booking_event.inc
8 | files[] = includes/rooms_availability.booking_event_interface.inc
9 | files[] = includes/rooms_availability.unit_calendar.inc
10 | files[] = includes/rooms_availability.unit_calendar_interface.inc
11 |
12 |
13 | dependencies[] = rooms_unit
14 | dependencies[] = rooms
15 | dependencies[] = rooms_ui
16 | dependencies[] = date
17 | dependencies[] = date_api
18 | dependencies[] = date_popup
19 | dependencies[] = ctools
20 | dependencies[] = bat_api
21 |
--------------------------------------------------------------------------------
/modules/rooms_availability_reference/css/rooms_availability_reference_calendar.css:
--------------------------------------------------------------------------------
1 |
2 | .rooms-availability-field-calendar .fc-content-skeleton .fc-event-container a {
3 | border-radius: 0px;
4 | }
5 |
6 | .rooms-availability-field-calendar .fc-content-skeleton .fc-event-container .event-start {
7 | content: "";
8 | position: absolute;
9 | width: 0;
10 | height: 0;
11 | border-style: solid;
12 | border-color: transparent;
13 | border-bottom: 0;
14 | bottom: -8px;
15 | left: 0px;
16 | border-width: 8px;
17 | }
18 |
19 | .rooms-availability-field-calendar .fc-content-skeleton .fc-event-container .event-end {
20 | content: "";
21 | position: absolute;
22 | width: 0;
23 | height: 0;
24 | border-style: solid;
25 | border-color: transparent;
26 | border-bottom: 0;
27 | bottom: -11px;
28 | left: 0px;
29 | border-width: 8px;
30 | }
31 |
32 | .rooms-availability-field-calendar .fc-content-skeleton .fc-event-container .event-end {
33 | margin-bottom: 26px;
34 | transform: rotate(180deg);
35 | -ms-transform: rotate(180deg); /* IE 9 */
36 | -webkit-transform: rotate(180deg);
37 | }
38 |
39 | .rooms-availability-field-calendar .fc-event .fc-title {
40 | color:white;
41 | }
42 |
43 | .rooms-availability-field-calendar .fc-event .fc-title:hover {
44 | color:white;
45 | }
46 |
47 | .rooms-availability-field-calendar .fc-unthemed .fc-popover,
48 | .rooms-availability-field-calendar .fc-unthemed .fc-row,
49 | .rooms-availability-field-calendar .fc-unthemed hr,
50 | .rooms-availability-field-calendar .fc-unthemed tbody,
51 | .rooms-availability-field-calendar .fc-unthemed td, .fc-unthemed th,
52 | .rooms-availability-field-calendar .fc-unthemed thead {
53 | border-color:white;
54 | }
55 |
56 | .rooms-availability-field-calendar .fc-event-container {
57 | padding-top: 2px;
58 | padding-bottom: 4px;
59 | }
--------------------------------------------------------------------------------
/modules/rooms_availability_reference/js/rooms_availability_reference.js:
--------------------------------------------------------------------------------
1 | (function ($) {
2 |
3 |
4 | Drupal.behaviors.rooms_availability_reference = {
5 | attach: function(context) {
6 | var today = moment();
7 |
8 | $('.cal').once('cal', function() {
9 | var lastSource;
10 | var cal_id = $(this).siblings('.availability-title').attr('id');
11 |
12 | $(this).fullCalendar({
13 | editable: false,
14 | displayEventTime: false,
15 | dayNamesShort:[Drupal.t("Sun"), Drupal.t("Mon"), Drupal.t("Tue"), Drupal.t("Wed"), Drupal.t("Thu"), Drupal.t("Fri"), Drupal.t("Sat")],
16 | monthNames:[Drupal.t("January"), Drupal.t("February"), Drupal.t("March"), Drupal.t("April"), Drupal.t("May"), Drupal.t("June"), Drupal.t("July"), Drupal.t("August"), Drupal.t("September"), Drupal.t("October"), Drupal.t("November"), Drupal.t("December")],
17 | defaultDate: today,
18 | firstDay: Drupal.settings.roomsAvailabilityRef[cal_id].firstDay,
19 | header:{
20 | left: 'today',
21 | center: 'title',
22 | right: 'prev, next'
23 | },
24 | viewRender: function(view, element) {
25 | if (view.name == 'month') {
26 | view.calendar.removeEvents();
27 |
28 | var url = '?q=bat/v1/availability&units=' + Drupal.settings.roomsAvailabilityRef[cal_id].unitID.join() + '&start_date=' + view.intervalStart.get('year') + '-' + (view.intervalStart.get('month') + 1) + '-01&duration=1M';
29 | $.ajax({
30 | url: url,
31 | success: function(data) {
32 | events = data['events'];
33 |
34 | for (var index = 0; index < Drupal.settings.roomsAvailabilityRef[cal_id].unitID.length; index++) {
35 | events_array = events[Drupal.settings.roomsAvailabilityRef[cal_id].unitID[index]];
36 |
37 | for (i in events_array) {
38 | events_array[i].end = moment(events_array[i].end).subtract(1, 'days').format();
39 | }
40 | view.calendar.addEventSource(events_array);
41 | }
42 | }
43 | });
44 | }
45 | },
46 | eventRender: function(event, el, view) {
47 | // Add a class if the event start it is not "AV" or "N/A".
48 | if (el.hasClass('fc-start') && this.id != 1 && this.id != 0) {
49 | el.append('
');
50 | el.find('.event-start').css('border-top-color', this.color);
51 | }
52 |
53 | // Add a class if the event end and it is not "AV" or "N/A".
54 | if (el.hasClass('fc-end') && this.id != 1 && this.id != 0) {
55 | el.append('');
56 | el.find('.event-end').css('border-top-color', this.color);
57 | }
58 | },
59 | eventAfterRender: function(event, element, view) {
60 | // Hide events that are outside this month.
61 | if (event.start.month() != view.intervalStart.month()) {
62 | element.css('visibility', 'hidden');
63 | return;
64 | }
65 |
66 | // Event width.
67 | var width = element.parent().width()
68 | // Event colspan number.
69 | var colspan = element.parent().get(0).colSpan;
70 | // Single cell width.
71 | var cell_width = width/colspan;
72 | var half_cell_width = cell_width/2;
73 |
74 | // Move events between table margins.
75 | element.css('margin-left', half_cell_width);
76 | element.css('margin-right', -(half_cell_width));
77 |
78 | // Calculate width event to add end date triangle.
79 | width_event = element.children('.fc-content').width();
80 |
81 | // Add a margin left to the top triangle.
82 | element.children().closest('.event-end').css('margin-left', width_event-14);
83 |
84 | if (element.parent().index() == 0) {
85 | if (element.hasClass('fc-start')) {
86 | var row_index = element.closest('.fc-row').index('.fc-row');
87 | if (row_index >= 2) {
88 | var event_color = $(view.dayGrid.rowEls[row_index - 2]).find('.fc-day-grid-event').last().css('background-color');
89 | var event_text = $(view.dayGrid.rowEls[row_index - 2]).find('.fc-day-grid-event').last().find('.fc-title').text();
90 |
91 | var new_event = $('' + event_text + '
');
92 | element.parent().append(new_event);
93 |
94 | var event_end = $(view.dayGrid.rowEls[row_index - 2]).find('.fc-day-grid-event').last().find('.event-end').prop('outerHTML');
95 | if (event_end != undefined) {
96 | $(view.dayGrid.rowEls[row_index - 2]).find('.fc-day-grid-event').last().find('.event-end').remove();
97 |
98 | new_event.append(event_end);
99 | new_event.find('.event-end').css('margin-left', half_cell_width - 16);
100 | }
101 | }
102 | }
103 | }
104 |
105 | if (element.parent().index() == element.parent().parent().children('td').length - 1) {
106 | element.css('margin-right', 0);
107 | }
108 |
109 | // If the event end in a next row.
110 | if (element.hasClass('fc-not-end')) {
111 | element.css('margin-right', 0);
112 | }
113 | // If the event start in a previous row.
114 | if (element.hasClass('fc-not-start')) {
115 | element.css('margin-left', 0);
116 | element.children().closest('.event-end').css('margin-left', (colspan * cell_width) + half_cell_width - 14);
117 | }
118 | }
119 | });
120 |
121 | });
122 |
123 |
124 | // Resize takes care of some quirks on occasion
125 | $(window).resize();
126 |
127 | }
128 | };
129 | })(jQuery);
130 |
--------------------------------------------------------------------------------
/modules/rooms_availability_reference/js/rooms_availability_reference_full_day.js:
--------------------------------------------------------------------------------
1 | (function ($) {
2 |
3 | Drupal.behaviors.rooms_availability_reference = {
4 | attach: function(context) {
5 | var today = moment();
6 |
7 | $('.cal').once('cal', function() {
8 | var lastSource;
9 | var cal_id = $(this).siblings('.availability-title').attr('id');
10 |
11 | $(this).fullCalendar({
12 | editable: false,
13 | displayEventTime: false,
14 | dayNamesShort:[Drupal.t("Sun"), Drupal.t("Mon"), Drupal.t("Tue"), Drupal.t("Wed"), Drupal.t("Thu"), Drupal.t("Fri"), Drupal.t("Sat")],
15 | monthNames:[Drupal.t("January"), Drupal.t("February"), Drupal.t("March"), Drupal.t("April"), Drupal.t("May"), Drupal.t("June"), Drupal.t("July"), Drupal.t("August"), Drupal.t("September"), Drupal.t("October"), Drupal.t("November"), Drupal.t("December")],
16 | defaultDate: today,
17 | firstDay: Drupal.settings.roomsAvailabilityRef[cal_id].firstDay,
18 | header:{
19 | left: 'today',
20 | center: 'title',
21 | right: 'prev, next'
22 | },
23 | viewRender: function(view, element) {
24 | if (view.name == 'month') {
25 | view.calendar.removeEvents();
26 |
27 | var url = '?q=bat/v1/availability&units=' + Drupal.settings.roomsAvailabilityRef[cal_id].unitID.join() + '&start_date=' + view.intervalStart.get('year') + '-' + (view.intervalStart.get('month') + 1) + '-01&duration=1M';
28 | $.ajax({
29 | url: url,
30 | success: function(data) {
31 | events = data['events'];
32 |
33 | for (var index = 0; index < Drupal.settings.roomsAvailabilityRef[cal_id].unitID.length; index++) {
34 | events_array = events[Drupal.settings.roomsAvailabilityRef[cal_id].unitID[index]];
35 |
36 | view.calendar.addEventSource(events_array);
37 | }
38 | }
39 | });
40 | }
41 | },
42 | eventAfterRender: function(event, element, view) {
43 | // Hide events that are outside this month.
44 | if (event.start.month() != view.intervalStart.month()) {
45 | element.css('visibility', 'hidden');
46 | return;
47 | }
48 | }
49 | });
50 |
51 | });
52 |
53 |
54 | // Resize takes care of some quirks on occasion
55 | $(window).resize();
56 |
57 | }
58 | };
59 | })(jQuery);
60 |
--------------------------------------------------------------------------------
/modules/rooms_availability_reference/rooms_availability_field_calendar.tpl.php:
--------------------------------------------------------------------------------
1 |
8 |
--------------------------------------------------------------------------------
/modules/rooms_availability_reference/rooms_availability_reference.info:
--------------------------------------------------------------------------------
1 | name = Rooms Availability Reference
2 | description = Provides a field to reference and display availability information on any fieldable entity.
3 | core = 7.x
4 |
5 | package = Rooms
6 |
7 | dependencies[] = rooms_availability
8 |
--------------------------------------------------------------------------------
/modules/rooms_availability_reference/rooms_availability_reference.install:
--------------------------------------------------------------------------------
1 | array(
15 | 'type' => 'int',
16 | 'unsigned' => TRUE,
17 | 'not null' => FALSE,
18 | ),
19 | );
20 | return array(
21 | 'columns' => $columns,
22 | 'indexes' => array('unit_id' => array('unit_id')),
23 | 'foreign keys' => array(
24 | 'unit_id' => array(
25 | 'table' => 'rooms_units',
26 | 'columns' => array('unit_id' => 'unit_id'),
27 | ),
28 | ),
29 | );
30 | }
31 |
--------------------------------------------------------------------------------
/modules/rooms_booking/css/rooms_booking.css:
--------------------------------------------------------------------------------
1 | /* Booking edit form */
2 | .rooms-booking-form .form-actions,
3 | .rooms-booking-form .rooms-booking-status-wrapper {
4 | float: none;
5 | clear: both;
6 | }
7 | .rooms-booking-form .rooms-booking-status-wrapper,
8 | .rooms-booking-form .rooms-booking-availability-wrapper,
9 | .rooms-booking-form .rooms-booking-unit-type-wrapper,
10 | .rooms-booking-form .rooms-booking-order-wrapper {
11 | margin-bottom: 15px;
12 | }
13 | .rooms-booking-form .rooms-booking-customer-wrapper,
14 | .rooms-booking-form .rooms-booking-data-wrapper {
15 | float: left;
16 | max-width: 400px;
17 | margin-right: 20px;
18 | }
19 | .rooms-booking-form .rooms-booking-customer-wrapper .form-item-client .form-text {
20 | width: 62%;
21 | min-width: 250px;
22 | }
23 | .rooms-booking-form .rooms-booking-customer-wrapper .form-item-client .field-suffix {
24 | width: 30%;
25 | display: block;
26 | }
27 | .rooms-booking-form .rooms-booking-date-range-wrapper {
28 | clear: both;
29 | padding: 0;
30 | margin: 0 0 1em;
31 | }
32 | .rooms-booking-form .rooms-booking-availability-button-wrapper {
33 | clear: both;
34 | }
35 | .rooms-booking-form .rooms-booking-availability-wrapper fieldset {
36 | background: none;
37 | float: none;
38 | clear: both;
39 | margin-bottom: 0;
40 | }
41 | .rooms-booking-form .rooms-booking-availability-wrapper .fieldset-description {
42 | padding: 0;
43 | }
44 | .rooms-booking-form .form-item-data-group-size,
45 | .rooms-booking-form .rooms-booking-group-size-children-container {
46 | float: left;
47 | margin-right: 20px;
48 | max-width: 175px;
49 | }
50 | .rooms-booking-form .form-item-data-group-size,
51 | .rooms-booking-form .form-item-data-group-size-children {
52 | padding: 0;
53 | }
54 | .rooms-booking-form .rooms-booking-options-wrapper .form-wrapper {
55 | margin: 0;
56 | }
57 | .rooms-booking-form .rooms-booking-options-wrapper .form-type-select {
58 | float: none;
59 | }
60 | .rooms-booking-form .rooms-booking-options-wrapper .form-type-select label {
61 | display: inline;
62 | font-weight: normal;
63 | }
64 | .rooms-booking-form .rooms-booking-availability-wrapper .form-item-unit-type {
65 | float: none;
66 | margin-bottom: 15px;
67 | }
68 |
69 | /* Children discount form */
70 | .children-discount-form .child-discount {
71 | clear: both;
72 | float: none;
73 | }
74 | .children-discount-form .child-discount__age-start,
75 | .children-discount-form .child-discount__age-end {
76 | width: 2em;
77 | text-align: right;
78 | }
79 | .children-discount-form .child-discount__amount {
80 | width: 3em;
81 | text-align: right;
82 | }
83 |
--------------------------------------------------------------------------------
/modules/rooms_booking/js/rooms_booking.js:
--------------------------------------------------------------------------------
1 |
2 | (function ($) {
3 |
4 | Drupal.behaviors.bookingFieldsetSummaries = {
5 | attach: function (context) {
6 | $('fieldset#edit-user', context).drupalSetSummary(function (context) {
7 | var name = $('#edit-owner-name').val() || Drupal.settings.anonymous;
8 | return Drupal.t('Owned by @name', { '@name': name });
9 | });
10 |
11 | $('fieldset#edit-booking-history', context).drupalSetSummary(function (context) {
12 | var summary = $('#edit-created', context).val() ?
13 | Drupal.t('Created @date', { '@date' : $('#edit-created').val() }) :
14 | Drupal.t('New order');
15 |
16 | // Add the changed date to the summary if it's different from the created.
17 | if ($('#edit-created', context).val() != $('#edit-changed', context).val()) {
18 | summary += '
' + Drupal.t('Updated @date', { '@date' : $('#edit-changed').val() });
19 | }
20 |
21 | return summary;
22 | });
23 | }
24 | };
25 |
26 | })(jQuery);
27 |
--------------------------------------------------------------------------------
/modules/rooms_booking/rooms_booking-extra-data.tpl.php:
--------------------------------------------------------------------------------
1 |
14 |
15 |
16 | Unit Sample Data: ' . $rooms_unit_sample_data = ($rooms_unit_sample_data) ? 'Switch On' : 'Switch Off' ?>
17 |
18 |
--------------------------------------------------------------------------------
/modules/rooms_booking/rooms_booking.api.php:
--------------------------------------------------------------------------------
1 | ROOMS_DYNAMIC_MODIFIER,
32 | '#quantity' => 1,
33 | '#op_type' => ROOMS_SUB,
34 | '#amount' => 10
35 | );
36 | }
37 |
--------------------------------------------------------------------------------
/modules/rooms_booking/rooms_booking.info:
--------------------------------------------------------------------------------
1 | name = Rooms Booking
2 | description = Create and administer bookings for Rooms.
3 | core = 7.x
4 |
5 | package = Rooms
6 |
7 | dependencies[] = rooms_unit
8 | dependencies[] = rooms_availability
9 | dependencies[] = rooms_pricing
10 | dependencies[] = views
11 | dependencies[] = commerce
12 | dependencies[] = commerce_ui
13 | dependencies[] = commerce_customer
14 | dependencies[] = commerce_customer_ui
15 | dependencies[] = commerce_cart
16 | dependencies[] = commerce_cart_expiration
17 | dependencies[] = commerce_order
18 |
19 | files[] = rooms_booking.admin.inc
20 | files[] = rooms_booking_type.admin.inc
21 | files[] = includes/rooms_booking.availability_agent.inc
22 | files[] = includes/rooms_booking.availability_agent_filter.inc
23 | files[] = views/rooms_booking.views.inc
24 | files[] = views/rooms_booking_handler_link_field.inc
25 | files[] = views/rooms_booking_handler_date_field.inc
26 | files[] = views/rooms_booking_handler_delete_link_field.inc
27 | files[] = views/rooms_booking_handler_edit_link_field.inc
28 | files[] = views/rooms_booking_handler_unit_field.inc
29 | files[] = views/rooms_booking_handler_booking_operations_field.inc
30 | files[] = views/rooms_booking_handler_booking_type_field.inc
31 | files[] = views/rooms_booking_handler_date_filter.inc
32 | files[] = views/rooms_booking_handler_field_booking_status.inc
33 | files[] = views/rooms_booking_handler_filter_booking_status.inc
34 | files[] = views/rooms_booking_handler_unit_filter.inc
35 | files[] = views/rooms_booking_handler_nights_field.inc
36 |
--------------------------------------------------------------------------------
/modules/rooms_booking/rooms_booking.tpl.php:
--------------------------------------------------------------------------------
1 |
31 | >
32 |
33 |
>
34 |
35 |
36 |
37 |
38 |
>
39 |
46 |
47 |
48 |
--------------------------------------------------------------------------------
/modules/rooms_booking/rooms_booking_type.admin.inc:
--------------------------------------------------------------------------------
1 | path]['description'] = 'Manage booking types, including adding and removing fields and the display of fields.';
23 | $items[$this->path]['weight'] = '3';
24 | $items[$this->path]['type'] = MENU_LOCAL_TASK;
25 | return $items;
26 | }
27 | }
28 |
29 | /**
30 | * Generates the Booking type editing form.
31 | */
32 | function rooms_booking_type_form($form, &$form_state, $booking_type, $op = 'edit') {
33 |
34 | $form['#attributes']['class'][] = 'rooms-management-form rooms-booking-type-form';
35 |
36 | if ($op == 'clone') {
37 | $booking_type->label .= ' (cloned)';
38 | $booking_type->type = '';
39 | }
40 |
41 | $form['label'] = array(
42 | '#title' => t('Label'),
43 | '#type' => 'textfield',
44 | '#default_value' => $booking_type->label,
45 | '#description' => t('The human-readable name of this booking type.'),
46 | '#required' => TRUE,
47 | '#size' => 30,
48 | );
49 | // Machine-readable type name.
50 | $form['type'] = array(
51 | '#type' => 'machine_name',
52 | '#default_value' => isset($booking_type->type) ? $booking_type->type : '',
53 | '#maxlength' => 32,
54 | '#machine_name' => array(
55 | 'exists' => 'rooms_booking_get_types',
56 | 'source' => array('label'),
57 | ),
58 | '#description' => t('A unique machine-readable name for this booking type. It must only contain lowercase letters, numbers, and underscores.'),
59 | );
60 |
61 | $form['actions'] = array(
62 | '#type' => 'actions',
63 | '#tree' => FALSE,
64 | );
65 | $form['actions']['submit'] = array(
66 | '#type' => 'submit',
67 | '#value' => t('Save Booking type'),
68 | '#weight' => 40,
69 | );
70 |
71 | return $form;
72 | }
73 |
74 | /**
75 | * Form API submit callback for the type form.
76 | */
77 | function rooms_booking_type_form_submit(&$form, &$form_state) {
78 | $booking_type = entity_ui_form_submit_build_entity($form, $form_state);
79 | // Save and go back.
80 | $booking_type->save();
81 | $form_state['redirect'] = 'admin/rooms/bookings/booking-types';
82 | }
83 |
84 | /**
85 | * Form API submit callback for the delete button.
86 | */
87 | function rooms_booking_type_form_submit_delete(&$form, &$form_state) {
88 | $form_state['redirect'] = 'admin/rooms/bookings/booking_types/manage/' . $form_state['rooms_booking_type']->type . '/delete';
89 | }
90 |
--------------------------------------------------------------------------------
/modules/rooms_booking/views/rooms_booking_handler_booking_operations_field.inc:
--------------------------------------------------------------------------------
1 | additional_fields['booking_id'] = 'booking_id';
12 | }
13 |
14 | function query() {
15 | $this->ensure_my_table();
16 | $this->add_additional_fields();
17 | }
18 |
19 | function render($values) {
20 | $links = menu_contextual_links('rooms_booking', 'admin/rooms/bookings/booking', array($this->get_value($values, 'booking_id')));
21 | if (!empty($links)) {
22 | return theme('links', array(
23 | 'links' => $links,
24 | 'attributes' => array(
25 | 'class' => array('links',
26 | 'inline',
27 | 'operations'
28 | ),
29 | ),
30 | ));
31 | }
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/modules/rooms_booking/views/rooms_booking_handler_booking_type_field.inc:
--------------------------------------------------------------------------------
1 | get_value($values));
17 | return $booking_type->label;
18 | }
19 |
20 | }
21 |
--------------------------------------------------------------------------------
/modules/rooms_booking/views/rooms_booking_handler_date_field.inc:
--------------------------------------------------------------------------------
1 | get_value($values);
17 | $date = new DateTime($value);
18 | $value = $date->getTimestamp();
19 | $format = $this->options['date_format'];
20 | if (in_array($format, array('custom', 'raw time ago', 'time ago', 'raw time span', 'time span', 'raw time span', 'inverse time span', 'time span'))) {
21 | $custom_format = $this->options['custom_date_format'];
22 | }
23 |
24 | if ($value) {
25 | $time_diff = REQUEST_TIME - $value;
26 | switch ($format) {
27 | case 'raw time ago':
28 | return format_interval($time_diff, is_numeric($custom_format) ? $custom_format : 2);
29 |
30 | case 'time ago':
31 | return t('%time ago', array('%time' => format_interval($time_diff, is_numeric($custom_format) ? $custom_format : 2)));
32 |
33 | case 'raw time hence':
34 | return format_interval(-$time_diff, is_numeric($custom_format) ? $custom_format : 2);
35 |
36 | case 'time hence':
37 | return t('%time hence', array('%time' => format_interval(-$time_diff, is_numeric($custom_format) ? $custom_format : 2)));
38 |
39 | case 'raw time span':
40 | return ($time_diff < 0 ? '-' : '') . format_interval(abs($time_diff), is_numeric($custom_format) ? $custom_format : 2);
41 |
42 | case 'inverse time span':
43 | return ($time_diff > 0 ? '-' : '') . format_interval(abs($time_diff), is_numeric($custom_format) ? $custom_format : 2);
44 |
45 | case 'time span':
46 | return t(($time_diff < 0 ? '%time hence' : '%time ago'), array('%time' => format_interval(abs($time_diff), is_numeric($custom_format) ? $custom_format : 2)));
47 |
48 | case 'custom':
49 | if ($custom_format == 'r') {
50 | return format_date($value, $format, $custom_format, NULL, 'en');
51 | }
52 | return format_date($value, $format, $custom_format);
53 |
54 | default:
55 | return format_date($value, $format);
56 | }
57 | }
58 | }
59 |
60 | }
61 |
--------------------------------------------------------------------------------
/modules/rooms_booking/views/rooms_booking_handler_date_filter.inc:
--------------------------------------------------------------------------------
1 | view);
12 |
13 | $value = date('Y-m-d', intval(strtotime($this->value['value'], $query_substitutions['***CURRENT_TIME***'])));
14 |
15 | $this->query->add_where_expression($this->options['group'], "$field $this->operator '$value'");
16 | }
17 |
18 | function op_between($field) {
19 | // Use the substitutions to ensure a consistent timestamp.
20 | $query_substitutions = views_views_query_substitutions($this->view);
21 | $a = date('Y-m-d', intval(strtotime($this->value['min'], $query_substitutions['***CURRENT_TIME***'])));
22 | $b = date('Y-m-d', intval(strtotime($this->value['max'], $query_substitutions['***CURRENT_TIME***'])));
23 |
24 | // This is safe because we are manually scrubbing the values.
25 | // It is necessary to do it this way because $a and $b are formulas when using an offset.
26 | $operator = strtoupper($this->operator);
27 | $this->query->add_where_expression($this->options['group'], "$field $operator '$a' AND '$b'");
28 | }
29 |
30 | }
31 |
--------------------------------------------------------------------------------
/modules/rooms_booking/views/rooms_booking_handler_delete_link_field.inc:
--------------------------------------------------------------------------------
1 | additional_fields['type'] = 'type';
14 | }
15 |
16 |
17 | function render($values) {
18 | $type = $values->{$this->aliases['type']};
19 |
20 | // Creating a dummy room to check access against.
21 | $dummy_booking = (object) array('type' => $type);
22 | if (!rooms_booking_access('delete', $dummy_booking)) {
23 | return;
24 | }
25 |
26 | $text = !empty($this->options['text']) ? $this->options['text'] : t('delete');
27 | $booking_id = $values->{$this->aliases['booking_id']};
28 |
29 | return l($text, 'admin/rooms/bookings/booking/' . $booking_id . '/delete');
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/modules/rooms_booking/views/rooms_booking_handler_edit_link_field.inc:
--------------------------------------------------------------------------------
1 | additional_fields['type'] = 'type';
14 | }
15 |
16 |
17 | function render($values) {
18 | $type = $values->{$this->aliases['type']};
19 |
20 | //Creating a dummy booking to check access against
21 | $dummy_booking = (object) array('type' => $type);
22 | if (!rooms_booking_access('update', $dummy_booking)) {
23 | return;
24 | }
25 | $text = !empty($this->options['text']) ? $this->options['text'] : t('edit');
26 | $booking_id = $values->{$this->aliases['booking_id']};
27 |
28 | return l($text, 'admin/rooms/bookings/booking/' . $booking_id . '/edit');
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/modules/rooms_booking/views/rooms_booking_handler_field_booking_status.inc:
--------------------------------------------------------------------------------
1 | get_value($values);
12 |
13 | if ($value == 0) {
14 | return 'Unconfirmed';
15 | }
16 | elseif ($value == 1) {
17 | return 'Confirmed';
18 | }
19 |
20 | return '';
21 | }
22 |
23 | }
24 |
--------------------------------------------------------------------------------
/modules/rooms_booking/views/rooms_booking_handler_filter_booking_status.inc:
--------------------------------------------------------------------------------
1 | 'Unconfirmed',
12 | '1' => 'Confirmed',
13 | );
14 |
15 | $this->value_options = $options;
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/modules/rooms_booking/views/rooms_booking_handler_link_field.inc:
--------------------------------------------------------------------------------
1 | additional_fields['booking_id'] = 'booking_id';
14 | $this->additional_fields['type'] = 'type';
15 | }
16 |
17 | function option_definition() {
18 | $options = parent::option_definition();
19 |
20 | $options['text'] = array('default' => '', 'translatable' => TRUE);
21 |
22 | return $options;
23 | }
24 |
25 | function options_form(&$form, &$form_state) {
26 | parent::options_form($form, $form_state);
27 |
28 | $form['text'] = array(
29 | '#type' => 'textfield',
30 | '#title' => t('Text to display'),
31 | '#default_value' => $this->options['text'],
32 | );
33 | }
34 |
35 | function query() {
36 | $this->ensure_my_table();
37 | $this->add_additional_fields();
38 | }
39 |
40 | function render($values) {
41 | $text = !empty($this->options['text']) ? $this->options['text'] : t('view');
42 | $booking_id = $values->{$this->aliases['booking_id']};
43 |
44 | return l($text, 'booking/' . $booking_id);
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/modules/rooms_booking/views/rooms_booking_handler_nights_field.inc:
--------------------------------------------------------------------------------
1 | options['group_type'] != 'group' ? array('function' => $this->options['group_type']) : array();
14 | $this->query->add_orderby(NULL, NULL, $order, $this->field_alias, $params);
15 | }
16 |
17 | function query() {
18 | $this->ensure_my_table();
19 |
20 | $this->field_alias = $this->table_alias . '_nights';
21 |
22 | $alias = $this->field_alias;
23 | $counter = 0;
24 | while (!empty($this->query->fields[$this->field_alias])) {
25 | $this->field_alias = $alias . '_' . ++$counter;
26 | }
27 |
28 | // Add the field.
29 | $params = $this->options['group_type'] != 'group' ? array('function' => $this->options['group_type']) : array();
30 | $this->query->add_field(NULL, '(TO_DAYS(' . $this->table_alias . '.end_date) - TO_DAYS(' . $this->table_alias . '.start_date))', $this->field_alias, $params);
31 |
32 | $this->add_additional_fields();
33 | }
34 |
35 | function render($values) {
36 | $value = number_format($values->{$this->field_alias}, $this->options['precision'], $this->options['decimal'], $this->options['separator']);
37 | return $this->sanitize_value($value);
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/modules/rooms_booking/views/rooms_booking_handler_unit_field.inc:
--------------------------------------------------------------------------------
1 | additional_fields['unit_id'] = 'unit_id';
15 | }
16 |
17 | function option_definition() {
18 | $options = parent::option_definition();
19 |
20 | $options['text'] = array('default' => '', 'translatable' => TRUE);
21 |
22 | return $options;
23 | }
24 |
25 | function options_form(&$form, &$form_state) {
26 | parent::options_form($form, $form_state);
27 |
28 | $form['text'] = array(
29 | '#type' => 'textfield',
30 | '#title' => t('Text to display'),
31 | '#default_value' => $this->options['text'],
32 | );
33 | }
34 |
35 | function query() {
36 | $this->ensure_my_table();
37 | $this->add_additional_fields();
38 | }
39 |
40 | function render($values) {
41 | $unit_id = $values->{$this->aliases['unit_id']};
42 | $unit = rooms_unit_load($unit_id);
43 | if (!is_object($unit)) {
44 | return '';
45 | }
46 |
47 | $text = !empty($this->options['text']) ? $this->options['text'] : $unit->name;
48 |
49 | return l($text, 'admin/rooms/units/unit/' . $unit_id . '/availability');
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/modules/rooms_booking_manager/css/rooms_booking_search.css:
--------------------------------------------------------------------------------
1 | /* Make availability search fields layout look decent out of the box. */
2 |
3 | .rooms-availability-search {
4 | position: relative;
5 | }
6 | .rooms-availability-search .ajax-progress {
7 | position: absolute;
8 | top: 0;
9 | width: 100%;
10 | background: rgba(255, 255, 255, 0.8);
11 | height: 100%;
12 | left: 0;
13 | }
14 |
15 | .rooms-availability-search .form-item-group-size-children,
16 | .rooms-availability-search .form-item-group-size-adults,
17 | .rooms-availability-search .form-item-unit-type,
18 | .rooms-availability-search .form-item-rooms,
19 | .rooms-availability-search .form-wrapper {
20 | float: left;
21 | margin: 0 1em .6em 0;
22 | }
23 |
24 | .rooms-availability-search .rooms-date-range .form-text {
25 | width: 100%;
26 | }
27 |
28 | /* Group size field */
29 | .rooms-group-size,
30 | .rooms-group-size tr,
31 | .rooms-group-size th,
32 | .rooms-group-size td {
33 | background: none;
34 | border: none;
35 | margin: 0;
36 | padding: 0;
37 | color: inherit;
38 | font: inherit;
39 | }
40 |
41 | /* Labels */
42 | .rooms-group-size th,
43 | .rooms-group-size td,
44 | .rooms-availability-search .form-item label {
45 | font-weight: normal;
46 | font-size: 1em;
47 | margin: 0;
48 | padding-top: 0;
49 | padding-bottom: 0.2em;
50 | }
51 | .rooms-group-size tr:last-child td {
52 | padding-bottom: 0;
53 | }
54 | .rooms-group-size .rooms-group-size__children {
55 | padding-left: 20px;
56 | }
57 | .rooms-group-size .form-item {
58 | margin: 0;
59 | }
60 |
61 | .rooms-availability-search .form-item-adults,
62 | .rooms-availability-search .form-item-children,
63 | .rooms-availability-search-results .form-item-adults,
64 | .rooms-availability-search-results .form-item-children {
65 | padding-left: 1.1em;
66 | }
67 |
68 | .rooms-availability-search .rooms-search-result__actions {
69 | padding: 0;
70 | margin: 1.2em 0 0;
71 | }
72 |
73 |
74 | /* Current Search Info */
75 | .rooms-current-search__info,
76 | .rooms-management-form .rooms-current-search__info {
77 | float: left; /* or right */
78 | margin-bottom: 20px;
79 | }
80 | .rooms-current-search__info .form-item,
81 | .rooms-current-search__actions {
82 | font-size: 0.9em;
83 | clear: both;
84 | margin: 0;
85 | }
86 | .rooms-current-search__info .fieldset-legend {
87 | position: relative;
88 | text-transform: none;
89 | }
90 | .rooms-current-search__change-search-button {
91 | float: left;
92 | margin-left: 10em;
93 | }
94 | .rooms-current-search__info .form-item label {
95 | display: block;
96 | float: left;
97 | width: 9.5em;
98 | text-align: right;
99 | margin-right: .5em;
100 | }
101 | .rooms-current-search__info .form-type-item .info {
102 | display: block;
103 | float: left;
104 | width: 8em;
105 | }
106 |
107 | .rooms-search-result__unit-type {
108 | clear: both;
109 | margin-bottom: 20px;
110 | }
111 | .rooms-search-result__unit-type-name {
112 | margin-top: 20px;
113 | padding-top: 20px;
114 | border-top: 1px solid #ccc;
115 | }
116 | .rooms-search-result__booking-form {
117 | vertical-align: top;
118 | }
119 | .rooms-search-result__booking-form {
120 | position: relative;
121 | width: 100%;
122 | }
123 | .rooms-search-result__booking-form .ajax-progress {
124 | position: absolute;
125 | top: 0;
126 | width: 100%;
127 | background: rgba(255, 255, 255, 0.8);
128 | height: 100%;
129 | left: 0;
130 | }
131 | .rooms-search-result__unit-type-name {
132 | font-weight: bold;
133 | }
134 | .rooms-search-result__unit-price {
135 | text-align: right;
136 | }
137 | .rooms-search-result__unit-base-price label,
138 | .rooms-search-result__unit-price label {
139 | font-weight: bold;
140 | display: inline;
141 | }
142 | .rooms-search-result__booking-legend,
143 | .rooms-search-result__select-units {
144 | text-align: left;
145 | width: 15%;
146 | }
147 | .rooms-search-result__select-units .form-item label {
148 | display: inline;
149 | }
150 |
151 | /* Individual (embedded) unit search results layout */
152 | .rooms-search-result__unit-embedded {
153 | float: left;
154 | width: 100%;
155 | }
156 | .rooms-search-result__unit-embedded .rooms-search-result__select-guests,
157 | .rooms-search-result__unit-embedded .rooms-search-result__select-children,
158 | .rooms-search-result__unit-embedded .rooms-search-result__select-childrenage {
159 | float: left;
160 | margin-right: 20px;
161 | }
162 | .rooms-search-result__unit-embedded .rooms-search-result__new-price,
163 | .rooms-search-result__unit-embedded .rooms-search-result__actions {
164 | float: right;
165 | clear: right;
166 | }
167 | .rooms-search-result__new-price {
168 | font-weight: bold;
169 | }
170 | .rooms-search-result__unit_options .no-unit-fieldset {
171 | border: 0px;
172 | }
173 | .rooms-search-result__unit_options .no-unit-fieldset .fieldset-legend {
174 | display: none;
175 | }
176 | .rooms-search-result__unit_options .no-unit-fieldset legend{
177 | background:none;
178 | border:none;
179 | }
180 |
--------------------------------------------------------------------------------
/modules/rooms_booking_manager/css/rooms_sticky_booking_legend.css:
--------------------------------------------------------------------------------
1 | .booking-legend.is-fixed {
2 | position: fixed;
3 | top: 80px;
4 | }
5 |
--------------------------------------------------------------------------------
/modules/rooms_booking_manager/js/rooms_booking_manager_checked.js:
--------------------------------------------------------------------------------
1 | (function ($) {
2 | $(document).ready(function() {
3 | $('#edit-perc-textfield').focus(function()
4 | {
5 | $('input[name=rooms_payment_options][value=11]').attr('checked', true);
6 | });
7 | });
8 | })(jQuery);
9 |
--------------------------------------------------------------------------------
/modules/rooms_booking_manager/js/rooms_sticky_booking_legend.js:
--------------------------------------------------------------------------------
1 | (function ($) {
2 |
3 | /**
4 | * Similar to sticky-enabled tables from core Drupal, this allows the legend
5 | * on the far right side of the booking form to stay in place as the user
6 | * scrolls down the page to view the options.
7 | */
8 | Drupal.behaviors.rooms_sticky_booking_legend = {
9 | attach: function(context) {
10 |
11 | if ($('.booking-legend').offset() !== null) {
12 | var top = $('.booking-legend').offset().top - parseFloat($('.booking-legend').css('marginTop').replace(/auto/, 0));
13 | $(window).scroll(function (event) {
14 | // How far has the user scrolled vertically.
15 | var y = $(this).scrollTop();
16 |
17 | // When the user scrolls past the top of the booking legend.
18 | if (y >= top) {
19 | // Fix the legend in place on the page.
20 | $('.booking-legend').addClass('is-fixed');
21 | } else {
22 | // Otherwise un-fix it.
23 | $('.booking-legend').removeClass('is-fixed');
24 | }
25 | });
26 | }
27 | }
28 | };
29 |
30 | })(jQuery);
31 |
--------------------------------------------------------------------------------
/modules/rooms_booking_manager/rooms_booking_email.tpl.php:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/modules/rooms_booking_manager/rooms_booking_enquiry_confirmation.tpl.php:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/modules/rooms_booking_manager/rooms_booking_manager.api.php:
--------------------------------------------------------------------------------
1 | $value) {
27 | if ($key > 200) {
28 | unset($units_per_type['villa'][$key]);
29 | }
30 | }
31 | }
32 |
33 | /**
34 | * Allows you to change the line item before it is added to the cart - this gives
35 | * lots of flexibility to add information to a line item or change the label.
36 | *
37 | *
38 | * @param $line_item
39 | * @param array $context
40 | */
41 | function hook_rooms_create_line_item_alter(&$line_item, $context) {
42 | // No example.
43 | }
44 |
--------------------------------------------------------------------------------
/modules/rooms_booking_manager/rooms_booking_manager.commerce.inc:
--------------------------------------------------------------------------------
1 | unit_id;
28 | $status = $unit_to_book['state'];
29 |
30 | $unit = rooms_unit_load($unit_id);
31 |
32 | $unit_type = rooms_unit_type_load($unit->type);
33 |
34 | // Set the correct departure date for the product name (checkout day).
35 | $dd = new DateTime($agent->end_date->format('Y-m-d'));
36 | $dd->add(new DateInterval('P1D'));
37 |
38 | $product_id = variable_get('rooms_booking_manager_booking_product_id', 0);
39 | $room_product = commerce_product_load($product_id);
40 | $line_item = commerce_product_line_item_new($room_product, 1, 0, array(), 'rooms_booking');
41 |
42 | // Product name - we set something that will make sense to the user here.
43 | $nights = $dd->diff($agent->start_date)->days;
44 |
45 | $line_item_label = rooms_string(
46 | t('Booking for') . ' ' . $unit_type->label . ' (' .
47 | format_plural($nights, '1 Night', '@count Nights') . '; ' .
48 | t('Arrival') . ': ' . $agent->start_date->format($date_format) . ' ' .
49 | t('Departure') . ': ' . $dd->format($date_format) . ')' ,
50 | $context = array(
51 | '#component' => 'rooms_booking_manager',
52 | '#purpose' => 'rooms_create_line_item',
53 | '#data' => array(
54 | 'unit' => $unit_to_book,
55 | 'unit_id' => $unit_id,
56 | 'unit_type' => $unit_type->label,
57 | 'arrival' => $agent->start_date,
58 | 'departure' => $dd,
59 | 'nights' => $nights,
60 | )
61 | )
62 | );
63 |
64 | $line_item->line_item_label = $line_item_label;
65 |
66 | $unit_info = $agent->checkAvailabilityForUnit($unit_id, $price_modifiers);
67 |
68 | // Check $unit_info to make sure we still have availability.
69 | if ($unit_info == ROOMS_NO_ROOMS) {
70 | form_set_error('', t('We apologize for the inconvenience; this unit is no longer available.'));
71 | }
72 | else {
73 | // If available set price and create line item.
74 | $unit_first = array_pop($unit_info);
75 | $price = $unit_first['price'];
76 |
77 | // Convert to integer value as this is what Commerce expects.
78 | $price = commerce_currency_decimal_to_amount($price, commerce_default_currency());
79 |
80 | // We do not need to setup the line item's commerce_unit_price here, as it
81 | // will be overwritten with the values from the product entity anyway.
82 | // Setting commerce unit price to the correct value is now done completely
83 | // by the function rooms_booking_manager_price_apply()
84 | // in rooms_booking_manager.module.
85 | $commerce_dates = array(
86 | LANGUAGE_NONE => array(
87 | array(
88 | 'value' => $agent->start_date->format('Y-m-d') . 'T00:00:00',
89 | 'value2' => $dd->format('Y-m-d') . 'T00:00:00',
90 | ),
91 | ),
92 | );
93 |
94 | $commerce_unit = array(
95 | LANGUAGE_NONE => array(
96 | array(
97 | 'value' => $unit->unit_id,
98 | ),
99 | ),
100 | );
101 |
102 | $commerce_status = array(
103 | LANGUAGE_NONE => array(
104 | array(
105 | 'value' => $status,
106 | ),
107 | ),
108 | );
109 |
110 | $commerce_price = array(
111 | LANGUAGE_NONE => array(
112 | array(
113 | 'value' => $price,
114 | ),
115 | ),
116 | );
117 |
118 | $booking_price = array(
119 | LANGUAGE_NONE => array(
120 | array(
121 | 'value' => $unit_first['booking_price'],
122 | ),
123 | ),
124 | );
125 |
126 | $group_size = array(
127 | LANGUAGE_NONE => array(
128 | array(
129 | 'value' => isset($booking_size['adults']) ? $booking_size['adults'] : 0,
130 | ),
131 | array(
132 | 'value' => isset($booking_size['children']) ? $booking_size['children'] : 0,
133 | ),
134 | ),
135 | );
136 |
137 | $childrens_age = array(LANGUAGE_NONE => array());
138 | if (isset($booking_size['childrens_age'])) {
139 | foreach ($booking_size['childrens_age'] as $age) {
140 | $childrens_age[LANGUAGE_NONE][]['value'] = $age;
141 | }
142 | }
143 |
144 | $price_options = array();
145 | foreach ($price_modifiers as $mod) {
146 | $price_options[LANGUAGE_NONE][] = array(
147 | 'name' => $mod['#name'],
148 | 'quantity' => $mod['#quantity'],
149 | 'operation' => $mod['#op_type'],
150 | 'value' => $mod['#amount'],
151 | );
152 | }
153 |
154 | $line_item->rooms_booking_children_ages = $childrens_age;
155 | $line_item->rooms_booking_number_people = $group_size;
156 | $line_item->rooms_booking_dates = $commerce_dates;
157 | $line_item->rooms_booked_unit_id = $commerce_unit;
158 | $line_item->rooms_booked_status = $commerce_status;
159 | $line_item->rooms_booked_price = $commerce_price;
160 | $line_item->rooms_booked_bookingprice = $booking_price;
161 | $line_item->rooms_booking_options = $price_options;
162 |
163 | $context = array(
164 | 'unit' => $unit_to_book,
165 | 'unit_id' => $unit_id,
166 | 'unit_type' => $unit_type->label,
167 | 'arrival' => $agent->start_date,
168 | 'departure' => $dd,
169 | 'nights' => $nights,
170 | );
171 | drupal_alter('rooms_create_line_item', $line_item, $context);
172 |
173 | return $line_item;
174 | }
175 | }
176 |
--------------------------------------------------------------------------------
/modules/rooms_booking_manager/rooms_booking_manager.info:
--------------------------------------------------------------------------------
1 | name = Rooms Booking Manager
2 | description = Manages booking for Rooms - handling main integration with Commerce
3 | core = 7.x
4 |
5 | package = Rooms
6 |
7 | files[] = views/rooms_booking_manager.views.inc
8 |
9 | dependencies[] = number
10 |
11 | dependencies[] = rooms
12 | dependencies[] = rooms_unit
13 | dependencies[] = rooms_booking
14 | dependencies[] = commerce_product
15 | dependencies[] = commerce_product_ui
16 | dependencies[] = commerce_price
17 | dependencies[] = commerce_line_item
18 | dependencies[] = commerce_order
19 | dependencies[] = commerce_order_ui
20 | dependencies[] = commerce_checkout
21 | dependencies[] = entityreference
22 |
--------------------------------------------------------------------------------
/modules/rooms_booking_manager/rooms_booking_manager.rules.inc:
--------------------------------------------------------------------------------
1 | t('Cancel the booking related to an order'),
16 | 'parameter' => array(
17 | 'commerce_order' => array(
18 | 'type' => 'commerce_order',
19 | 'label' => t('Order from which to extract info for booking cancellation'),
20 | ),
21 | ),
22 | 'group' => t('Rooms'),
23 | 'callbacks' => array(
24 | 'execute' => 'rooms_booking_cancel_order_booking',
25 | ),
26 | );
27 |
28 | $actions['rooms_booking_manager_price_apply'] = array(
29 | 'label' => t('Apply price to a booking line item'),
30 | 'parameter' => array(
31 | 'commerce_line_item' => array(
32 | 'type' => 'commerce_line_item',
33 | 'label' => t('Line item'),
34 | ),
35 | ),
36 | 'group' => t('Rooms'),
37 | 'callbacks' => array(
38 | 'execute' => 'rooms_booking_manager_price_apply',
39 | ),
40 | );
41 |
42 | $actions['rooms_booking_manager_booked_price'] = array(
43 | 'label' => t('Set the line item price to the booked price'),
44 | 'parameter' => array(
45 | 'commerce_line_item' => array(
46 | 'type' => 'commerce_line_item',
47 | 'label' => t('Line item'),
48 | ),
49 | ),
50 | 'group' => t('Rooms'),
51 | 'callbacks' => array(
52 | 'execute' => 'rooms_booking_manager_booked_price',
53 | ),
54 | );
55 |
56 | return $actions;
57 | }
58 |
--------------------------------------------------------------------------------
/modules/rooms_booking_manager/rooms_booking_manager.rules_defaults.inc:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/modules/rooms_booking_manager/rooms_booking_results.tpl.php:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 | $units_per_price_level): ?>
16 |
17 |
18 |
19 |
20 | $units) : ?>
21 | $unit) : ?>
22 |
23 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
--------------------------------------------------------------------------------
/modules/rooms_pricing/css/rooms_pricing.css:
--------------------------------------------------------------------------------
1 | /* Styles for the rooms_pricing edit form */
2 | .rooms-bulk-pricing-form .fc-header {
3 | display: none;
4 | }
5 |
6 | /* Filter month form */
7 | .rooms-filter-month-form .form-item-month,
8 | .rooms-filter-month-form .form-item-year,
9 | .rooms-management-form .form-item,
10 | .rooms-filter-month-form .form-item-type {
11 | float: left;
12 | margin-right: 20px;
13 | }
14 | .rooms-filter-month-form .form-item-month label,
15 | .rooms-filter-month-form .form-item-year label,
16 | .rooms-filter-month-form .form-item-type label {
17 | display: inline;
18 | margin-right: 4px;
19 | }
20 |
21 | /* Bulk pricing form */
22 | .rooms-bulk-pricing-form .fc-day-grid-container {
23 | overflow-y: hidden;
24 | height: 60px;
25 | }
26 | .rooms-bulk-pricing-form .form-item-day-options {
27 | float: left;
28 | margin-right: 20px;
29 | }
30 | .rooms-bulk-pricing-form .form-item-day-options .form-type-checkbox {
31 | display: inline;
32 | }
33 | .rooms-bulk-pricing-form .form-item-day-options .form-checkboxes:after {
34 | content: ".";
35 | display: block;
36 | height: 0;
37 | clear: both;
38 | visibility: hidden;
39 | }
40 | .fc-day-grid-container {
41 | overflow-y: hidden;
42 | }
43 | .fc-title {
44 | color: white;
45 | }
46 |
--------------------------------------------------------------------------------
/modules/rooms_pricing/includes/rooms_pricing.pricing_event.inc:
--------------------------------------------------------------------------------
1 | unit_id = $unit_id;
40 | $this->amount = $amount;
41 | $this->start_date = $start_date;
42 | $this->end_date = $end_date;
43 | $this->operation = $operation;
44 | }
45 |
46 | /**
47 | * {@inheritdoc}
48 | */
49 | protected function createEvent(DateTime $start_date, DateTime $end_date) {
50 | return new PricingEvent($this->unit_id, $this->amount, $start_date, $end_date, $this->operation);
51 | }
52 |
53 | /**
54 | * {@inheritdoc}
55 | */
56 | public function applyOperation($amount, $operation) {
57 | switch ($operation) {
58 | case ROOMS_REPLACE:
59 | $this->amount = $amount;
60 | break;
61 |
62 | case ROOMS_ADD:
63 | $this->amount = $this->amount + $amount;
64 | break;
65 |
66 | case ROOMS_SUB:
67 | $this->amount = $this->amount - $amount;
68 | break;
69 |
70 | case ROOMS_INCREASE:
71 | $this->amount = $this->amount + (($this->amount) * ($amount / 100));
72 | break;
73 |
74 | case ROOMS_DECREASE:
75 | $this->amount = $this->amount - (($this->amount) * ($amount / 100));
76 | break;
77 |
78 | default:
79 | break;
80 | }
81 |
82 | }
83 |
84 | /**
85 | * {@inheritdoc}
86 | */
87 | public function formatJson() {
88 | $amount = $this->amount;
89 |
90 | $event = array(
91 | "id" => $amount,
92 | "start" => $this->startYear() . '-' . $this->startMonth('m') . '-' . $this->startDay('d') . 'T13:00:00',
93 | "end" => $this->endYear() . '-' . $this->endMonth('m') . '-' . $this->endDay('d') . 'T13:00:00',
94 | );
95 |
96 | // Set the color.
97 | if ($amount < 100) {
98 | $event['color'] = variable_get('rooms_price_low_value_color', '#F3C776');
99 | $event['title'] = $amount;
100 | }
101 | elseif ($amount >= 100) {
102 | $event['color'] = variable_get('rooms_price_high_value_color', '#9DDC9D');
103 | $event['title'] = $amount;
104 | }
105 |
106 | return $event;
107 | }
108 |
109 | }
110 |
--------------------------------------------------------------------------------
/modules/rooms_pricing/includes/rooms_pricing.pricing_event_interface.inc:
--------------------------------------------------------------------------------
1 | $t('Rooms periodic Pricing'),
15 | 'description' => $t('You need to run @url', array('@url' => 'update.php')),
16 | 'value' => 'Weekly, Monthly fields missing',
17 | 'severity' => REQUIREMENT_ERROR,
18 | );
19 | }
20 | }
21 |
22 | return $requirements;
23 | }
24 |
--------------------------------------------------------------------------------
/modules/rooms_pricing/modules/rooms_periodic_pricing/rooms_periodic_pricing.module:
--------------------------------------------------------------------------------
1 | 'fieldset',
11 | '#title' => t('Weekly/Monthly discount'),
12 | '#tree' => FALSE,
13 | '#weight' => -97,
14 | '#collapsible' => TRUE,
15 | '#collapsed' => TRUE,
16 | );
17 |
18 | $form['weekly_monthly_discount']['weekly_discount'] = array(
19 | '#type' => 'textfield',
20 | '#title' => t('Weekly discount'),
21 | '#default_value' => isset($unit->weekly_discount) ? $unit->weekly_discount : '',
22 | '#size' => '5',
23 | '#field_suffix' => t('% (> 7 days)'),
24 | '#description' => t('You can provide here a percentage that will be applied as a discount to the standard cost for bookings that exceed 7 days.'),
25 | '#maxlength' => 10,
26 | );
27 |
28 | $form['weekly_monthly_discount']['monthly_discount'] = array(
29 | '#type' => 'textfield',
30 | '#title' => t('Monthly discount'),
31 | '#default_value' => isset($unit->monthly_discount) ? $unit->monthly_discount : '',
32 | '#size' => '5',
33 | '#field_suffix' => t('% (> 28 days)'),
34 | '#description' => t('You can provide here a percentage that will be applied as a discount to the standard cost for bookings that exceed 28 days.'),
35 | '#maxlength' => 10,
36 | );
37 |
38 | if (isset($unit->weekly_discount) && $unit->weekly_discount == '0.00') {
39 | $form['weekly_monthly_discount']['weekly_discount']['#default_value'] = '';
40 | }
41 | if (isset($unit->monthly_discount) && $unit->monthly_discount == '0.00') {
42 | $form['weekly_monthly_discount']['monthly_discount']['#default_value'] = '';
43 | }
44 |
45 | $form['#validate'][] = 'rooms_periodic_pricing_form_rooms_unit_edit_form_validate';
46 |
47 | $form['#attached']['css'][] = drupal_get_path('module', 'rooms_periodic_pricing') . '/css/rooms_periodic_pricing.css';
48 | }
49 |
50 | /**
51 | * Validate 'Weekly discount' and 'Monthly discount'.
52 | */
53 | function rooms_periodic_pricing_form_rooms_unit_edit_form_validate(&$form, &$form_state) {
54 | if (empty($form_state['values']['weekly_discount'])) {
55 | $form_state['values']['weekly_discount'] = '0';
56 | }
57 | elseif (!empty($form_state['values']['weekly_discount'])) {
58 | if (!is_numeric($form_state['values']['weekly_discount'])) {
59 | form_set_error('weekly_discount', t('%name: you must enter a numeric value for the weekly percentage.', array('%name' => t('Weekly discount'))));
60 | }
61 | elseif ($form_state['values']['weekly_discount'] < 0 || $form_state['values']['weekly_discount'] > 100) {
62 | form_set_error('weekly_discount', t('%name: you must enter a valid value for the weekly percentage.', array('%name' => t('Weekly discount'))));
63 | }
64 | }
65 |
66 | if (empty($form_state['values']['monthly_discount'])) {
67 | $form_state['values']['monthly_discount'] = '0';
68 | }
69 | elseif (!empty($form_state['values']['monthly_discount'])) {
70 | if (!is_numeric($form_state['values']['monthly_discount'])) {
71 | form_set_error('monthly_discount', t('%name: you must enter a numeric value for the monthly percentage.', array('%name' => t('Monthly discount'))));
72 | }
73 | elseif ($form_state['values']['monthly_discount'] < 0 || $form_state['values']['monthly_discount'] > 100) {
74 | form_set_error('weekly_discount', t('%name: you must enter a valid value for the monthly percentage.', array('%name' => t('Monthly discount'))));
75 | }
76 | }
77 | }
78 |
79 | /**
80 | * Implements hook_rooms_string_alter().
81 | */
82 | function rooms_periodic_pricing_rooms_string_alter(&$string_suggestions, $context) {
83 | if ($context['#purpose'] == 'display_base_price') {
84 | $string_suggestion = reset($string_suggestions);
85 |
86 | if (module_exists('commerce_multicurrency')) {
87 | $currency_code = commerce_multicurrency_get_user_currency_code();
88 | }
89 | else {
90 | $currency_code = commerce_default_currency();
91 | }
92 |
93 | $price = $context['#data']['price'];
94 |
95 | if ($context['#component'] == 'units_per_type_form') {
96 | $units = reset($context['#data']['units'][$price]);
97 | $unit = $units['unit'];
98 |
99 | $price_log = $units['price_log'];
100 | }
101 | elseif ($context['#component'] == 'book_unit_form_builder') {
102 | $unit = $context['#data']['unit'];
103 | $price_log = $context['#data']['price_log'];
104 | }
105 |
106 | $start_date = $context['#data']['arrival'];
107 | $end_date = $context['#data']['departure'];
108 |
109 | if (isset($price_log['modifiers']['rooms_periodic_pricing']['dynamic_modifier']['pre'])) {
110 | $pre_price = $price_log['modifiers']['rooms_periodic_pricing']['dynamic_modifier']['pre'];
111 | $post_price = $price_log['modifiers']['rooms_periodic_pricing']['dynamic_modifier']['post'];
112 |
113 | $price_amount = ($pre_price - $post_price) * 100;
114 | if (module_exists('commerce_multicurrency')) {
115 | $price_amount = commerce_currency_convert($price_amount, commerce_default_currency(), $currency_code);
116 | }
117 |
118 | $string_suggestion .= ' ' . t('(Reduction of @amount)', array('@amount' => commerce_currency_format($price_amount, $currency_code)));
119 | }
120 |
121 | $string_suggestions[] = $string_suggestion;
122 | }
123 | }
124 |
125 | /**
126 | * Implements hook_rooms_price_modifier_alter().
127 | */
128 | function rooms_periodic_pricing_rooms_price_modifier_alter(&$price_modifiers, $booking_info) {
129 | if (!isset($price_modifiers['rooms_periodic_pricing'])) {
130 | $unit = $booking_info['unit'];
131 | $end_date = $booking_info['end_date'];
132 | $start_date = $booking_info['start_date'];
133 |
134 | $weeks_months_days = rooms_periodic_pricing_calculate_weeks_months_days($start_date, $end_date);
135 |
136 | // If "Monthly discount" is set and the current period is greater than or equal to 28 days.
137 | if ($weeks_months_days['months'] > 0 && $unit->monthly_discount > 0) {
138 | // Add a new price modifier to decrease old price with monthly discount.
139 | $price_modifiers['rooms_periodic_pricing'] = array(
140 | '#type' => ROOMS_DYNAMIC_MODIFIER,
141 | '#quantity' => 1,
142 | '#op_type' => ROOMS_DECREASE,
143 | '#amount' => $unit->monthly_discount,
144 | );
145 | }
146 | // If "Weekly discount" is set and the current period is greater than or equal to 7 days.
147 | elseif ($weeks_months_days['total_weeks'] > 0 && $unit->weekly_discount > 0) {
148 | // Add a new price modifier to decrease old price with weekly discount.
149 | $price_modifiers['rooms_periodic_pricing'] = array(
150 | '#type' => ROOMS_DYNAMIC_MODIFIER,
151 | '#quantity' => 1,
152 | '#op_type' => ROOMS_DECREASE,
153 | '#amount' => $unit->weekly_discount,
154 | );
155 | }
156 | }
157 | }
158 |
159 | /**
160 | * Calculate number of days, weeks and months in a given period.
161 | *
162 | * @param DateTime $start_date
163 | * The starting date
164 | *
165 | * @param DateTime $end_date
166 | * The end date of our range
167 | *
168 | * @return array
169 | */
170 | function rooms_periodic_pricing_calculate_weeks_months_days($start_date, $end_date) {
171 | $days = $end_date->diff($start_date)->days;
172 |
173 | $weeks = floor($days / 7);
174 | $months = floor($weeks / 4);
175 |
176 | $more_weeks = $weeks % 4;
177 | $more_days = $days % 7;
178 |
179 | return array(
180 | 'total_days' => $days,
181 | 'total_weeks' => $weeks,
182 | 'more_days' => $more_days,
183 | 'more_weeks' => $more_weeks,
184 | 'months' => $months,
185 | );
186 | }
187 |
--------------------------------------------------------------------------------
/modules/rooms_pricing/rooms_pricing.api.php:
--------------------------------------------------------------------------------
1 | diff($booking_data['end_date'])->days + 1;
33 |
34 | if ($period > 5) {
35 | $price = 100;
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/modules/rooms_pricing/rooms_pricing.info:
--------------------------------------------------------------------------------
1 | name = Rooms Pricing
2 | description = Manages pricing information for Rooms.
3 | core = 7.x
4 |
5 | package = Rooms
6 |
7 | files[] = includes/rooms_pricing.unit_pricing_calendar.inc
8 | files[] = includes/rooms_pricing.unit_pricing_calendar_interface.inc
9 | files[] = includes/rooms_pricing.pricing_event.inc
10 | files[] = includes/rooms_pricing.pricing_event_interface.inc
11 |
12 | dependencies[] = rooms_unit
13 | dependencies[] = commerce
14 | dependencies[] = bat_api
15 |
--------------------------------------------------------------------------------
/modules/rooms_unit/css/rooms_unit.css:
--------------------------------------------------------------------------------
1 | /* Bookable unit edit form */
2 | .rooms-unit-edit-form .form-wrapper {
3 | max-width: 400px;
4 | margin: 0 20px 0.4em 0;
5 | }
6 | .rooms-unit-edit-form .form-item {
7 | margin-bottom: 1em;
8 | }
9 | .rooms-unit-edit-form .form-item label,
10 | .rooms-unit-edit-form .form-wrapper legend {
11 | margin-bottom: 0.2em;
12 | }
13 | .rooms-unit-edit-form .form-item label,
14 | .rooms-unit-edit-form .form-wrapper .fieldset-legend {
15 | font-size: 1em;
16 | font-weight: bold;
17 | }
18 | .rooms-unit-edit-form .form-checkbox + label {
19 | font-weight: normal;
20 | }
21 | .rooms-unit-edit-form .form-checkbox:checked + label {
22 | font-weight: bold;
23 | }
24 | .rooms-unit-edit-form .field-widget-rooms-options-combined {
25 | max-width: inherit;
26 | margin-right: 0;
27 | clear: both;
28 | }
29 |
30 | .rooms-unit-edit-form .field-widget-rooms-availability-constraints-range {
31 | max-width: inherit;
32 | margin-right: 0;
33 | clear: both;
34 | }
35 |
36 | .rooms-unit-edit-form .form-item-name,
37 | .rooms-unit-edit-form .form-item-base-price,
38 | .rooms-unit-edit-form .rooms-unit-guest-capacity,
39 | .rooms-unit-edit-form .rooms-unit-child-capacity,
40 | .rooms-unit-edit-form .rooms-unit-bed-arrangement {
41 | float: left;
42 | width: 15em;
43 | margin-right: 20px;
44 | }
45 |
46 | .rooms-unit-edit-form .rooms-unit-guest-capacity {
47 | clear: left;
48 | }
49 |
50 | .rooms-unit-edit-form .rooms-unit-guest-capacity .form-text,
51 | .rooms-unit-edit-form .rooms-unit-child-capacity .form-text,
52 | .rooms-unit-edit-form .rooms-unit-data-bed-arrangement .form-text {
53 | width: 2em;
54 | text-align: right;
55 | }
56 |
57 | .rooms-unit-edit-form .form-item-base-price .form-text {
58 | width: 6em;
59 | text-align: right;
60 | }
61 |
62 | .rooms-unit-edit-form .form-actions {
63 | clear: both;
64 | float: none;
65 | }
66 |
--------------------------------------------------------------------------------
/modules/rooms_unit/css/rooms_unit_type.css:
--------------------------------------------------------------------------------
1 | /* Bookable unit type edit form */
2 | .rooms-unit-type-edit-form .form-wrapper {
3 | max-width: 400px;
4 | margin: 0 20px 0.4em 0;
5 | }
6 | .rooms-unit-type-edit-form .form-item {
7 | margin-bottom: 1em;
8 | }
9 | .rooms-unit-type-edit-form .form-item label,
10 | .rooms-unit-type-edit-form .form-wrapper legend {
11 | margin-bottom: 0.2em;
12 | }
13 | .rooms-unit-type-edit-form .form-item label,
14 | .rooms-unit-type-edit-form .form-wrapper .fieldset-legend {
15 | font-size: 1em;
16 | font-weight: bold;
17 | }
18 | .rooms-unit-type-edit-form .form-checkbox + label {
19 | font-weight: normal;
20 | }
21 | .rooms-unit-type-edit-form .form-checkbox:checked + label {
22 | font-weight: bold;
23 | }
24 | .rooms-unit-type-edit-form .field-widget-rooms-options-combined {
25 | max-width: inherit;
26 | margin-right: 0;
27 | clear: both;
28 | }
29 | .rooms-unit-type-edit-form .field-widget-rooms-availability-constraints-range {
30 | max-width: inherit;
31 | margin-right: 0;
32 | clear: both;
33 | }
34 | .rooms-unit-type-edit-form .form-actions {
35 | clear: both;
36 | }
37 |
38 | .rooms-unit-type-edit-form .form-item-name,
39 | .rooms-unit-type-edit-form .form-item-data-base-price,
40 | .rooms-unit-type-edit-form .rooms-unit-type-guest-capacity,
41 | .rooms-unit-type-edit-form .rooms-unit-type-child-capacity {
42 | float: left;
43 | width: 15em;
44 | margin-right: 20px;
45 | }
46 | .rooms-unit-type-edit-form .rooms-unit-type-reference,
47 | .rooms-unit-type-edit-form .rooms-unit-type-defaults {
48 | float: none;
49 | width: 100%;
50 | max-width: 100%;
51 | }
52 |
--------------------------------------------------------------------------------
/modules/rooms_unit/js/rooms_unit.js:
--------------------------------------------------------------------------------
1 | (function ($) {
2 |
3 | Drupal.behaviors.nodeFieldsetSummaries = {
4 | attach: function (context) {
5 | $('fieldset.unit-form-availability', context).drupalSetSummary(function (context) {
6 | var vals = [];
7 |
8 | if ($('.form-item-bookable input', context).is(':checked')) {
9 | vals.push(Drupal.t('Bookable'));
10 | }
11 | else {
12 | vals.push(Drupal.t('Not bookable'));
13 | }
14 |
15 | vals.push($('#edit-default-state option:selected').text());
16 |
17 | return vals.join(', ');
18 | });
19 |
20 | $('fieldset.unit-form-multiple', context).drupalSetSummary(function (context) {
21 |
22 | if ($('.form-item-multiple input', context).val() > 1) {
23 | return (Drupal.t('Multiple: @units units', { '@units': $('.form-item-multiple input', context).val()}));
24 | }
25 | else {
26 | return (Drupal.t('Not multiple'));
27 | }
28 | });
29 |
30 | $('fieldset.unit-form-author', context).drupalSetSummary(function (context) {
31 | var name = $('.form-item-author-name input', context).val() || Drupal.settings.anonymous,
32 | date = $('.form-item-date input', context).val();
33 | return date ?
34 | Drupal.t('By @name on @date', { '@name': name, '@date': date }) :
35 | Drupal.t('By @name', { '@name': name });
36 | });
37 |
38 | $('fieldset.unit-form-published', context).drupalSetSummary(function (context) {
39 |
40 | if ($('.form-item-status input', context).is(':checked')) {
41 | return (Drupal.t('Published'));
42 | }
43 | else {
44 | return (Drupal.t('Not published'));
45 | }
46 | });
47 | }
48 | };
49 |
50 | })(jQuery);
51 |
--------------------------------------------------------------------------------
/modules/rooms_unit/rooms_unit-extra-data.tpl.php:
--------------------------------------------------------------------------------
1 |
14 |
15 |
16 | Unit Sample Data: ' . $rooms_unit_sample_data = ($rooms_unit_sample_data) ? 'Switch On' : 'Switch Off' ?>
17 |
18 |
--------------------------------------------------------------------------------
/modules/rooms_unit/rooms_unit.features.inc:
--------------------------------------------------------------------------------
1 |
31 | >
32 |
33 |
>
34 |
35 |
36 |
37 |
38 |
>
39 |
46 |
47 |
48 |
--------------------------------------------------------------------------------
/modules/rooms_unit/views/rooms_unit_handler_delete_link_field.inc:
--------------------------------------------------------------------------------
1 | additional_fields['type'] = 'type';
13 | }
14 |
15 |
16 | function render($values) {
17 | $type = $values->{$this->aliases['type']};
18 |
19 | // Creating a dummy room to check access against.
20 | $dummy_unit = (object) array('type' => $type);
21 | if (!rooms_unit_access('delete', $dummy_unit)) {
22 | return;
23 | }
24 |
25 | $text = !empty($this->options['text']) ? $this->options['text'] : t('delete');
26 | $unit_id = $values->{$this->aliases['unit_id']};
27 |
28 | return l($text, 'admin/rooms/units/unit/' . $unit_id . '/delete');
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/modules/rooms_unit/views/rooms_unit_handler_edit_link_field.inc:
--------------------------------------------------------------------------------
1 | additional_fields['type'] = 'type';
13 | }
14 |
15 |
16 | function render($values) {
17 | $type = $values->{$this->aliases['type']};
18 |
19 | // Creating a dummy unit to check access against.
20 | $dummy_unit = (object) array('type' => $type);
21 | if (!rooms_unit_access('update', $dummy_unit)) {
22 | return;
23 | }
24 | $text = !empty($this->options['text']) ? $this->options['text'] : t('edit');
25 | $unit_id = $values->{$this->aliases['unit_id']};
26 |
27 | return l($text, 'admin/rooms/units/unit/' . $unit_id . '/edit');
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/modules/rooms_unit/views/rooms_unit_handler_link_field.inc:
--------------------------------------------------------------------------------
1 | additional_fields['unit_id'] = 'unit_id';
14 | $this->additional_fields['type'] = 'type';
15 | }
16 |
17 | function option_definition() {
18 | $options = parent::option_definition();
19 |
20 | $options['text'] = array('default' => '', 'translatable' => TRUE);
21 |
22 | return $options;
23 | }
24 |
25 | function options_form(&$form, &$form_state) {
26 | parent::options_form($form, $form_state);
27 |
28 | $form['text'] = array(
29 | '#type' => 'textfield',
30 | '#title' => t('Text to display'),
31 | '#default_value' => $this->options['text'],
32 | );
33 | }
34 |
35 | function query() {
36 | $this->ensure_my_table();
37 | $this->add_additional_fields();
38 | }
39 |
40 | function render($values) {
41 | $text = !empty($this->options['text']) ? $this->options['text'] : t('view');
42 | $unit_id = $values->{$this->aliases['unit_id']};
43 |
44 | return l($text, 'unit/' . $unit_id);
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/modules/rooms_unit/views/rooms_unit_handler_unit_operations_field.inc:
--------------------------------------------------------------------------------
1 | additional_fields['unit_id'] = 'unit_id';
14 | }
15 |
16 | function query() {
17 | $this->ensure_my_table();
18 | $this->add_additional_fields();
19 | }
20 |
21 | function render($values) {
22 | $links = menu_contextual_links('rooms_unit', 'admin/rooms/units/unit', array($this->get_value($values, 'unit_id')));
23 |
24 | // Unset the "view" link, as this is provided separately.
25 | if (array_key_exists('rooms_unit-view', $links)) {
26 | unset($links['rooms_unit-view']);
27 | }
28 |
29 | if (!empty($links)) {
30 | return theme('links', array(
31 | 'links' => $links,
32 | 'attributes' => array(
33 | 'class' => array(
34 | 'links',
35 | 'inline',
36 | 'operations',
37 | ),
38 | ),
39 | ));
40 | }
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/modules/rooms_unit/views/rooms_unit_handler_unit_type_field.inc:
--------------------------------------------------------------------------------
1 | get_value($values));
17 | return $unit_type->label;
18 | }
19 |
20 | }
21 |
--------------------------------------------------------------------------------
/rooms.api.php:
--------------------------------------------------------------------------------
1 | max_sleeps;
94 | }
95 | }
96 |
--------------------------------------------------------------------------------
/rooms.info:
--------------------------------------------------------------------------------
1 | name = Rooms
2 | description = Provides basic underlying functionality and configuration options used by all Rooms modules.
3 | core = 7.x
4 | php = 5.3.9
5 |
6 | files[] = includes/rooms.calendar.inc
7 | files[] = includes/rooms.calendar_interface.inc
8 | files[] = includes/rooms.event.inc
9 | files[] = includes/rooms.event_interface.inc
10 |
11 | package = Rooms
12 |
13 | dependencies[] = date
14 | dependencies[] = date_api
15 | dependencies[] = date_popup
16 | dependencies[] = jquery_update
17 | dependencies[] = libraries (>=2.x)
18 | dependencies[] = variable
19 |
--------------------------------------------------------------------------------
/rooms.install:
--------------------------------------------------------------------------------
1 | array(
15 | 'name' => array(
16 | 'type' => 'varchar',
17 | 'length' => 255,
18 | 'not null' => TRUE,
19 | ),
20 | 'quantity' => array(
21 | 'type' => 'int',
22 | 'not null' => FALSE,
23 | ),
24 | 'operation' => array(
25 | 'type' => 'varchar',
26 | 'length' => 255,
27 | 'not null' => FALSE,
28 | ),
29 | 'value' => array(
30 | 'type' => 'float',
31 | 'not null' => FALSE,
32 | ),
33 | 'type' => array(
34 | 'type' => 'varchar',
35 | 'length' => 255,
36 | 'not null' => FALSE,
37 | ),
38 | ),
39 | );
40 | }
41 | }
42 |
43 | /**
44 | * Implements hook_requirements().
45 | */
46 | function rooms_requirements($phase) {
47 | $requirements = array();
48 | $t = get_t();
49 | switch ($phase) {
50 | case 'runtime':
51 | if (!rooms_library_loaded('fullcalendar', 'minified')) {
52 | $description = array();
53 | $fullcalendar_library = libraries_detect('fullcalendar');
54 | if (!$fullcalendar_library['installed']) {
55 | $description[] = $t('Could not load the FullCalendar Library');
56 | }
57 | $requirements['fullcalendar'] = array(
58 | 'title' => $t('FullCalendar'),
59 | 'description' => implode('
', $description),
60 | 'value' => 'FullCalendar Missing',
61 | 'severity' => REQUIREMENT_ERROR,
62 | );
63 | }
64 | else {
65 | $requirements['fullcalendar'] = array(
66 | 'title' => $t('FullCalendar'),
67 | 'description' => $t('The FullCalendar Library is installed'),
68 | 'value' => 'FullCalendar Installed',
69 | 'severity' => REQUIREMENT_OK,
70 | );
71 | }
72 | }
73 |
74 | return $requirements;
75 | }
76 |
77 | /**
78 | * Utility function: rename a set of permissions.
79 | */
80 | function rooms_update_rename_permissions($map) {
81 | // Easy part: rename the permissions in {role_permission}.
82 | foreach ($map as $old_name => $new_name) {
83 | db_update('role_permission')
84 | ->fields(array('permission' => $new_name))
85 | ->condition('permission', $old_name)
86 | ->execute();
87 | }
88 |
89 | // Trickier: rename the permission for the in-database Views.
90 | foreach (views_get_all_views() as $view) {
91 | if ($view->type == t('Default')) {
92 | continue;
93 | }
94 |
95 | $save_view = FALSE;
96 | foreach ($view->display as $display_name => $display) {
97 | if (!empty($display->display_options['access']['type']) && $display->display_options['access']['type'] == 'perm') {
98 | $permission_name = $display->display_options['access']['perm'];
99 | if (isset($map[$permission_name])) {
100 | $display->display_options['access']['perm'] = $map[$permission_name];
101 | $save_view = TRUE;
102 | }
103 | }
104 | }
105 |
106 | if ($save_view) {
107 | $view->save();
108 | }
109 | }
110 | }
111 |
112 | /**
113 | * Converts the booking option price value columns from integer to float.
114 | */
115 | function rooms_update_7001() {
116 | $spec = array(
117 | 'type' => 'float',
118 | 'not null' => FALSE,
119 | );
120 |
121 | $fields = array_filter(field_info_fields(), function($item) {
122 | return $item['type'] == 'rooms_options';
123 | });
124 |
125 | foreach ($fields as $field_definition) {
126 | $data_table = 'field_data_' . $field_definition['field_name'];
127 | $revision_table = 'field_revision_' . $field_definition['field_name'];
128 | $field = $field_definition['field_name'] . '_value';
129 |
130 | db_change_field($data_table, $field, $field, $spec);
131 | db_change_field($revision_table, $field, $field, $spec);
132 | }
133 | return t('Field structure updated.');
134 | }
135 |
136 | /**
137 | * Add the booking option Type column.
138 | */
139 | function rooms_update_7002() {
140 | $fields = field_info_fields();
141 |
142 | foreach ($fields as $field) {
143 | if ($field['type'] == 'rooms_options') {
144 | $revision_table = key($field['storage']['details']['sql']['FIELD_LOAD_REVISION']);
145 | $field_name = $field['storage']['details']['sql']['FIELD_LOAD_REVISION'][$revision_table]['type'];
146 | if (!db_field_exists($revision_table, $field_name)) {
147 | $field_spec = $field['columns']['type'];
148 | $field_spec['initial'] = 'optional';
149 | db_add_field($revision_table, $field_name, $field_spec);
150 | }
151 |
152 | $current_table = key($field['storage']['details']['sql']['FIELD_LOAD_CURRENT']);
153 | $field_name = $field['storage']['details']['sql']['FIELD_LOAD_CURRENT'][$current_table]['type'];
154 | if (!db_field_exists($current_table, $field_name)) {
155 | $field_spec = $field['columns']['type'];
156 | $field_spec['initial'] = 'optional';
157 | db_add_field($current_table, $field_name, $field_spec);
158 | }
159 | }
160 | }
161 | }
162 |
--------------------------------------------------------------------------------
/rooms.make:
--------------------------------------------------------------------------------
1 | api = 2
2 | core = 7.x
3 |
4 | ; @see https://github.com/drush-ops/drush
5 |
6 | ; FullCalendar
7 | libraries[fullcalendar][directory_name] = fullcalendar
8 | libraries[fullcalendar][type] = library
9 | libraries[fullcalendar][destination] = libraries
10 | libraries[fullcalendar][download][type] = get
11 | libraries[fullcalendar][download][url] = https://github.com/arshaw/fullcalendar/releases/download/v3.1.0/fullcalendar-3.1.0.zip
12 |
--------------------------------------------------------------------------------
/rooms.variable.inc:
--------------------------------------------------------------------------------
1 | 'string',
13 | 'title' => t('Arrival Date'),
14 | 'default' => 'Arrival Date',
15 | 'description' => t('Change text : Arrival Date'),
16 | 'localize' => TRUE,
17 | 'group' => 'rooms',
18 | );
19 |
20 | $variables['rooms_departure_date'] = array(
21 | 'type' => 'string',
22 | 'title' => t('Departure Date'),
23 | 'default' => 'Departure Date',
24 | 'description' => t('Change text : Departure Date'),
25 | 'localize' => TRUE,
26 | 'group' => 'rooms',
27 | );
28 |
29 | return $variables;
30 | }
31 |
32 | /**
33 | * Implements hook_variable_group_info().
34 | */
35 |
36 | function rooms_variable_group_info() {
37 | $groups['rooms'] = array(
38 | 'title' => t('Rooms'),
39 | 'description' => t('Variable examples of different types.'),
40 | 'access' => 'configure room settings',
41 | 'path' => array('admin/rooms/'),
42 | );
43 | return $groups;
44 | }
45 |
46 |
--------------------------------------------------------------------------------
/rooms_three_month_calendar.tpl.php:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
12 |
13 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/rooms_ui.info:
--------------------------------------------------------------------------------
1 | name = Rooms UI
2 | description = Interface support to the Rooms family of modules.
3 | core = 7.x
4 | version = 1.x-dev
5 |
6 | package = Rooms
7 |
8 | dependencies[] = rooms
9 | dependencies[] = variable
10 |
--------------------------------------------------------------------------------
/rooms_ui.module:
--------------------------------------------------------------------------------
1 | 'Rooms',
18 | 'description' => 'Administer Rooms.',
19 | 'page callback' => 'system_admin_menu_block_page',
20 | 'access arguments' => array('access administration pages'),
21 | 'file path' => drupal_get_path('module', 'system'),
22 | 'file' => 'system.admin.inc',
23 | 'weight' => -7,
24 | );
25 | $items['admin/rooms/config'] = array(
26 | 'title' => 'Configuration',
27 | 'description' => 'Configure settings and business rules for Rooms management.',
28 | 'page callback' => 'system_admin_menu_block_page',
29 | 'access arguments' => array('configure room settings'),
30 | 'type' => MENU_NORMAL_ITEM,
31 | 'weight' => 10,
32 | 'file path' => drupal_get_path('module', 'system'),
33 | 'file' => 'system.admin.inc',
34 | );
35 | $items['admin/rooms/config/bookings'] = array(
36 | 'title' => 'Booking Settings',
37 | 'description' => 'Configure settings and business rules for Bookings.',
38 | 'page callback' => 'drupal_get_form',
39 | 'page arguments' => array('rooms_booking_settings'),
40 | 'access arguments' => array('configure room settings'),
41 | 'type' => MENU_NORMAL_ITEM,
42 | );
43 | $items['admin/rooms/config/terminology'] = array(
44 | 'title' => 'Rooms Terminology',
45 | 'description' => 'Change Rooms Terminology',
46 | 'page callback' => 'drupal_get_form',
47 | 'page arguments' => array('variable_group_form', 'rooms'),
48 | 'access arguments' => array('configure room settings'),
49 | );
50 |
51 | return $items;
52 | }
53 |
54 | /**
55 | * Implements hook_page_build().
56 | */
57 | function rooms_ui_page_build(&$page) {
58 | drupal_add_css(drupal_get_path('module', 'rooms_ui') . '/css/rooms_ui.css');
59 | }
60 |
61 | /**
62 | * Main booking settings form.
63 | */
64 | function rooms_booking_settings($form, &$form_state) {
65 | // Management vertical tabs.
66 | $form['rooms_settings'] = array(
67 | '#type' => 'vertical_tabs',
68 | '#weight' => 99,
69 | '#attached' => array(
70 | 'css' => array(
71 | array(
72 | 'data' => '#rooms-booking-settings .vertical-tabs .form-type-textfield input { width: auto; }',
73 | 'type' => 'inline',
74 | ),
75 | ),
76 | ),
77 | );
78 |
79 | $form['rooms_booking_settings'] = array(
80 | '#type' => 'fieldset',
81 | '#group' => 'rooms_settings',
82 | '#title' => t('Rooms booking settings'),
83 | );
84 |
85 | $form['rooms_booking_settings']['rooms_booking_start_date'] = array(
86 | '#type' => 'select',
87 | '#title' => t('How soon a booking can start'),
88 | '#description' => t('Users with the "Make same-day bookings" permission will not be affected by this setting.'),
89 | '#options' => array(
90 | '0' => t('Same day bookings'),
91 | '1' => t('1 day in advance'),
92 | '2' => t('@count days in advance', array('@count' => 2)),
93 | '3' => t('@count days in advance', array('@count' => 3)),
94 | '4' => t('@count days in advance', array('@count' => 4)),
95 | '5' => t('@count days in advance', array('@count' => 5)),
96 | '6' => t('@count days in advance', array('@count' => 6)),
97 | '7' => t('@count days in advance', array('@count' => 7)),
98 | ),
99 | '#default_value' => variable_get('rooms_booking_start_date', 1),
100 | );
101 |
102 | return system_settings_form($form);
103 | }
104 |
105 | /**
106 | * Implements hook_variable_info_alter().
107 | *
108 | * Group all rooms-related variables under a single 'rooms' group.
109 | * This simplifies access control and the Rooms Terminology form.
110 | */
111 | function rooms_ui_variable_info_alter(&$info) {
112 | foreach ($info as $name => $variable) {
113 | if (0 === strpos($name, 'rooms_')) {
114 | $info[$name]['group'] = 'rooms';
115 | }
116 | }
117 | }
118 |
--------------------------------------------------------------------------------
/test/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "require": {
3 | "drupal/drupal-extension": "~3.1"
4 | },
5 | "config": {
6 | "bin-dir": "bin/"
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/test/default.behat.yml:
--------------------------------------------------------------------------------
1 | default:
2 | suites:
3 | default:
4 | contexts:
5 | - FeatureContext
6 | - Drupal\DrupalExtension\Context\DrupalContext
7 | - Drupal\DrupalExtension\Context\MessageContext
8 | - Drupal\DrupalExtension\Context\MinkContext
9 | - Drupal\DrupalExtension\Context\MarkupContext
10 | extensions:
11 | Behat\MinkExtension:
12 | goutte: ~
13 | base_url: http://roomsdemo.local
14 | default_session: goutte
15 | selenium2:
16 | browser: chrome
17 | capabilities: { "browserName": "chrome", "browser": "chrome", 'chrome': {'switches':['--no-sandbox']} }
18 | Drupal\DrupalExtension:
19 | blackbox: ~
20 | api_driver: 'drupal'
21 | drush_driver: 'drush'
22 | drush:
23 | alias: 'rooms.local'
24 | drupal:
25 | drupal_root: '/path/to/drupal'
26 | selectors:
27 | message_selector: '.messages'
28 | error_message_selector: '.messages.error'
29 | success_message_selector: '.messages.status'
30 |
--------------------------------------------------------------------------------
/test/features/availability.feature:
--------------------------------------------------------------------------------
1 | Feature: Once rooms_availability is installed
2 | In order to create bookable units
3 | As a site administrator
4 | I should be able to manage the bookable units availability options
5 |
6 | @api @javascript
7 | Scenario: Availability manager user should be able to modify the availability state of units both in bulk availability page and per unit.
8 | # Creating a unit type and some units.
9 | Given unit types:
10 | | type | label | base_price | min_sleeps | max_sleeps | min_children | max_children |
11 | | standard | Standard | 100 | 2 | 3 | 0 | 1 |
12 |
13 | # Creating a bunch of units programmatically.
14 | Given "standard" units:
15 | | name | default_state |
16 | | Unavailable | 0 |
17 | | Available | 1 |
18 | | On Request | 2 |
19 | | An. Booking | 3 |
20 |
21 | # Checking the initial conditions.
22 | Given the cache has been cleared
23 | And I am logged in as a user with the "access administration pages,view any rooms_unit entity of bundle standard,administer rooms_unit availability,update availability any rooms_unit entity of bundle standard,access availability index service" permissions
24 | Then the state for "Unavailable" between "2016-01-05" and "2016-03-07" should be "0"
25 | And the state for "Available" between "2016-01-05" and "2016-03-07" should be "1"
26 | And the state for "On Request" between "2016-01-05" and "2016-03-07" should be "2"
27 | And the state for "An. Booking" between "2016-01-05" and "2016-03-07" should be "3"
28 |
29 | Given I am on "admin/rooms/units/bulk_unit_management/2016/1"
30 | Then I click "Update Availability"
31 | And I fill in "rooms_start_date[date]" with "19/01/2016"
32 | And I fill in "rooms_end_date[date]" with "23/01/2016"
33 | And I select "On Request" from "change_event_status"
34 | And I select "All (this page)" from "select-all"
35 | And I press the "Update Unit Availability" button
36 |
37 | Then the state for "Available" between "2016-01-19" and "2016-01-23" should be "2"
38 | And the state for "Unavailable" between "2016-01-19" and "2016-01-23" should be "2"
39 | And the state for "On Request" between "2016-01-19" and "2016-01-23" should be "2"
40 | And the state for "An. Booking" between "2016-01-19" and "2016-01-23" should be "2"
41 |
42 | # Checking the single unit availability management page.
43 | Given I am managing the "Unavailable" unit availability
44 | Then I click "Update Unit Availability"
45 | And I fill in "rooms_start_date[date]" with "29/01/2016"
46 | And I fill in "rooms_end_date[date]" with "23/02/2017"
47 | And I select "Available" from "unit_state"
48 | And I press the "Update Availability" button
49 |
50 | Then the state for "Unavailable" between "2016-01-29" and "2017-02-23" should be "1"
51 |
--------------------------------------------------------------------------------
/test/features/availability_constraints.feature:
--------------------------------------------------------------------------------
1 | Feature: Once rooms_availability_constraints is installed
2 | I should be able to create bookable units availability range constrains
3 |
4 | @api @javascript
5 | Scenario: I can create bookable units range constraints.
6 | Given I am logged in as a user with the "administrator" role
7 |
8 | # Creating a unit type and some units.
9 | Given unit types:
10 | | type | label | base_price | min_sleeps | max_sleeps | min_children | max_children |
11 | | standard | Standard | 100 | 2 | 3 | 0 | 1 |
12 |
13 | # Creating a bunch of units programmatically.
14 | Given "standard" units:
15 | | name | base_price |
16 | | Normal | 120 |
17 | | Special | 130 |
18 |
19 | Then I am on "admin/rooms/units/unit-types/manage/standard"
20 | And I check the box "rooms_availability_range_unit"
21 | And I check the box "rooms_availability_range_type"
22 | And I press the "Save unit type" button
23 |
24 | Then I am editing the "Normal" unit
25 | And I add a constraint from "2016-01-03" to "2016-03-03" "must" start on "1"
26 | And I add a constraint from "2016-01-03" to "2016-03-03" "" start on "" and the minimum is "" and the maximum is "5"
27 | And I add a constraint from "2016-03-04" to "2016-06-03" "if" start on "2" and the minimum is "3" and the maximum is ""
28 | And I add a constraint from "2016-03-04" to "2016-06-03" "" start on "" and the minimum is "" and the maximum is "5"
29 | And I add an always constraint where "" start on "" and the minimum is "2" and the maximum is ""
30 | And I press the "Save Unit" button
31 |
32 | Then I will be able to make a booking for "Normal" unit from "2016-01-04" to "2016-01-07"
33 | And I won't be able to make a booking for "Normal" unit from "2016-01-04" to "2016-01-15"
34 | And I won't be able to make a booking for "Normal" unit from "2016-01-05" to "2016-01-08"
35 | And I won't be able to make a booking for "Normal" unit from "2016-03-08" to "2016-03-10"
36 | And I won't be able to make a booking for "Normal" unit from "2016-03-08" to "2016-03-16"
37 | And I will be able to make a booking for "Normal" unit from "2016-03-08" to "2016-03-12"
38 | And I will be able to make a booking for "Normal" unit from "2016-03-09" to "2016-03-12"
39 | And I won't be able to make a booking for "Normal" unit from "2016-10-08" to "2016-10-09"
40 | And I will be able to make a booking for "Normal" unit from "2016-10-08" to "2016-10-19"
41 |
42 | Then I am on "admin/rooms/units/unit-types/manage/standard"
43 |
44 | And I add a constraint from "2016-06-04" to "2016-09-03" "must" start on "3"
45 | And I add a constraint from "2016-06-04" to "2016-09-03" "" start on "" and the minimum is "" and the maximum is "5"
46 | And I add a constraint from "2016-09-04" to "2016-12-03" "if" start on "2" and the minimum is "3" and the maximum is ""
47 | And I add a constraint from "2016-09-04" to "2016-12-03" "" start on "" and the minimum is "" and the maximum is "5"
48 | And I press the "Save unit type" button
49 |
50 | Then I will be able to make a booking for "Special" unit from "2016-08-03" to "2016-08-06"
51 | And I won't be able to make a booking for "Special" unit from "2016-08-03" to "2016-08-14"
52 | And I won't be able to make a booking for "Special" unit from "2016-08-04" to "2016-08-07"
53 | And I will be able to make a booking for "Special" unit from "2016-10-18" to "2016-10-22"
54 | And I won't be able to make a booking for "Special" unit from "2016-10-18" to "2016-10-26"
55 | And I will be able to make a booking for "Special" unit from "2016-10-19" to "2016-10-20"
56 | And I will be able to make a booking for "Special" unit from "2016-10-08" to "2016-10-09"
57 |
58 | Then I won't be able to make a booking for "Normal" unit from "2016-10-08" to "2016-10-19"
59 |
--------------------------------------------------------------------------------
/test/features/availability_filter.feature:
--------------------------------------------------------------------------------
1 | Feature: Availability filter
2 | In order to test overlapping confirmation message
3 |
4 | @api @javascript
5 | Scenario: Placing bookings in cart with the same dates
6 | Given unit types:
7 | | type | label | base_price | min_sleeps | max_sleeps | min_children | max_children |
8 | | standard | Standard | 100 | 2 | 3 | 0 | 1 |
9 |
10 | Given "standard" units:
11 | | name |
12 | | Normal |
13 |
14 | Given CommerceCart Availability Filter is not active
15 |
16 | Given the cache has been cleared
17 |
18 | Given I am logged in as a user with the "access checkout" permission
19 | Then I will be able to make a booking for "Normal" unit from "2016-01-05" to "2016-01-08"
20 |
21 | When I am on "booking/2016-01-05/2016-01-08/1/?rooms_group_size1=2"
22 | Then I select "1" from "standard[300][quantity]"
23 | And I wait for AJAX to finish
24 | And I press "Place Booking"
25 | Then I should see "Booking for Standard (3 Nights; Arrival: 05-01-2016 Departure: 08-01-2016)"
26 | And I should see "$300.00"
27 |
28 | When I am on "booking/2016-01-05/2016-01-08/1/?rooms_group_size1=2"
29 | Then I select "1" from "standard[300][quantity]"
30 | And I wait for AJAX to finish
31 | And I press "Place Booking"
32 | Then I should see "You have a booking request with overlapping dates, continuing will replace it."
33 | And I should see "Go Back to Search"
34 | And I press "Continue"
35 | Then I should see "Booking for Standard (3 Nights; Arrival: 05-01-2016 Departure: 08-01-2016)"
36 | And I should see "$300.00"
37 |
38 | @api @javascript
39 | Scenario: Placing bookings in cart with overlapping dates
40 | Given unit types:
41 | | type | label | base_price | min_sleeps | max_sleeps | min_children | max_children |
42 | | standard | Standard | 100 | 2 | 3 | 0 | 1 |
43 |
44 | Given "standard" units:
45 | | name |
46 | | Normal |
47 |
48 | Given CommerceCart Availability Filter is not active
49 |
50 | Given the cache has been cleared
51 |
52 | Given I am logged in as a user with the "access checkout" permission
53 | Then I will be able to make a booking for "Normal" unit from "2016-01-05" to "2016-01-08"
54 |
55 | When I am on "booking/2016-01-05/2016-01-08/1/?rooms_group_size1=2"
56 | Then I select "1" from "standard[300][quantity]"
57 | And I wait for AJAX to finish
58 | And I press "Place Booking"
59 | Then I should see "Booking for Standard (3 Nights; Arrival: 05-01-2016 Departure: 08-01-2016)"
60 | And I should see "$300.00"
61 |
62 | When I am on "booking/2016-01-03/2016-01-11/1/?rooms_group_size1=2"
63 | Then I select "1" from "standard[800][quantity]"
64 | And I wait for AJAX to finish
65 | And I press "Place Booking"
66 | Then I should see "You have a booking request with overlapping dates, continuing will replace it."
67 | And I should see "Go Back to Search"
68 | And I press "Continue"
69 |
70 | @api @javascript
71 | Scenario: Replacing overlapping bookings
72 | Given unit types:
73 | | type | label | base_price | min_sleeps | max_sleeps | min_children | max_children |
74 | | standard | Standard | 100 | 2 | 3 | 0 | 1 |
75 |
76 | Given "standard" units:
77 | | name |
78 | | Normal |
79 |
80 | Given CommerceCart Availability Filter is not active
81 |
82 | Given the cache has been cleared
83 |
84 | Given I am logged in as a user with the "access checkout" permission
85 | Then I will be able to make a booking for "Normal" unit from "2016-01-05" to "2016-01-08"
86 |
87 | When I am on "booking/2016-01-05/2016-01-08/1/?rooms_group_size1=2"
88 | Then I select "1" from "standard[300][quantity]"
89 | And I wait for AJAX to finish
90 | And I press "Place Booking"
91 | Then I should see "Booking for Standard (3 Nights; Arrival: 05-01-2016 Departure: 08-01-2016)"
92 | And I should see "$300.00"
93 |
94 | When I am on "booking/2016-01-03/2016-01-11/1/?rooms_group_size1=2"
95 | Then I select "1" from "standard[800][quantity]"
96 | And I wait for AJAX to finish
97 | And I press "Place Booking"
98 | Then I should see "You have a booking request with overlapping dates, continuing will replace it."
99 | And I should see "Go Back to Search"
100 | And I press "Continue"
101 | Then I should see "Booking for Standard (8 Nights; Arrival: 03-01-2016 Departure: 11-01-2016)"
102 | And I should see "$800.00"
103 | And I should not see "Booking for Standard (3 Nights; Arrival: 05-01-2016 Departure: 08-01-2016)"
104 | And I should not see "$300.00"
105 |
--------------------------------------------------------------------------------
/test/features/availability_reference.feature:
--------------------------------------------------------------------------------
1 | Feature: Once rooms_availability_reference is installed
2 | In order to create bookable units
3 | As a site administrator
4 | I should be able to add Availability calendars in any entity.
5 |
6 | @api @javascript
7 | Scenario: Admin user should be able to add an availability_calendar in nodes.
8 | Given I am logged in as a user with the "administrator" role
9 |
10 | # Creating a unit type and some units.
11 | Given unit types:
12 | | type | label | base_price | min_sleeps | max_sleeps | min_children | max_children |
13 | | standard | Standard | 100 | 2 | 3 | 0 | 1 |
14 |
15 | # Creating a bunch of units programmatically.
16 | Given "standard" units:
17 | | name | base_price |
18 | | Normal | 120 |
19 | | Special | 130 |
20 |
21 | # Creating a customer profile.
22 | Given customer profiles:
23 | | profile_id | name | country | locality | address | postal_code |
24 | | profile1 | User test 1 | US | Austin | 1900 David St | 78705 |
25 | | profile2 | User test 2 | US | Austin | 1900 David St | 78705 |
26 |
27 | # Creating a booking.
28 | Given "standard_booking" bookings:
29 | | profile_id | guests | children | start_date | end_date | unit | status |
30 | | profile2 | 1 | 1 | 2016-05-19 | 2016-05-23 | Normal | 1 |
31 |
32 | Then the "Normal" unit should be Confirmed by the last booking between "2016-05-19" and "2016-05-22"
33 |
34 | # Creating a booking.
35 | Given "standard_booking" bookings:
36 | | profile_id | guests | children | start_date | end_date | unit | status |
37 | | profile1 | 3 | 0 | 2016-05-19 | 2016-05-23 | Special | 0 |
38 |
39 | Then the "Special" unit should be Unconfirmed by the last booking between "2016-05-19" and "2016-05-22"
40 |
41 | When I add the "availability_ref" availability reference field referencing to "standard" units in "page2" content
42 | Then I should be able to edit a "page2"
43 | And reference units "Normal,Special" in the "availability_ref" field
44 | And I fill in "title" with "asdf"
45 | And I press the "Save" button
46 |
47 | Then I navigate in the fullCalendar to "2016-05"
48 | And I should see the text "User test 2"
49 | And I should see the text "UNCONF"
50 |
--------------------------------------------------------------------------------
/test/features/booking.feature:
--------------------------------------------------------------------------------
1 | Feature: Once rooms_booking correctly installed
2 | In order to create bookings
3 | As a site administrator
4 | I need to be able to access all the Rooms booking configuration screens
5 | And create bookings from scratch
6 |
7 | @api @javascript
8 | Scenario: I can create a booking
9 | Given I am logged in as a user with the "administrator" role
10 |
11 | # Creating a unit type and some units.
12 | Given unit types:
13 | | type | label | base_price | min_sleeps | max_sleeps | min_children | max_children |
14 | | standard | Standard | 100 | 2 | 3 | 0 | 1 |
15 |
16 | # Creating a bunch of units programmatically.
17 | Given "standard" units:
18 | | name | base_price | min_sleeps | max_sleeps |
19 | | Normal | 120 | 1 | 2 |
20 | | Special | 130 | 2 | 3 |
21 |
22 | # Checking that Standard booking type exists.
23 | When I am on "admin/rooms/bookings/booking-types"
24 | Then I should see the text "Standard Booking"
25 |
26 | # Creating a booking and acustomer profile in modal click by click.
27 | When I am on "admin/rooms/bookings"
28 | Then I should see the text "Add a Booking"
29 |
30 | When I click "Add a Booking"
31 | Then I should see the text "Add Standard Booking"
32 |
33 | When I click "create a new profile"
34 | And I wait for AJAX to finish
35 |
36 | Then I fill in "commerce_customer_address[und][0][name_line]" with "User test"
37 | And select "United States" from "commerce_customer_address[und][0][country]"
38 | And I wait for AJAX to finish
39 |
40 | Then I fill in "commerce_customer_address[und][0][thoroughfare]" with "1900 David St"
41 | And I fill in "commerce_customer_address[und][0][locality]" with "Austin"
42 | And select "Texas" from "commerce_customer_address[und][0][administrative_area]"
43 | And I fill in "commerce_customer_address[und][0][postal_code]" with "78705"
44 | And I press the "Save profile" button
45 |
46 | Given I wait for AJAX to finish
47 | Then I fill in "rooms_start_date[date]" with "19/06/2015"
48 | And I fill in "rooms_end_date[date]" with "23/06/2015"
49 | And I press the "Check availability" button
50 | And I wait for AJAX to finish
51 |
52 | Then select "Standard" from "unit_type"
53 | And I wait for AJAX to finish
54 |
55 | Then I should see the text "Normal - Cost: $ 480"
56 | And I should see the text "Special - Cost: $ 520"
57 |
58 | #Playing with the number of guests to check restrictions.
59 | Then select "1" from "data[group_size]"
60 | And I wait for AJAX to finish
61 |
62 | Then I should see the text "Normal - Cost: $ 480"
63 | And I should see the text "Special - Cost: $ 520"
64 |
65 | Then select "3" from "data[group_size]"
66 | And I wait for AJAX to finish
67 |
68 | Then I should not see the text "Normal - Cost: $ 480"
69 | And I should see the text "Special - Cost: $ 520"
70 |
71 | Then select "2" from "data[group_size]"
72 | And I wait for AJAX to finish
73 |
74 | Then I should see the text "Normal - Cost: $ 480"
75 | And I should see the text "Special - Cost: $ 520"
76 |
77 | # Selecting the desired unit.
78 | Then I select the radio button "Normal - Cost: $ 480"
79 | And I wait for AJAX to finish
80 |
81 | Then the "price" field should contain "480.00"
82 | And I press the "Save Booking" button
83 |
84 | # Checking that the unit has been locked.
85 | Then the "Normal" unit should be Unconfirmed by the last booking between "2015-06-19" and "2015-06-23"
86 |
87 | # Editing the booking to mark it as confirmed.
88 | When I am on "admin/rooms/bookings"
89 | Then I should see the text "19-06-2015"
90 | And I should see the text "23-06-2015"
91 | And I should see the text "User test"
92 | And I click "Edit"
93 |
94 | Then the "rooms_start_date[date]" field should contain "19/06/2015"
95 | And the "rooms_end_date[date]" field should contain "23/06/2015"
96 |
97 | Then I check the box "Booking Confirmed"
98 | And I press the "Save Booking" button
99 |
100 | # Checking that the unit has been locked and the booking confirmed..
101 | Then the "Normal" unit should be Confirmed by the last booking between "2015-06-19" and "2015-06-23"
102 |
103 | # Editing the booking and changing the unit assigned.
104 | When I am on "admin/rooms/bookings"
105 | And I click "Edit"
106 |
107 | Then I press the "Re-assign Unit" button
108 | And I wait for AJAX to finish
109 |
110 | Then select "Standard" from "unit_type"
111 | And I wait for AJAX to finish
112 |
113 | Then I select the radio button "Special - Cost: $ 520"
114 | And I wait for AJAX to finish
115 |
116 | Then the "price" field should contain "520.00"
117 | And I press the "Save Booking" button
118 |
119 | # Checking that the prior unit has been released and the new one locked.
120 | Then the "Special" unit should be Confirmed by the last booking between "2015-06-19" and "2015-06-23"
121 | And the state for "Normal" between "2015-06-19" and "2015-06-23" should be "1"
122 |
123 | # Deleting created entities to keep installation clean.
124 | When I am on "admin/rooms/bookings"
125 | And I click "Delete"
126 | Then I press the "Delete" button
127 |
128 | When I am on "admin/commerce/customer-profiles"
129 | And I click "delete"
130 | When I press the "Delete" button
131 | Then I should see the success message "The profile has been deleted."
132 |
133 | @api @javascript
134 | Scenario: I can create a booking programmatically
135 | Given I am logged in as a user with the "administrator" role
136 |
137 | # Creating a unit type and some units.
138 | Given unit types:
139 | | type | label | base_price | min_sleeps | max_sleeps | min_children | max_children |
140 | | standard | Standard | 100 | 2 | 3 | 0 | 1 |
141 |
142 | # Creating a bunch of units programmatically.
143 | Given "standard" units:
144 | | name | base_price |
145 | | Normal | 120 |
146 | | Special | 130 |
147 |
148 | # Creating a customer profile.
149 | Given customer profiles:
150 | | profile_id | name | country | locality | address | postal_code |
151 | | profile1 | User test 1 | US | Austin | 1900 David St | 78705 |
152 | | profile2 | User test 2 | US | Austin | 1900 David St | 78705 |
153 |
154 | # Creating a booking.
155 | Given "standard_booking" bookings:
156 | | profile_id | guests | children | start_date | end_date | unit | status |
157 | | profile2 | 1 | 1 | 2015-05-19 | 2015-05-23 | Normal | 1 |
158 |
159 | Then the "Normal" unit should be Confirmed by the last booking between "2015-05-19" and "2015-05-22"
160 |
161 | # Creating a booking.
162 | Given "standard_booking" bookings:
163 | | profile_id | guests | children | start_date | end_date | unit | status |
164 | | profile1 | 3 | 0 | 2015-05-19 | 2015-05-23 | Special | 0 |
165 |
166 | Then the "Special" unit should be Unconfirmed by the last booking between "2015-05-19" and "2015-05-22"
167 |
--------------------------------------------------------------------------------
/test/features/example.feature:
--------------------------------------------------------------------------------
1 | Feature: Create Example Bookings
2 | In order to create bookings
3 | As a site administrator
4 | I need to be able to access all the Rooms booking configuration screens
5 | And create bookings from scratch
6 |
7 | @api @javascript
8 | Scenario: Bulk creation of units and bookings
9 |
10 | Given customer profiles:
11 | | profile_id | name | country | locality | address | postal_code |
12 | | profile1 | User test 1 | US | Austin | 1900 David St | 78705 |
13 |
14 | Given unit types:
15 | | type | label | base_price | min_sleeps | max_sleeps | min_children | max_children |
16 | | standard | Standard | 100 | 2 | 3 | 0 | 1 |
17 | | special | Special | 120 | 2 | 3 | 0 | 1 |
18 | | deluxe | Deluxe | 150 | 2 | 3 | 0 | 1 |
19 | | suite | Suite | 200 | 2 | 3 | 0 | 1 |
20 | | single | Single | 140 | 1 | 1 | 0 | 1 |
21 |
22 | Given 2 units of type "standard"
23 | Given 2 units of type "special"
24 | Given 2 units of type "deluxe"
25 | Given 2 units of type "suite"
26 | Given 2 units of type "single"
27 |
28 | Given 2 bookings of type "standard_booking" for all "standard" units
29 | Given 2 bookings of type "standard_booking" for all "special" units
30 | Given 2 bookings of type "standard_booking" for all "deluxe" units
31 | Given 2 bookings of type "standard_booking" for all "suite" units
32 | Given 2 bookings of type "standard_booking" for all "single" units
33 |
--------------------------------------------------------------------------------
/test/features/installation.feature:
--------------------------------------------------------------------------------
1 | Feature: Have Rooms correctly installed
2 | In order to use Rooms
3 | As a site administrator
4 | I need to be able to access all the Rooms configuration screens
5 |
6 | @api
7 | Scenario: I can access the Bookable Units interface
8 | Given I am logged in as a user with the "administrator" role
9 | When I am on "admin/rooms"
10 | Then I should see the text "Bookable Units"
11 |
--------------------------------------------------------------------------------
/test/features/pricing.feature:
--------------------------------------------------------------------------------
1 | Feature: Once rooms_pricing is installed
2 | In order to create bookable units
3 | As a site administrator
4 | I should be able to manage the bookable units pricing options
5 |
6 | @api @javascript
7 | Scenario: Availability manager user should be able to modify the pricing of units both in bulk pricing page and per unit.
8 | # Creating a unit type and some units.
9 | Given unit types:
10 | | type | label | base_price | min_sleeps | max_sleeps | min_children | max_children |
11 | | standard | Standard | 100 | 2 | 3 | 0 | 1 |
12 |
13 | # Creating a bunch of units programmatically.
14 | Given "standard" units:
15 | | name | base_price |
16 | | Normal | 120 |
17 | | Special | 130 |
18 |
19 | # Check the initial conditions.
20 | Given the cache has been cleared
21 | And I am logged in as a user with the "access administration pages,view any rooms_unit entity of bundle standard,administer rooms_unit pricing,update pricing any rooms_unit entity of bundle standard,book in advance without limitation,access pricing index service" permissions
22 | Then the price for "Normal" between "2016-05-05" and "2016-07-07" should be "120"
23 | And the price for "Special" between "2016-05-05" and "2016-07-07" should be "130"
24 |
25 | # Check the Add to price operation.
26 | Given I am on "admin/rooms/units/bulk_pricing_management/2016/5"
27 | Then I click "Update Pricing"
28 | And I fill in "rooms_start_date[date]" with "19/05/2016"
29 | And I fill in "rooms_end_date[date]" with "23/05/2016"
30 | And I select "Add to price" from "operation"
31 | And I fill in "amount" with "30"
32 | And I select "All (this page)" from "select-all"
33 | And I press the "Update Unit Pricing" button
34 |
35 | Then the price for "Normal" between "2016-05-19" and "2016-05-23" should be "150"
36 | And the price for "Special" between "2016-05-19" and "2016-05-23" should be "160"
37 |
38 | # Check the Add to price per night operation.
39 | Given I am on "admin/rooms/units/bulk_pricing_management/2016/5"
40 | Then I click "Update Pricing"
41 | And I fill in "rooms_start_date[date]" with "19/05/2016"
42 | And I fill in "rooms_end_date[date]" with "23/05/2016"
43 | And I select "Add to price" from "operation"
44 | And I fill in "amount" with "50"
45 | And I select "All (this page)" from "select-all"
46 | And I press the "Update Unit Pricing" button
47 |
48 | Then the price for "Normal" between "2016-05-19" and "2016-05-23" should be "200"
49 | And the price for "Special" between "2016-05-19" and "2016-05-23" should be "210"
50 |
51 | # Check the Subtract from price operation.
52 | Given I am on "admin/rooms/units/bulk_pricing_management/2016/5"
53 | Then I click "Update Pricing"
54 | And I fill in "rooms_start_date[date]" with "19/05/2016"
55 | And I fill in "rooms_end_date[date]" with "23/05/2016"
56 | And I select "Subtract from price" from "operation"
57 | And I fill in "amount" with "30"
58 | And I select "All (this page)" from "select-all"
59 | And I press the "Update Unit Pricing" button
60 |
61 | Then the price for "Normal" between "2016-05-19" and "2016-05-23" should be "170"
62 | And the price for "Special" between "2016-05-19" and "2016-05-23" should be "180"
63 |
64 | # Check the Subtract from price per night operation.
65 | Given I am on "admin/rooms/units/bulk_pricing_management/2016/5"
66 | Then I click "Update Pricing"
67 | And I fill in "rooms_start_date[date]" with "19/05/2016"
68 | And I fill in "rooms_end_date[date]" with "23/05/2016"
69 | And I select "Subtract from price" from "operation"
70 | And I fill in "amount" with "50"
71 | And I select "All (this page)" from "select-all"
72 | And I press the "Update Unit Pricing" button
73 |
74 | Then the price for "Normal" between "2016-05-19" and "2016-05-23" should be "120"
75 | And the price for "Special" between "2016-05-19" and "2016-05-23" should be "130"
76 |
77 | # Check the Replace price operation.
78 | Given I am on "admin/rooms/units/bulk_pricing_management/2016/5"
79 | Then I click "Update Pricing"
80 | And I fill in "rooms_start_date[date]" with "19/05/2016"
81 | And I fill in "rooms_end_date[date]" with "23/05/2016"
82 | And I select "Replace price" from "operation"
83 | And I fill in "amount" with "150"
84 | And I select "All (this page)" from "select-all"
85 | And I press the "Update Unit Pricing" button
86 |
87 | Then the price for "Normal" between "2016-05-19" and "2016-05-23" should be "150"
88 | And the price for "Special" between "2016-05-19" and "2016-05-23" should be "150"
89 |
90 | # Check the Increase price by % amount operation.
91 | Given I am on "admin/rooms/units/bulk_pricing_management/2016/5"
92 | Then I click "Update Pricing"
93 | And I fill in "rooms_start_date[date]" with "19/05/2016"
94 | And I fill in "rooms_end_date[date]" with "23/05/2016"
95 | And I select "Increase price by % amount" from "operation"
96 | And I fill in "amount" with "20"
97 | And I select "All (this page)" from "select-all"
98 | And I press the "Update Unit Pricing" button
99 |
100 | Then the price for "Normal" between "2016-05-19" and "2016-05-23" should be "180"
101 | And the price for "Special" between "2016-05-19" and "2016-05-23" should be "180"
102 |
103 | # Check the Decrease price by % amount operation.
104 | Given I am on "admin/rooms/units/bulk_pricing_management/2016/5"
105 | Then I click "Update Pricing"
106 | And I fill in "rooms_start_date[date]" with "19/05/2016"
107 | And I fill in "rooms_end_date[date]" with "23/05/2016"
108 | And I select "Decrease price by % amount" from "operation"
109 | And I fill in "amount" with "20"
110 | And I select "All (this page)" from "select-all"
111 | And I press the "Update Unit Pricing" button
112 |
113 | Then the price for "Normal" between "2016-05-19" and "2016-05-23" should be "144"
114 | And the price for "Special" between "2016-05-19" and "2016-05-23" should be "144"
115 |
116 | # Check the day of the week select boxes.
117 | Given I am on "admin/rooms/units/bulk_pricing_management/2016/5"
118 | Then I click "Update Pricing"
119 | And I fill in "rooms_start_date[date]" with "19/05/2016"
120 | And I fill in "rooms_end_date[date]" with "21/05/2016"
121 | And I select "Replace price" from "operation"
122 | And I fill in "amount" with "120"
123 | And I check the box "day_options[2]"
124 | And I check the box "day_options[3]"
125 | And I check the box "day_options[4]"
126 | And I select "All (this page)" from "select-all"
127 | And I press the "Update Unit Pricing" button
128 |
129 | Then the price for "Normal" between "2016-05-19" and "2016-05-21" should be "120"
130 | And the price for "Special" between "2016-05-19" and "2016-05-21" should be "120"
131 | And the price for "Normal" between "2016-05-22" and "2016-05-23" should be "144"
132 | And the price for "Special" between "2016-05-22" and "2016-05-23" should be "144"
133 |
134 | # Check the single unit price management page.
135 | Given I am managing the "Normal" unit pricing
136 | Then I click "Update Unit Pricing"
137 | And I fill in "rooms_start_date[date]" with "29/05/2016"
138 | And I fill in "rooms_end_date[date]" with "23/06/2017"
139 | And I select "Replace price" from "operation"
140 | And I fill in "amount" with "150"
141 | And I press the "Update Unit Pricing" button
142 |
143 | Then the price for "Normal" between "2016-05-29" and "2017-06-23" should be "150"
144 |
--------------------------------------------------------------------------------
/test/features/unit.feature:
--------------------------------------------------------------------------------
1 | Feature: Once rooms_unit is installed
2 | In order to create bookable units
3 | As a site administrator
4 | I should be able to access the unit type and unit edition pages
5 |
6 | @api @javascript
7 | Scenario: Unit type manager can access the Bookable unit types page and create, edit and delete Unit types
8 | Given I am logged in as a user with the "administer rooms_unit_type entities" permission
9 | When I am on "admin/rooms/units/unit-types"
10 | Then I should see the text "Add bookable unit type"
11 | When I click "Add bookable unit type"
12 | Then I am on "admin/rooms/units/unit-types/add"
13 | When I fill in "label" with "Standard"
14 | And I fill in "data[base_price]" with "100"
15 | And I fill in "data[min_sleeps]" with "2"
16 | And I fill in "data[max_sleeps]" with "3"
17 | And I fill in "data[min_children]" with "0"
18 | And I fill in "data[max_children]" with "1"
19 | When I press the "Save unit type" button
20 | Then I should be on "admin/rooms/units/unit-types"
21 | And I should see the text "Standard"
22 | And I should see the text "(Machine name: standard)"
23 | Then I am on "admin/rooms/units/unit-types/manage/standard"
24 | And the "label" field should contain "Standard"
25 | And the "data[base_price]" field should contain "100"
26 | And the "data[min_sleeps]" field should contain "2"
27 | And the "data[max_sleeps]" field should contain "3"
28 | And the "data[min_children]" field should contain "0"
29 | And the "data[max_children]" field should contain "1"
30 | Then I fill in "label" with "Modified value"
31 | And I fill in "data[base_price]" with "1200"
32 | And I fill in "data[min_sleeps]" with "1"
33 | And I fill in "data[max_sleeps]" with "4"
34 | And I fill in "data[min_children]" with "1"
35 | And I fill in "data[max_children]" with "3"
36 | When I press the "Save unit type" button
37 | Then I should be on "admin/rooms/units/unit-types"
38 | When I am on "admin/rooms/units/unit-types/manage/standard"
39 | And the "label" field should contain "Modified value"
40 | And the "data[base_price]" field should contain "1200"
41 | And the "data[min_sleeps]" field should contain "1"
42 | And the "data[max_sleeps]" field should contain "4"
43 | And the "data[min_children]" field should contain "1"
44 | And the "data[max_children]" field should contain "3"
45 | When I am on "admin/rooms/units/unit-types/manage/standard/delete"
46 | And I press the "Confirm" button
47 | Then I should see the message "Deleted Bookable Unit Type Modified value."
48 |
49 | @api @javascript
50 | Scenario: Unit type manager creates two unit types and two unit admin creates and edit it
51 | # Creating a unit type programmatically.
52 | Given unit types:
53 | | type | label | base_price | min_sleeps | max_sleeps | min_children | max_children |
54 | | standard | Standard | 100 | 2 | 3 | 0 | 1 |
55 | | deluxe | Deluxe | 150 | 1 | 2 | 0 | 1 |
56 |
57 | # Standard unit manager manages the unit type.
58 | Given the cache has been cleared
59 | And I am logged in as a user with the "access administration pages,view any rooms_unit entity of bundle standard,create rooms_unit entities of bundle standard,update any rooms_unit entity of bundle standard,delete any rooms_unit entity of bundle standard" permissions
60 | When I am on "admin/rooms/units/add/standard"
61 | Then the "base_price" field should contain "100"
62 | And the "min_sleeps" field should contain "2"
63 | And the "max_sleeps" field should contain "3"
64 | And the "min_children" field should contain "0"
65 | And the "max_children" field should contain "1"
66 | Then I fill in "name" with "Standard one"
67 | And I press the "Save Unit" button
68 | Then I should see the message "Bookable unit Standard one saved"
69 | When I am editing the "Standard one" unit
70 | Then I fill in "name" with "Standard one edited"
71 | And I fill in "base_price" with "150"
72 | And I fill in "min_sleeps" with "3"
73 | And I fill in "max_sleeps" with "8"
74 | And I fill in "min_children" with "1"
75 | And I fill in "max_children" with "4"
76 | And I press the "Save Unit" button
77 | Then I should see the message "Bookable unit Standard one edited saved"
78 | When I am on the "Standard one edited" unit
79 | Then I should see the text "Standard one edited"
80 | When I am editing the "Standard one edited" unit
81 | Then the "base_price" field should contain "150.00"
82 | And the "min_sleeps" field should contain "3"
83 | And the "max_sleeps" field should contain "8"
84 | And the "min_children" field should contain "1"
85 | And the "max_children" field should contain "4"
86 | When I am deleting the "Standard one edited" unit
87 | And I press the "Delete" button
88 | Then I should see the message "The unit Standard one edited has been deleted."
89 |
90 | # Deluxe unit manager manages the unit type.
91 | Given I am logged in as a user with the "access administration pages,view any rooms_unit entity of bundle deluxe,create rooms_unit entities of bundle deluxe,update any rooms_unit entity of bundle deluxe,delete any rooms_unit entity of bundle deluxe" permissions
92 | When I am on "admin/rooms/units/add/deluxe"
93 | Then the "base_price" field should contain "150"
94 | And the "min_sleeps" field should contain "1"
95 | And the "max_sleeps" field should contain "2"
96 | And the "min_children" field should contain "0"
97 | And the "max_children" field should contain "1"
98 | Then I fill in "name" with "Deluxe one"
99 | And I press the "Save Unit" button
100 | Then I should see the message "Bookable unit Deluxe one saved"
101 | When I am editing the "Deluxe one" unit
102 | Then I fill in "name" with "Deluxe one edited"
103 | And I fill in "base_price" with "150"
104 | And I fill in "min_sleeps" with "3"
105 | And I fill in "max_sleeps" with "8"
106 | And I fill in "min_children" with "1"
107 | And I fill in "max_children" with "4"
108 | And I press the "Save Unit" button
109 | Then I should see the message "Bookable unit Deluxe one edited saved"
110 | When I am on the "Deluxe one edited" unit
111 | Then I should see the text "Deluxe one edited"
112 | When I am editing the "Deluxe one edited" unit
113 | Then the "base_price" field should contain "150.00"
114 | And the "min_sleeps" field should contain "3"
115 | And the "max_sleeps" field should contain "8"
116 | And the "min_children" field should contain "1"
117 | And the "max_children" field should contain "4"
118 | When I am deleting the "Deluxe one edited" unit
119 | And I press the "Delete" button
120 | Then I should see the message "The unit Deluxe one edited has been deleted."
121 |
122 | @api @javascript
123 | Scenario: Creating a bunch of units for testing purposes.
124 | # Creating a unit type programmatically.
125 | Given unit types:
126 | | type | label | base_price | min_sleeps | max_sleeps | min_children | max_children |
127 | | standard | Standard | 100 | 2 | 3 | 0 | 1 |
128 |
129 | # Creating a bunch of units programmatically.
130 | Given "standard" units:
131 | | name | base_price | min_sleeps | max_sleeps |
132 | | test1 | 120 | 1 | 2 |
133 | | test2 | 140 | 2 | 4 |
134 |
135 | Given I am logged in as a user with the "administrator" role
136 | When I am on the "test1" unit
137 | Then I should see the text "test1"
138 | When I am on the "test2" unit
139 | Then I should see the text "test2"
140 |
--------------------------------------------------------------------------------