HEX
Server: Apache/2.4.52 (Ubuntu)
System: Linux spn-python 5.15.0-89-generic #99-Ubuntu SMP Mon Oct 30 20:42:41 UTC 2023 x86_64
User: arjun (1000)
PHP: 8.1.2-1ubuntu2.20
Disabled: NONE
Upload Files
File: /var/www/html/appointmentbook.me/wp-content/plugins/booknetic-customer-panel/App/Frontend/Ajax.php
<?php

namespace BookneticAddon\Customerpanel\Frontend;

use BookneticAddon\Customerpanel\CustomerPanelHelper;
use BookneticApp\Backend\Appointments\Helpers\AppointmentService;
use BookneticApp\Backend\Appointments\Helpers\CalendarService;
use BookneticApp\Models\Appointment;
use BookneticApp\Models\AppointmentPrice;
use BookneticApp\Models\AppointmentExtra;
use BookneticApp\Models\Customer;
use BookneticApp\Models\Service;
use BookneticApp\Providers\Common\PaymentGatewayService;
use BookneticApp\Providers\Core\FrontendAjax;
use BookneticApp\Providers\DB\DB;
use BookneticApp\Providers\Helpers\Date;
use BookneticApp\Providers\Helpers\Helper;
use BookneticApp\Providers\Core\Permission;
use function BookneticAddon\Customerpanel\bkntc__;

class Ajax extends FrontendAjax
{

    public function save_profile()
    {
        if( ! CustomerPanelHelper::canUseCustomerPanel() )
        {
            return $this->response( false );
        }

        $name		=	Helper::_post('name', '', 'str');
        $surname	=	Helper::_post('surname', '', 'str');
        $email		=	Helper::_post('email', '', 'str');
        $phone		=	Helper::_post('phone', '', 'str');
        $birthdate	=	Helper::_post('birthdate', '', 'str');
        $gender		=	Helper::_post('gender', '', 'str', ['', 'male', 'female']);

        if( empty( $name ) || empty( $surname ) || empty( $email ) || empty( $phone ) || ( ! empty( $birthdate ) && ! Date::isValid( $birthdate ) ) )
        {
            return $this->response( false, bkntc__('Please fill all required fields!') );
        }

	    /**
	     * Eger email deyishibse o halda wp_users`de de deyishsin emaili.
	     */
        if( $email != CustomerPanelHelper::myCustomer()->email )
        {
	        if ( ! filter_var( $email, FILTER_VALIDATE_EMAIL ) )
	        {
		        return $this->response(false, bkntc__('Please enter a valid email address!') );
	        }

	        $checkIfEmailAlreadyExist = Customer::where('email', $email)->fetch();

	        if( $checkIfEmailAlreadyExist || email_exists( $email ) )
	        {
		        return $this->response(false, bkntc__('This email address is already used by another customer.') );
	        }

	        wp_update_user([
		        'ID'         => Permission::userId(),
		        'user_email' => $email
	        ]);
        }

        Customer::where('user_id', Permission::userId())->noTenant()->update([
            'first_name'		=>	trim( $name ),
            'last_name'			=>	trim( $surname ),
            'phone_number'		=>	$phone,
            'email'				=>	$email,
            'gender'			=>	$gender,
            'birthdate'			=>	empty( $birthdate ) ? null : Date::dateSQL( $birthdate )
        ]);

        wp_update_user([
            'ID' => Permission::userId(),
            'first_name' => trim($name),
            'last_name'	=>	trim( $surname )
        ]);

        return $this->response( true, ['message' => bkntc__('Profile data was saved successfully')] );
    }

