Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature: Persisting appointment price & allowing custom price entry #1479

Open
wants to merge 11 commits into
base: develop
Choose a base branch
from
2 changes: 2 additions & 0 deletions application/controllers/Booking.php
Original file line number Diff line number Diff line change
Expand Up @@ -419,6 +419,8 @@ public function register()
$appointment['id_users_customer'] = $customer_id;
$appointment['is_unavailability'] = false;
$appointment['color'] = $service['color'];
$appointment['price'] = $service['price'];
$appointment['currency'] = $service['currency'];

$appointment_status_options_json = setting('appointment_status_options', '[]');
$appointment_status_options = json_decode($appointment_status_options_json, true) ?? [];
Expand Down
12 changes: 12 additions & 0 deletions application/controllers/Calendar.php
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,11 @@ public function save_appointment()

if ($appointment_data) {
$appointment = $appointment_data;
$service = $this->services_model->find($appointment['id_services']);

if(!$service) {
throw new RuntimeException('Invalid service selection');
}

$required_permissions = !empty($appointment['id'])
? can('add', PRIV_APPOINTMENTS)
Expand Down Expand Up @@ -251,8 +256,15 @@ public function save_appointment()
'id_users_provider',
'id_users_customer',
'id_services',
'price',
'currency',
]);

// Persist price and currency (at time of initial booking creation)
// Fallback to setting the standard service price & currency
$appointment['price'] = $appointment['price'] ?? $service['price'];
$appointment['currency'] = $appointment['currency'] ?? $service['currency'];

$appointment['id'] = $this->appointments_model->save($appointment);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
<?php defined('BASEPATH') or exit('No direct script access allowed');

/* ----------------------------------------------------------------------------
* Easy!Appointments - Open Source Web Scheduler
*
* @package EasyAppointments
* @author A.Tselegidis <alextselegidis@gmail.com>
* @copyright Copyright (c) 2013 - 2020, Alex Tselegidis
* @license http://opensource.org/licenses/GPL-3.0 - GPLv3
* @link http://easyappointments.org
* @since v1.5.0
* ---------------------------------------------------------------------------- */