    public function change_password()
    {
        if( ! CustomerPanelHelper::canUseCustomerPanel() )
        {
            return $this->response( false );
        }

        $old_password			=	Helper::_post('old_password', '', 'str');
        $new_password			=	Helper::_post('new_password', '', 'str');
        $repeat_new_password	=	Helper::_post('repeat_new_password', '', 'str');

        if( $new_password != $repeat_new_password || empty( $new_password ) )
        {
            return $this->response( false, bkntc__('Password does not match!') );
        }

        $userId = Permission::userId();

        $userInf = get_user_by('id', $userId);
        if( $userInf && !wp_check_password( $old_password, $userInf->data->user_pass, $userId ) )
        {
            return $this->response( false, bkntc__('Current password is wrong!') );
        }

        wp_set_password( $new_password, $userId );

        do_action( 'bkntc_customer_reset_password', Customer::select([ 'id' ])->where('user_id', $userId)->fetch()->id );

        return $this->response( true, ['message' => bkntc__('Password was changed successfully')] );
    }

    public function reschedule_appointment()
    {
	    if ( ! CustomerPanelHelper::canUseCustomerPanel() )
	    {
		    return $this->response( false );
	    }

        $appointment_id	=	Helper::_post('id', '', 'int');
        $date			=	Helper::_post('date', '', 'str');
        $time			=	Helper::_post('time', '', 'str');

        $date = Date::reformatDateFromCustomFormat( $date );// doit: Customer panelde ele bil yigishdirmishdiq format meselesini?

        $newD = new \DateTime(Date::dateTimeSQL($date . ' ' .$time), Date::getTimeZone(Helper::getOption('client_timezone_enable', 'off') == 'on') );
        $newD->setTimezone(Date::getTimeZone());
        $date = $newD->format('Y-m-d');
        $time = $newD->format('H:i');

        $appointmentInfo = Appointment::noTenant()->get( $appointment_id );
        if ( Helper::isSaaSVersion() )
        {
            Permission::setTenantId( $appointmentInfo->tenant_id );
        }

        $allowedRescheduleStatuses = Helper::getOption('customer_panel_reschedule_allowed_status', '');
        $allowedRescheduleStatuses = explode(',', $allowedRescheduleStatuses);

        if ( ! preg_match( '/^[0-9]{2}:[0-9]{2}$/', $time ) )
        {
            return $this->response( false, bkntc__( 'Time format is wrong.' ) );
        }

        if ( Date::epoch() >= Date::epoch( $date . ' ' . $time . ':00' ) )
        {
            return $this->response( false, bkntc__( 'You can not change the date and time to past.' ) );
        }

        if ( ! $appointmentInfo || ! in_array( $appointmentInfo->customer_id, CustomerPanelHelper::myCustomersIDs() ) )
        {
            return $this->response( false );
        }

	    if ( Helper::getOption( 'customer_panel_allow_reschedule', 'on' ) != 'on' )
	    {
		    return $this->response( false );
	    }

        if ( ! in_array($appointmentInfo->status, $allowedRescheduleStatuses) && !empty($allowedRescheduleStatuses) )
        {
            return $this->response( false );
        }

        $minute = Helper::getOption( 'time_restriction_to_make_changes_on_appointments', '5' );
        $beforeThisTime = Helper::getMinTimeRequiredPriorBooking( $appointmentInfo->service_id, '5' );

        if ( Date::epoch( '+' . $minute . ' minutes' ) > Date::epoch( $appointmentInfo->starts_at ) )
        {
            return $this->response( false, bkntc__( 'Minimum time requirement prior to change the appointment date and time is %s', [ Helper::secFormatWithName( $minute * 60 ) ] ) );
        }

        $before = Date::epoch( '+' . $beforeThisTime . ' minutes' );

        if ( $before > Date::epoch( $date . ' ' . $time . ':00' ) )
        {
            return $this->response( false, bkntc__( 'You cannot change the appointment less than %s in advance', [ Helper::secFormatWithName( $beforeThisTime * 60 ) ] ) );
        }

        if ( Date::dateSQL( $appointmentInfo->date ) == Date::dateSQL( $date ) && Date::timeSQL( $appointmentInfo->start_time ) == Date::timeSQL( $time ) )
        {
            return $this->response( false, bkntc__( 'You have not changed the date and time.' ) );
        }

        try
        {
	        AppointmentService::reschedule( $appointment_id, $date, $time );

            return $this->response( true, [
                'message' => bkntc__( 'Appointment was rescheduled successfully!' ),
            ]);
        }
        catch ( \Exception $e )
        {
        	return $this->response( false, $e->getMessage() );
        }
    }