class Migration_Add_price_column_to_appointments_table extends EA_Migration
{
/**
* Upgrade method.
*/
public function up()
{
if (!$this->db->field_exists('price', 'appointments')) {
$fields = [
'price' => [
'type' => 'DECIMAL',
'constraint' => '10,2',
'null' => true,
'after' => 'status',
],
'currency' => [
'type' => 'VARCHAR',
'constraint' => '32',
'null' => true,
],
];

$this->dbforge->add_column('appointments', $fields);

// Update existing records
$sql = "UPDATE `" . $this->db->dbprefix('appointments') . "` AS `appointments`
JOIN `" . $this->db->dbprefix('services') . "` AS `services` ON `appointments`.`id_services` = `services`.`id`
SET `appointments`.`price` = `services`.`price`,
`appointments`.`currency` = `services`.`currency`";

$this->db->query($sql);

}
}

/**
* Downgrade method.
*/
public function down()
{
if ($this->db->field_exists('price', 'appointments')) {
$this->dbforge->drop_column('appointments', 'price');
$this->dbforge->drop_column('appointments', 'currency');
}
}
}
30 changes: 30 additions & 0 deletions application/models/Appointments_model.php
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ class Appointments_model extends EA_Model
'color' => 'color',
'status' => 'status',
'notes' => 'notes',
'price' => 'price',
'currency' => 'currency',
'hash' => 'hash',
'serviceId' => 'id_services',
'providerId' => 'id_users_provider',
Expand All @@ -61,6 +63,24 @@ public function save(array $appointment): int
{
$this->validate($appointment);

// If not passed, take from service
if (!isset($appointment['price']) || !isset($appointment['currency'])) {

$service = $this->services_model->find($appointment['id_services']);

if (!$service) {
throw new InvalidArgumentException('The provided service ID was not found in the database: ' . $appointment['id_services']);
}

if (!isset($appointment['price'])) {
$appointment['price'] = $service['price'];
}

if (!isset($appointment['currency'])) {
$appointment['currency'] = $service['currency'];
}
}

if (empty($appointment['id'])) {
return $this->insert($appointment);
} else {
Expand Down Expand Up @@ -539,6 +559,8 @@ public function api_encode(array &$appointment)
'status' => $appointment['status'],
'location' => $appointment['location'],
'notes' => $appointment['notes'],
'price' => $appointment['price'],
'currency' => $appointment['currency'],
'customerId' => $appointment['id_users_customer'] !== null ? (int) $appointment['id_users_customer'] : null,
'providerId' => $appointment['id_users_provider'] !== null ? (int) $appointment['id_users_provider'] : null,
'serviceId' => $appointment['id_services'] !== null ? (int) $appointment['id_services'] : null,
Expand Down Expand Up @@ -591,6 +613,14 @@ public function api_decode(array &$appointment, array $base = null)
$decoded_request['notes'] = $appointment['notes'];
}

if (array_key_exists('price', $appointment)) {
$decoded_request['price'] = $appointment['price'];
}

if (array_key_exists('currency', $appointment)) {
$decoded_request['currency'] = $appointment['currency'];
}

if (array_key_exists('customerId', $appointment)) {
$decoded_request['id_users_customer'] = $appointment['customerId'];
}
Expand Down
28 changes: 28 additions & 0 deletions application/views/components/appointments_modal.php
Original file line number Diff line number Diff line change
Expand Up @@ -342,6 +342,34 @@ class="<?= $require_notes ? 'required' : '' ?> form-control"></textarea>
</div>
</div>
</fieldset>

<hr>

<fieldset>

<div class="row">
<div class="col-6">
<div class="mb-3">
<label for="appointment-price" class="form-label">
<?= lang('price') ?>
</label>
<input type="text" id="appointment-price"
class="form-control"
maxlength="100"/>
</div>
</div>
<div class="col-6">
<div class="mb-3">
<label for="appointment-currency" class="form-label">
<?= lang('currency') ?>
</label>
<input type="text" id="appointment-currency"
class="form-control"
maxlength="100"/>
</div>
</div>
</div>
</fieldset>
</form>
</div>

Expand Down
13 changes: 11 additions & 2 deletions assets/js/components/appointments_modal.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ App.Components.AppointmentsModal = (function () {
const $appointmentId = $('#appointment-id');
const $appointmentLocation = $('#appointment-location');
const $appointmentStatus = $('#appointment-status');
const $appointmentPrice = $('#appointment-price');
const $appointmentCurrency = $('#appointment-currency');
const $appointmentColor = $('#appointment-color');
const $appointmentNotes = $('#appointment-notes');
const $reloadAppointments = $('#reload-appointments');
Expand Down Expand Up @@ -102,6 +104,8 @@ App.Components.AppointmentsModal = (function () {
color: App.Components.ColorSelection.getColor($appointmentColor),
status: $appointmentStatus.val(),
notes: $appointmentNotes.val(),
price: $appointmentPrice.val(),
currency: $appointmentCurrency.val(),
is_unavailability: Number(false),
};

Expand Down Expand Up @@ -365,8 +369,13 @@ App.Components.AppointmentsModal = (function () {
return Number(availableService.id) === Number(serviceId);
});

if (service?.color) {
App.Components.ColorSelection.getColor($appointmentColor, service.color);
if (service) {
if (service.color) {
App.Components.ColorSelection.getColor($appointmentColor, service.color);
}

$appointmentCurrency.val(service.currency);
$appointmentPrice.val(service.price);
}

const duration = service ? service.duration : 60;
Expand Down
4 changes: 4 additions & 0 deletions assets/js/utils/calendar_default_view.js
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,8 @@ App.Utils.CalendarDefaultView = (function () {
$appointmentsModal.find('#appointment-location').val(appointment.location);
$appointmentsModal.find('#appointment-status').val(appointment.status);
$appointmentsModal.find('#appointment-notes').val(appointment.notes);
$appointmentsModal.find('#appointment-price').val(appointment.price);
$appointmentsModal.find('#appointment-currency').val(appointment.currency);
$appointmentsModal.find('#customer-notes').val(customer.notes);
$appointmentsModal.find('#custom-field-1').val(customer.custom_field_1);
$appointmentsModal.find('#custom-field-2').val(customer.custom_field_2);
Expand Down Expand Up @@ -1617,6 +1619,8 @@ App.Utils.CalendarDefaultView = (function () {
$appointmentsModal.find('#appointment-location').val(appointment.location);
$appointmentsModal.find('#appointment-status').val(appointment.status);
$appointmentsModal.find('#appointment-notes').val(appointment.notes);
$appointmentsModal.find('#appointment-price').val(appointment.price);
$appointmentsModal.find('#appointment-currency').val(appointment.currency);
$appointmentsModal.find('#customer-notes').val(customer.notes);
$appointmentsModal.find('#custom-field-1').val(customer.custom_field_1);
$appointmentsModal.find('#custom-field-2').val(customer.custom_field_2);
Expand Down
2 changes: 2 additions & 0 deletions assets/js/utils/calendar_table_view.js
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,8 @@ App.Utils.CalendarTableView = (function () {
$appointmentsModal.find('#appointment-location').val(appointment.location);
$appointmentsModal.find('#appointment-status').val(appointment.status);
$appointmentsModal.find('#appointment-notes').val(appointment.notes);
$appointmentsModal.find('#appointment-price').val(appointment.price);
$appointmentsModal.find('#appointment-currency').val(appointment.currency);
$appointmentsModal.find('#customer-notes').val(customer.notes);
$appointmentsModal.find('#custom-field-1').val(customer.custom_field_1);
$appointmentsModal.find('#custom-field-2').val(customer.custom_field_2);
Expand Down
4 changes: 3 additions & 1 deletion docs/rest-api.md
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,9 @@ You can also try the GET requests with your browser by navigating to the respect
"id": 1,
"book": "2016-07-08 12:57:00",
"start": "2016-07-08 18:00:00",
"end": "2016-07-08 18:30:00",
"end": "2016-07-08 18:30:00",
"price": "10",
"currency": "USD",
"hash": "apTWVbSvBJXR",
"location": "Test Street 1A, 12345 Some State, Some Place"
"notes": "This is a test appointment.",
Expand Down
12 changes: 12 additions & 0 deletions openapi.yml
Original file line number Diff line number Diff line change
Expand Up @@ -1794,6 +1794,10 @@ components:
type: string
notes:
type: string
price:
type: string
currency:
type: string
customerId:
type: integer
providerId:
Expand All @@ -1812,6 +1816,8 @@ components:
color: '#123456'
status: Booked
notes: This is a test appointment.
price: 10
currency: USD
customerId: 5
providerId: 2
serviceId: 6
Expand All @@ -1831,6 +1837,10 @@ components:
type: string
notes:
type: string
price:
type: string
currency:
type: string
customerId:
type: integer
providerId:
Expand All @@ -1844,6 +1854,8 @@ components:
color: '#123456'
status: Booked
notes: This is a test appointment.
price: 10
currency: USD
customerId: 5
providerId: 2
serviceId: 6
Expand Down