    public function get_allowed_statuses()
    {
	    if( ! CustomerPanelHelper::myCustomersIDs() )
	    {
		    return $this->response( false );
	    }

        $appointment_id	    = Helper::_post('id', 0, 'int');
        $appointmentInf     = Appointment::noTenant()->where('id', $appointment_id )->fetch();

	    if ( ! $appointmentInf || ! in_array( $appointmentInf->customer_id, CustomerPanelHelper::myCustomersIDs() ) )
	    {
		    return $this->response( false );
	    }

	    if( Helper::isSaaSVersion() )
	    {
		    Permission::setTenantId( $appointmentInf->tenant_id );
	    }

        $statuses = Helper::getOption('customer_panel_allowed_status', '');
        $statusesArray = explode(',', $statuses);
        $status = $appointmentInf->status;
        $dataForReturn = [];

        foreach ( Helper::getAppointmentStatuses() AS $statusKey => $statusVal )
        {
            if( ! in_array( $statusKey, $statusesArray ) || $status === $statusKey)
            {
                continue;
            }

            $dataForReturn[] = [
                'id'=>$statusKey,
                'text' =>$statusVal['title']
            ];
        }

        return $this->response(true, [ 'results' => $dataForReturn ] );
    }

    public function get_allowed_payment_gateways()
    {
	    if( ! CustomerPanelHelper::myCustomersIDs() )
	    {
		    return $this->response( false );
	    }

        $appointment_id	    = Helper::_post('id', 0, 'int');
        $appointmentInf     = Appointment::noTenant()->where('id', $appointment_id )->fetch();

	    if ( ! $appointmentInf || ! in_array( $appointmentInf->customer_id, CustomerPanelHelper::myCustomersIDs() ) )
	    {
		    return $this->response( false );
	    }

	    if( Helper::isSaaSVersion() )
	    {
		    Permission::setTenantId( $appointmentInf->tenant_id );
	    }

        $serviceCustomMethods = Service::getData($appointmentInf->service_id , 'custom_payment_methods');
        $serviceCustomMethods = json_decode($serviceCustomMethods,true);
        if( empty( $serviceCustomMethods ) )
        {
            $paymentMethods = PaymentGatewayService::getEnabledGatewayNames();
        }else
        {
            $paymentMethods = $serviceCustomMethods;
        }

        $totalPrice = AppointmentPrice::where('appointment_id', $appointmentInf->id )
            ->select('sum(price * negative_or_positive) as total_price', true)->fetch()->total_price;
        if( $totalPrice == $appointmentInf->paid_amount )
            $paymentMethods = [];

        $dataForReturn = [];
        foreach ( $paymentMethods AS $paymentMethod )
        {
            $paymentMethodService = PaymentGatewayService::find( $paymentMethod );

            if( ! property_exists( $paymentMethodService, 'createPaymentLink' ) )
                continue;

            $dataForReturn[] = [
                'id'=>$paymentMethod,
                'text' => $paymentMethodService->getTitle()
            ];
        }

        return $this->response(true, [ 'results' => $dataForReturn ] );
    }

    public function change_appointment_status()
    {
	    if( ! CustomerPanelHelper::canUseCustomerPanel() )
	    {
		    return $this->response( false );
	    }

        $appointment_id	            = Helper::_post('id', 0, 'int');
        $appointment_status         = Helper::_post('status', '', 'string');
	    $appointmentInf             = Appointment::noTenant()->where('id', $appointment_id )->fetch();

	    if( ! $appointmentInf || ! in_array( $appointmentInf->customer_id, CustomerPanelHelper::myCustomersIDs() ) )
	    {
		    return $this->response( false );
	    }

	    if( Helper::isSaaSVersion() )
	    {
		    Permission::setTenantId( $appointmentInf->tenant_id );
	    }

		if ( ! CustomerPanelHelper::canChangeAppointmentStatus( $appointmentInf ) )
		{
			return $this->response(false, bkntc__('Time limit to change appointment status expired'));
		}

        $statuses = Helper::getOption( 'customer_panel_allowed_status', '' );
        $statusesArray = explode(',', $statuses);
        $status = $appointmentInf->status;

        if ( ! in_array( $appointment_status ,$statusesArray )  )
        {
            return $this->response(false, bkntc__('Invalid appointment status') );
        }
        else if ( $status === $appointment_status )
        {
            return $this->response(false, bkntc__('Change current status before save') );
        }

        AppointmentService::setStatus($appointmentInf->id, $appointment_status);

        return $this->response(true, [
			'message' => bkntc__('Appointment status changed to %s', [ Helper::appointmentStatus( $appointment_status )[ 'title' ] ])
        ] );
    }

    public function create_payment_link()
    {
        if( Helper::getOption('hide_pay_now_btn_customer_panel', 'off')=='on' )
            return $this->response(false);

	    if( ! CustomerPanelHelper::canUseCustomerPanel() )
	    {
		    return $this->response( false );
	    }

        $appointment_id	            = Helper::_post('id', 0, 'int');
        $paymentMethod              = Helper::_post('payment_method', '', 'string');
	    $appointmentInf             = Appointment::noTenant()->where('id', $appointment_id )->fetch();

	    if( ! $appointmentInf || ! in_array( $appointmentInf->customer_id, CustomerPanelHelper::myCustomersIDs() ) )
	    {
		    return $this->response( false );
	    }

	    if( Helper::isSaaSVersion() )
	    {
		    Permission::setTenantId( $appointmentInf->tenant_id );
	    }

        $serviceCustomMethods = Service::getData($appointmentInf->service_id , 'custom_payment_methods');
        $serviceCustomMethods = json_decode($serviceCustomMethods,true);

        if( empty( $serviceCustomMethods ) )
        {
            $paymentMethods = PaymentGatewayService::getEnabledGatewayNames();
        }else
        {
            $paymentMethods = $serviceCustomMethods;
        }
        $paymentMethods = array_filter($paymentMethods , function ($paymentMethod){
           return $paymentMethod != 'local';
        });

        if ( ! in_array( $paymentMethod ,$paymentMethods )  )
        {
            return $this->response(false, bkntc__('Invalid payment method') );
        }

        $totalAmountQuery = AppointmentPrice::where('appointment_id', DB::field( Appointment::getField('id') ))
            ->select('sum(price * negative_or_positive)', true);

        $appointments = Appointment::leftJoin('customer', ['first_name', 'last_name', 'email', 'profile_image', 'phone_number'])
            ->leftJoin('staff', ['name', 'profile_image'])
            ->leftJoin('location', ['name'])
            ->leftJoin('service', ['name'])
            ->where(Appointment::getField('id') , $appointment_id )
            ->selectSubQuery( $totalAmountQuery, 'total_price' );

        $appointment = $appointments->fetch();

        $paymentGatewayService = PaymentGatewayService::find( $paymentMethod );

        if(! property_exists( $paymentGatewayService  ,'createPaymentLink'))
        {
            return $this->response(false);
        }

        $data = $paymentGatewayService->createPaymentLink([$appointment]);

        if( ! isset( $data->data['url'] ) )
            return $this->response(false);

        return $this->response(true, [
			'url' => $data->data[ 'url' ],
            'id' => $appointment->id
        ] );
    }

    public function get_available_times_of_appointment()
    {
        if( ! CustomerPanelHelper::canUseCustomerPanel() )
        {
            return $this->response( false );
        }

        $appointmentId = Helper::_post( 'id', 0, 'int' );
        $search        = Helper::_post( 'q', '', 'string' );
        $date		   = Helper::_post( 'date', '', 'string' );

        $date = Date::reformatDateFromCustomFormat( $date );// doit: Customer panelde ele bil yigishdirmishdiq format meselesini?

        $appointmentInf = Appointment::noTenant()->get( $appointmentId );

        if( ! $appointmentInf || ! in_array( $appointmentInf->customer_id, CustomerPanelHelper::myCustomersIDs() ) )
        {
            return $this->response( false );
        }

        $customerId = $appointmentInf->customer_id;
        $staff	    = $appointmentInf->staff_id;
        $service    = $appointmentInf->service_id;

        if( Helper::isSaaSVersion() )
        {
            Permission::setTenantId( $appointmentInf->tenant_id );
        }

        if( Helper::getOption('customer_panel_allow_reschedule', 'on') != 'on' )
        {
            return $this->response( false );
        }

        $extras_arr = [];
        $appointmentExtras = AppointmentExtra::where('appointment_id', $appointmentInf->id)->fetchAll();
        foreach ( $appointmentExtras AS $extra )
        {
            $extra_inf = $extra->extra()->fetch();
            $extra_inf['quantity'] = $extra['quantity'];
            $extra_inf['customer'] = $customerId;

            $extras_arr[] = $extra_inf;
        }

        $date = Date::dateSQL( $date );

        $serviceInf  = apply_filters( 'bkntc_set_service_duration_frontend', Service::get( $service ), $appointmentId );

	    $calendarData = new CalendarService( $date );
	    $calendarData->setStaffId( $staff )
	                 ->setLocationId( $appointmentInf->location_id )
	                 ->setServiceInf( $serviceInf )
	                 ->setServiceExtras( $extras_arr )
	                 ->setExcludeAppointmentId( $appointmentInf->id )
	                 ->setShowExistingTimeSlots( true );
	    $calendarData = $calendarData->getCalendar();

        $data = $calendarData['dates'];

        if( ! isset( $data[ $date ] ) )
            return $this->response(true, [ 'results' => [] ] );

        return $this->response(true, [ 'results' => $this->getDataForReturn( $data[ $date ], $search ) ] );
    }

    private function getDataForReturn( $data, $search )
    {
        $dataForReturn = [];

        foreach ( $data AS $dataInf )
        {
            $startTime = $dataInf[ 'start_time_format' ];

            if( ! empty( $search ) && strpos( $startTime, $search ) === false )
                continue;

            $clientTime = $dataInf[ 'start_time_format' ];
            $text       = $clientTime . ( $dataInf[ 'weight' ] > 0 && $dataInf[ 'max_capacity' ] > 1 ? ' [ ' . ( int ) $dataInf[ 'weight' ] . '/' . ( int ) $dataInf[ 'max_capacity' ] . ' ]' : '' );

            $result = [
                'id'		   => $clientTime,
                'text'		   => $text,
                'max_capacity' => $dataInf[ 'max_capacity' ],
                'weight'       => $dataInf[ 'weight' ]
            ];

            $dataForReturn[] = apply_filters( 'bkntc_customer_panel_render_date_time', $result, $dataInf );
        }

        return $dataForReturn;
    }

    public function delete_profile()
    {
        if( ! CustomerPanelHelper::canUseCustomerPanel() )
        {
            return $this->response( false );
        }

        if( Helper::getOption('customer_panel_allow_delete_account', 'on', false) != 'on' )
        {
            return $this->response( false );
        }

        Customer::where('user_id', Permission::userId())->noTenant()->update([
            'user_id'		=>	null,
            'first_name'	=>	'[-] ID: ' . CustomerPanelHelper::myCustomer()->id,
            'last_name'		=>	'',
            'phone_number'	=>	'',
            'email'			=>	'',
            'birthdate'		=>	null,
            'gender'		=>	'',
            'notes'			=>	'',
            'profile_image'	=>	''
        ]);

	    require_once ABSPATH . 'wp-admin/includes/user.php';

        wp_logout();
        wp_delete_user( Permission::userId() );

        return $this->response( true, ['redirect_url' => site_url('/')] );
    }

	public function get_appointments_list()
	{
		$totalPricesSubQuery = AppointmentPrice::where('appointment_id', DB::field( Appointment::getField('id') ))->select('sum(price * negative_or_positive)');

		$appointments = Appointment::noTenant()
		                           ->leftJoin('service', 'name')
		                           ->leftJoin('staff', ['name', 'profile_image'])
		                           ->where(Appointment::getField('customer_id'), CustomerPanelHelper::myCustomersIDs())
		                           ->selectSubQuery($totalPricesSubQuery, 'total_price')
		                           ->orderBy(Appointment::getField('id')." desc")
                                   ->fetchAll();

		foreach ( $appointments AS $appointment )
		{
			Permission::setTenantId( $appointment->tenant_id );
			$allStatuses = Helper::getAppointmentStatuses();

			if ( array_key_exists($appointment->status, $allStatuses) )
			{
				$status = $allStatuses[$appointment->status];
			}
			else
			{
				$status = ['title' => $appointment->status, 'color' => '#000'];
			}

			$appointment->status_text = $status['title'];
			$appointment->status_color = $status['color'];
		}

		return $this->response( true, [
			'list_html'  =>  Helper::renderView( __DIR__ . '/view/appointments_list.php', [ 'appointments' => $appointments ] )
		] );
	}

    public function get_available_dates()
    {
        if( ! CustomerPanelHelper::canUseCustomerPanel() )
        {
            return $this->response( false );
        }

        $appointment_id	    = Helper::_post('appointment_id', 0, 'int');
        $month			    = Helper::_post('current_month', '', 'string');
        $year			    = Helper::_post('current_year', '', 'string');
        $startDate = new \DateTime("$year-$month-01");
        $endDate = clone $startDate;
        $startDate  = $startDate->format('Y-m-d');
        $endDate    = $endDate->modify('+1 months')->format('Y-m-d');

        $appointmentInf = Appointment::noTenant()->get( $appointment_id );


        if( ! $appointmentInf || ! in_array( $appointmentInf->customer_id, CustomerPanelHelper::myCustomersIDs() ) )
        {
            return $this->response( false );
        }

        $customer_id    = $appointmentInf->customer_id;
        $staff			= $appointmentInf->staff_id;
        $service		= $appointmentInf->service_id;

        if( Helper::isSaaSVersion() )
        {
            Permission::setTenantId( $appointmentInf->tenant_id );
        }

        if( Helper::getOption('customer_panel_allow_reschedule', 'on') != 'on' )
        {
            return $this->response( false );
        }

        $extras_arr = [];
        $appointmentExtras = AppointmentExtra::where('appointment_id', $appointmentInf->id)->fetchAll();
        foreach ( $appointmentExtras AS $extra )
        {
            $extra_inf = $extra->extra()->fetch();
            $extra_inf['quantity'] = $extra['quantity'];
            $extra_inf['customer'] = $customer_id;

            $extras_arr[] = $extra_inf;
        }

        $startDate = Date::dateSQL( $startDate );
        $endDate = Date::dateSQL( $endDate );

        $serviceInf  = apply_filters( 'bkntc_set_service_duration_frontend', Service::get( $service ), $appointmentInf->id );

        $calendarData = new CalendarService( $startDate , $endDate );
        $calendarData->setStaffId( $staff )
            ->setLocationId( $appointmentInf->location_id )
            ->setServiceInf( $serviceInf )
            ->setServiceExtras( $extras_arr )
            ->setExcludeAppointmentId( $appointmentInf->id )
            ->setShowExistingTimeSlots( true );
        $calendarData = $calendarData->getCalendar();

        $availableDates = array_keys( array_filter($calendarData['dates'], function ($item)
        {
            return ! empty($item);
        }));

        $format = Helper::isSaaSVersion() ? 'Y-m-d' : null;
        $availableDates = array_map(function ($availableDate) use($format){
           return Date::convertDateFormat($availableDate , $format );
        },$availableDates);

        return $this->response(true, [ 'available_dates' => $availableDates ] );
    }


}