Booking product type added
|
|
@ -101,7 +101,8 @@
|
||||||
"Webkul\\CartRule\\": "packages/Webkul/CartRule/src",
|
"Webkul\\CartRule\\": "packages/Webkul/CartRule/src",
|
||||||
"Webkul\\Rule\\": "packages/Webkul/Rule/src",
|
"Webkul\\Rule\\": "packages/Webkul/Rule/src",
|
||||||
"Webkul\\CMS\\": "packages/Webkul/CMS/src",
|
"Webkul\\CMS\\": "packages/Webkul/CMS/src",
|
||||||
"Webkul\\Velocity\\": "packages/Webkul/Velocity/src"
|
"Webkul\\Velocity\\": "packages/Webkul/Velocity/src",
|
||||||
|
"Webkul\\BookingProduct\\": "packages/Webkul/BookingProduct/src"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -265,6 +265,7 @@ return [
|
||||||
Webkul\Rule\Providers\RuleServiceProvider::class,
|
Webkul\Rule\Providers\RuleServiceProvider::class,
|
||||||
Webkul\CMS\Providers\CMSServiceProvider::class,
|
Webkul\CMS\Providers\CMSServiceProvider::class,
|
||||||
Webkul\Velocity\Providers\VelocityServiceProvider::class,
|
Webkul\Velocity\Providers\VelocityServiceProvider::class,
|
||||||
|
Webkul\BookingProduct\Providers\BookingProductServiceProvider::class,
|
||||||
],
|
],
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@ return [
|
||||||
\Webkul\User\Providers\ModuleServiceProvider::class,
|
\Webkul\User\Providers\ModuleServiceProvider::class,
|
||||||
\Webkul\CatalogRule\Providers\ModuleServiceProvider::class,
|
\Webkul\CatalogRule\Providers\ModuleServiceProvider::class,
|
||||||
\Webkul\CartRule\Providers\ModuleServiceProvider::class,
|
\Webkul\CartRule\Providers\ModuleServiceProvider::class,
|
||||||
\Webkul\CMS\Providers\ModuleServiceProvider::class
|
\Webkul\CMS\Providers\ModuleServiceProvider::class,
|
||||||
|
\Webkul\BookingProduct\Providers\ModuleServiceProvider::class
|
||||||
]
|
]
|
||||||
];
|
];
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
/node_modules
|
||||||
|
/package-lock.json
|
||||||
|
npm-debug.log
|
||||||
|
|
@ -0,0 +1,22 @@
|
||||||
|
{
|
||||||
|
"private": true,
|
||||||
|
"scripts": {
|
||||||
|
"dev": "npm run development",
|
||||||
|
"development": "cross-env NODE_ENV=development node_modules/webpack/bin/webpack.js --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js",
|
||||||
|
"watch": "cross-env NODE_ENV=development node_modules/webpack/bin/webpack.js --watch --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js",
|
||||||
|
"watch-poll": "cross-env npm run watch -- --watch-poll --progress",
|
||||||
|
"hot": "cross-env NODE_ENV=development node_modules/webpack-dev-server/bin/webpack-dev-server.js --inline --hot --config=node_modules/laravel-mix/setup/webpack.config.js",
|
||||||
|
"prod": "npm run production",
|
||||||
|
"production": "cross-env NODE_ENV=production node_modules/webpack/bin/webpack.js --no-progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"axios": "^0.19.0",
|
||||||
|
"cross-env": "^6.0.3",
|
||||||
|
"jquery": "^3.4.1",
|
||||||
|
"laravel-mix": "^5.0.0",
|
||||||
|
"laravel-mix-merge-manifest": "^0.1.2",
|
||||||
|
"sass": "^1.25.0",
|
||||||
|
"sass-loader": "^8.0.2",
|
||||||
|
"vue": "^2.6.10"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
.bp-location-icon{background-image:url(../images/location.svg);width:32px;height:32px}.bp-slot-icon{background-image:url(../images/slot.svg);width:32px;height:32px}.bp-phone-icon{background-image:url(../images/phone.svg);width:32px;height:32px}.booking-information{margin-bottom:15px;border-top:1px solid #e8e8e8;padding-top:15px}.booking-information .booking-info-row{padding-left:32px;margin-bottom:20px;position:relative}.booking-information .booking-info-row .icon{position:absolute;left:0;top:-4px}.booking-information .booking-info-row .title{color:#5e5e5e;display:block;margin-bottom:5px}.booking-information .booking-info-row .value{display:block;margin-bottom:5px}.booking-information .booking-info-row .value .text-danger{color:#ff5656}.booking-information .booking-info-row .toggle{color:#0041ff;cursor:pointer;-webkit-touch-callout:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.booking-information .booking-info-row .toggle .icon{position:relative;width:10px;height:10px;margin-left:5px;top:0}.booking-information .booking-info-row .toggle .icon.arrow-down-icon{background-image:url(../images/arrow-down.svg)!important}.booking-information .booking-info-row .toggle .icon.arrow-up-icon{background-image:url(../images/arrow-up.svg)!important}.booking-information .booking-info-row .days-availability table{margin-top:10px;border-collapse:collapse}.booking-information .booking-info-row .days-availability table tr td{padding:5px;vertical-align:top}.booking-information .booking-info-row .days-availability table tr td:first-child{padding-left:0}.booking-information .booking-info-row .days-availability table tr td:last-child{font-size:14px;padding-left:15px;padding-right:0;color:#5e5e5e}.booking-information .booking-info-row .days-availability table tr td .text-danger{color:#ff5656}.booking-information .book-slots{padding-top:25px;display:inline-block;width:100%;border-top:1px solid #e8e8e8}.booking-information .book-slots h3{font-weight:600;font-size:16px;color:#242424;margin-top:0}.booking-information .book-slots label{color:#3a3a3a}.booking-information .book-slots .control-group label{font-size:16px}.booking-information .book-slots .control-group .radio{display:inline-block}.booking-information .book-slots .control-group-container{width:100%;float:left}.booking-information .book-slots .control-group-container .control-group:not(.quantity){width:50%;float:left}.booking-information .book-slots .control-group-container .control-group:not(.quantity) .control{width:100%}.booking-information .book-slots .control-group-container .control-group:not(.quantity).date{padding-right:5px}.booking-information .book-slots .control-group-container .control-group:not(.quantity).date:after{position:absolute;top:14px;right:10px}.booking-information .book-slots .control-group-container .control-group:not(.quantity).slots:first-child{padding-right:5px}.booking-information .book-slots .control-group-container .control-group:not(.quantity).slots:last-child{padding-left:5px}.booking-information .book-slots .ticket-list .ticket-item{width:100%;display:inline-block;padding:16px 0;border-bottom:1px solid #e8e8e8}.booking-information .book-slots .ticket-list .ticket-item .ticket-info{width:50%;float:left}.booking-information .book-slots .ticket-list .ticket-item .ticket-info .ticket-name{color:#242424;margin-bottom:12px}.booking-information .book-slots .ticket-list .ticket-item .ticket-info .ticket-price{color:#5e5e5e}.booking-information .book-slots .ticket-list .ticket-item .ticket-quantity{width:50%;display:inline-block}.booking-information .book-slots .ticket-list .ticket-item .ticket-quantity .control-group{margin:0}.booking-information .book-slots .ticket-list .ticket-item p{color:#242424;margin-bottom:0;font-weight:400}.booking-information .book-slots .ticket-total{font-size:16px;font-weight:600;color:#242424;padding-top:16px}.booking-information .book-slots .ticket-total>div{margin-bottom:12px}.booking-information .book-slots .ticket-total>div:last-child{margin-bottom:0}.booking-information .book-slots .ticket-total>div p{color:#242424;font-weight:400;margin-top:4px}
|
||||||
|
|
@ -0,0 +1,10 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<svg width="8px" height="8px" viewBox="0 0 8 8" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||||
|
<!-- Generator: Sketch 51.1 (57501) - http://www.bohemiancoding.com/sketch -->
|
||||||
|
<title>icon-dropdown</title>
|
||||||
|
<desc>Created with Sketch.</desc>
|
||||||
|
<defs></defs>
|
||||||
|
<g id="icon-dropdown" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||||
|
<polygon id="›" fill="#242424" transform="translate(4.000000, 4.514496) rotate(-270.000000) translate(-4.000000, -4.514496) " points="1.48080444 8.51449585 4.54690552 4.51449585 1.48080444 0.51449585 3.48550415 0.51449585 6.51919556 4.51449585 3.48550415 8.51449585"></polygon>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 745 B |
|
|
@ -0,0 +1,10 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<svg width="8px" height="8px" viewBox="0 0 8 8" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||||
|
<!-- Generator: Sketch 50 (54983) - http://www.bohemiancoding.com/sketch -->
|
||||||
|
<title>icon-dropdown-up</title>
|
||||||
|
<desc>Created with Sketch.</desc>
|
||||||
|
<defs></defs>
|
||||||
|
<g id="icon-dropdown-up" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||||
|
<polygon id="›" fill="#242424" transform="translate(4.000000, 3.519196) scale(1, -1) rotate(-270.000000) translate(-4.000000, -3.519196) " points="1.48080444 7.51919556 4.54690552 3.51919556 1.48080444 -0.480804443 3.48550415 -0.480804443 6.51919556 3.51919556 3.48550415 7.51919556"></polygon>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 766 B |
|
|
@ -0,0 +1,11 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<svg width="32px" height="32px" viewBox="0 0 32 32" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||||
|
<!-- Generator: Sketch 51.1 (57501) - http://www.bohemiancoding.com/sketch -->
|
||||||
|
<title>tab/heading/icon/address</title>
|
||||||
|
<desc>Created with Sketch.</desc>
|
||||||
|
<defs></defs>
|
||||||
|
<g id="tab/heading/icon/address" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||||
|
<path d="M15.5,23.897235 C20.2087657,20.0716385 22.5,16.8805311 22.5,14.5 C22.5,10.6340068 19.3659932,7.5 15.5,7.5 C11.6340068,7.5 8.5,10.6340068 8.5,14.5 C8.5,16.8805311 10.7912343,20.0716385 15.5,23.897235 Z" id="Oval" stroke="#242424" stroke-width="3"></path>
|
||||||
|
<circle id="Oval-2" fill="#242424" cx="15.5" cy="14.5" r="2.5"></circle>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 835 B |
|
|
@ -0,0 +1,18 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<svg width="24px" height="24px" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||||
|
<!-- Generator: Sketch 51.1 (57501) - http://www.bohemiancoding.com/sketch -->
|
||||||
|
<title>icon-menu copy</title>
|
||||||
|
<desc>Created with Sketch.</desc>
|
||||||
|
<defs></defs>
|
||||||
|
<g id="icon-menu-copy" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" stroke-linecap="round">
|
||||||
|
<g id="Group-3" transform="translate(7.000000, 5.000000)" stroke="#242424" stroke-width="3">
|
||||||
|
<g id="Group-2">
|
||||||
|
<g id="Group">
|
||||||
|
<path d="M0,1 C0,6.2 2.66666667,10.5333333 8,14" id="Path-24"></path>
|
||||||
|
<path d="M0,0.860920013 L3.33066907e-16,0.860920013 C0.692541156,0.399225909 1.62823371,0.58636442 2.08992781,1.27890558 C2.0981214,1.29119595 2.10613384,1.30360612 2.11396256,1.31613206 L2.36753004,1.72184003 C2.99745806,2.72972486 2.84834566,4.03901444 2.00791685,4.87944325 L1.29138002,5.59598008" id="Path-25" fill="#242424"></path>
|
||||||
|
<path d="M8.63269516,13.7386314 L5,10.4383311 L5.96373991,10.125193 C7.09411415,9.75791214 8.32839532,10.2194571 8.94044595,11.2382972 L9.18681717,11.648415 C9.19442371,11.6610771 9.20184367,11.6738503 9.20907467,11.6867306 C9.61652862,12.4125102 9.35847472,13.3311774 8.63269516,13.7386314 Z" id="Path-25" stroke-linejoin="round"></path>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1.5 KiB |
|
|
@ -0,0 +1,15 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<svg width="32px" height="32px" viewBox="0 0 32 32" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||||
|
<!-- Generator: Sketch 51.1 (57501) - http://www.bohemiancoding.com/sketch -->
|
||||||
|
<title>tab/heading/icon/calender</title>
|
||||||
|
<desc>Created with Sketch.</desc>
|
||||||
|
<defs></defs>
|
||||||
|
<g id="tab/heading/icon/calender" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||||
|
<g id="Group" transform="translate(7.000000, 8.000000)" stroke="#242424" stroke-width="3">
|
||||||
|
<rect id="Rectangle-10" x="1.5" y="1.5" width="16" height="13"></rect>
|
||||||
|
</g>
|
||||||
|
<rect id="Rectangle" fill="#242424" x="7" y="13" width="19" height="3" rx="1.5"></rect>
|
||||||
|
<rect id="Rectangle-2" fill="#242424" x="11" y="5" width="3" height="6"></rect>
|
||||||
|
<rect id="Rectangle-2-Copy" fill="#242424" x="19" y="5" width="3" height="6"></rect>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 957 B |
|
|
@ -0,0 +1,3 @@
|
||||||
|
{
|
||||||
|
"/css/booking-product.css": "/css/booking-product.css?id=083d9215be8e5552a0e7"
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,10 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
return [
|
||||||
|
'booking' => [
|
||||||
|
'key' => 'booking',
|
||||||
|
'name' => 'Booking',
|
||||||
|
'class' => 'Webkul\BookingProduct\Type\Booking',
|
||||||
|
'sort' => 7
|
||||||
|
]
|
||||||
|
];
|
||||||
|
|
@ -0,0 +1,7 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Webkul\BookingProduct\Contracts;
|
||||||
|
|
||||||
|
interface BookingProduct
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,7 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Webkul\BookingProduct\Contracts;
|
||||||
|
|
||||||
|
interface BookingProductAppointmentSlot
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,7 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Webkul\BookingProduct\Contracts;
|
||||||
|
|
||||||
|
interface BookingProductDefaultSlot
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,7 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Webkul\BookingProduct\Contracts;
|
||||||
|
|
||||||
|
interface BookingProductEventSlot
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,7 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Webkul\BookingProduct\Contracts;
|
||||||
|
|
||||||
|
interface BookingProductRentalSlot
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,7 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Webkul\BookingProduct\Contracts;
|
||||||
|
|
||||||
|
interface BookingProductTableSlot
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,37 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
|
||||||
|
class CreateBookingProductsTable extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function up()
|
||||||
|
{
|
||||||
|
Schema::create('booking_products', function (Blueprint $table) {
|
||||||
|
$table->increments('id');
|
||||||
|
$table->string('type');
|
||||||
|
$table->string('location')->nullable();
|
||||||
|
$table->boolean('show_location')->default(0);
|
||||||
|
|
||||||
|
$table->integer('product_id')->unsigned();
|
||||||
|
$table->foreign('product_id')->references('id')->on('products')->onDelete('cascade');
|
||||||
|
$table->timestamps();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function down()
|
||||||
|
{
|
||||||
|
Schema::dropIfExists('booking_products');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,39 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
|
||||||
|
class CreateBookingProductDefaultSlotsTable extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function up()
|
||||||
|
{
|
||||||
|
Schema::create('booking_product_default_slots', function (Blueprint $table) {
|
||||||
|
$table->increments('id');
|
||||||
|
$table->string('booking_type');
|
||||||
|
$table->date('available_from')->nullable();
|
||||||
|
$table->date('available_to')->nullable();
|
||||||
|
$table->integer('duration')->nullable();
|
||||||
|
$table->integer('break_time')->nullable();
|
||||||
|
$table->json('slots')->nullable();
|
||||||
|
|
||||||
|
$table->integer('booking_product_id')->unsigned();
|
||||||
|
$table->foreign('booking_product_id')->references('id')->on('booking_products')->onDelete('cascade');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function down()
|
||||||
|
{
|
||||||
|
Schema::dropIfExists('booking_product_default_slots');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,41 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
|
||||||
|
class CreateBookingProductAppointmentSlotsTable extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function up()
|
||||||
|
{
|
||||||
|
Schema::create('booking_product_appointment_slots', function (Blueprint $table) {
|
||||||
|
$table->increments('id');
|
||||||
|
$table->integer('duration')->nullable();
|
||||||
|
$table->integer('break_time')->nullable();
|
||||||
|
$table->boolean('available_every_week')->nullable();
|
||||||
|
$table->date('available_from')->nullable();
|
||||||
|
$table->date('available_to')->nullable();
|
||||||
|
$table->boolean('slot_has_quantity')->nullable();
|
||||||
|
$table->boolean('same_slot_all_days')->nullable();
|
||||||
|
$table->json('slots')->nullable();
|
||||||
|
|
||||||
|
$table->integer('booking_product_id')->unsigned();
|
||||||
|
$table->foreign('booking_product_id')->references('id')->on('booking_products')->onDelete('cascade');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function down()
|
||||||
|
{
|
||||||
|
Schema::dropIfExists('booking_product_appointment_slots');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,36 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
|
||||||
|
class CreateBookingProductEventSlotsTable extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function up()
|
||||||
|
{
|
||||||
|
Schema::create('booking_product_event_slots', function (Blueprint $table) {
|
||||||
|
$table->increments('id');
|
||||||
|
$table->datetime('available_from')->nullable();
|
||||||
|
$table->datetime('available_to')->nullable();
|
||||||
|
$table->json('slots')->nullable();
|
||||||
|
|
||||||
|
$table->integer('booking_product_id')->unsigned();
|
||||||
|
$table->foreign('booking_product_id')->references('id')->on('booking_products')->onDelete('cascade');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function down()
|
||||||
|
{
|
||||||
|
Schema::dropIfExists('booking_product_event_slots');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,42 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
|
||||||
|
class CreateBookingProductRentalSlotsTable extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function up()
|
||||||
|
{
|
||||||
|
Schema::create('booking_product_rental_slots', function (Blueprint $table) {
|
||||||
|
$table->increments('id');
|
||||||
|
$table->string('renting_type');
|
||||||
|
$table->decimal('daily_price', 12, 4)->default(0)->nullable();;
|
||||||
|
$table->decimal('hourly_price', 12, 4)->default(0)->nullable();;
|
||||||
|
$table->boolean('available_every_week')->nullable();
|
||||||
|
$table->date('available_from')->nullable();
|
||||||
|
$table->date('available_to')->nullable();
|
||||||
|
$table->boolean('slot_has_quantity')->nullable();
|
||||||
|
$table->boolean('same_slot_all_days')->nullable();
|
||||||
|
$table->json('slots')->nullable();
|
||||||
|
|
||||||
|
$table->integer('booking_product_id')->unsigned();
|
||||||
|
$table->foreign('booking_product_id')->references('id')->on('booking_products')->onDelete('cascade');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function down()
|
||||||
|
{
|
||||||
|
Schema::dropIfExists('booking_product_rental_slots');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,43 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
|
||||||
|
class CreateBookingProductTableSlotsTable extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function up()
|
||||||
|
{
|
||||||
|
Schema::create('booking_product_table_slots', function (Blueprint $table) {
|
||||||
|
$table->increments('id');
|
||||||
|
$table->string('price_type');
|
||||||
|
$table->integer('guest_limit')->default(0);
|
||||||
|
$table->integer('duration');
|
||||||
|
$table->integer('break_time');
|
||||||
|
$table->integer('prevent_scheduling_before');
|
||||||
|
$table->boolean('available_every_week')->nullable();
|
||||||
|
$table->date('available_from')->nullable();
|
||||||
|
$table->date('available_to')->nullable();
|
||||||
|
$table->boolean('same_slot_all_days')->nullable();
|
||||||
|
$table->json('slots')->nullable();
|
||||||
|
|
||||||
|
$table->integer('booking_product_id')->unsigned();
|
||||||
|
$table->foreign('booking_product_id')->references('id')->on('booking_products')->onDelete('cascade');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function down()
|
||||||
|
{
|
||||||
|
Schema::dropIfExists('booking_product_table_slots');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Webkul\BookingProduct\Helpers;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* AppointmentSlot Helper
|
||||||
|
*
|
||||||
|
* @author Jitendra Singh <jitendra@webkul.com>
|
||||||
|
* @copyright 2018 Webkul Software Pvt Ltd (http://www.webkul.com)
|
||||||
|
*/
|
||||||
|
class AppointmentSlot extends Booking
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,276 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Webkul\BookingProduct\Helpers;
|
||||||
|
|
||||||
|
use Carbon\Carbon;
|
||||||
|
use Webkul\BookingProduct\Repositories\BookingProductDefaultSlotRepository;
|
||||||
|
use Webkul\BookingProduct\Repositories\BookingProductAppointmentSlotRepository;
|
||||||
|
use Webkul\BookingProduct\Repositories\BookingProductEventSlotRepository;
|
||||||
|
use Webkul\BookingProduct\Repositories\BookingProductRentalSlotRepository;
|
||||||
|
use Webkul\BookingProduct\Repositories\BookingProductTableSlotRepository;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Booking Helper
|
||||||
|
*
|
||||||
|
* @author Jitendra Singh <jitendra@webkul.com>
|
||||||
|
* @copyright 2018 Webkul Software Pvt Ltd (http://www.webkul.com)
|
||||||
|
*/
|
||||||
|
class Booking
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
protected $typeRepositories = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
protected $daysOfWeek = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new helper instance.
|
||||||
|
*
|
||||||
|
* @param Webkul\BookingProduct\Repositories\BookingProductDefaultSlotRepository $bookingProductDefaultSlotRepository
|
||||||
|
* @param Webkul\BookingProduct\Repositories\BookingProductAppointmentSlotRepository $bookingProductAppointmentSlotRepository
|
||||||
|
* @param Webkul\BookingProduct\Repositories\BookingProductEventSlotRepository $bookingProductEventSlotRepository
|
||||||
|
* @param Webkul\BookingProduct\Repositories\BookingProductRentalSlotRepository $bookingProductRentalSlotRepository
|
||||||
|
* @param Webkul\BookingProduct\Repositories\BookingProductTableSlotRepository $bookingProductTableSlotRepository
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function __construct(
|
||||||
|
BookingProductDefaultSlotRepository $bookingProductDefaultSlotRepository,
|
||||||
|
BookingProductAppointmentSlotRepository $bookingProductAppointmentSlotRepository,
|
||||||
|
BookingProductEventSlotRepository $bookingProductEventSlotRepository,
|
||||||
|
BookingProductRentalSlotRepository $bookingProductRentalSlotRepository,
|
||||||
|
BookingProductTableSlotRepository $bookingProductTableSlotRepository
|
||||||
|
)
|
||||||
|
{
|
||||||
|
$this->typeRepositories['default'] = $bookingProductDefaultSlotRepository;
|
||||||
|
|
||||||
|
$this->typeRepositories['appointment'] = $bookingProductAppointmentSlotRepository;
|
||||||
|
|
||||||
|
$this->typeRepositories['event'] = $bookingProductEventSlotRepository;
|
||||||
|
|
||||||
|
$this->typeRepositories['rental'] = $bookingProductRentalSlotRepository;
|
||||||
|
|
||||||
|
$this->typeRepositories['table'] = $bookingProductTableSlotRepository;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the booking information
|
||||||
|
*
|
||||||
|
* @param BookingProduct $bookingProduct
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getWeekSlotDurations($bookingProduct)
|
||||||
|
{
|
||||||
|
$slotsByDays = [];
|
||||||
|
|
||||||
|
$bookingProductSlot = $this->typeRepositories[$bookingProduct->type]->findOneByField('booking_product_id', $bookingProduct->id);
|
||||||
|
|
||||||
|
$availabileDays = $this->getAvailableWeekDays($bookingProductSlot);
|
||||||
|
|
||||||
|
foreach ($this->daysOfWeek as $index => $isOpen) {
|
||||||
|
$slots = [];
|
||||||
|
|
||||||
|
if ($isOpen)
|
||||||
|
$slots = $bookingProductSlot->same_slot_all_days ? $bookingProductSlot->slots : ($bookingProductSlot->slots[$index] ?? []);
|
||||||
|
|
||||||
|
$slotsByDays[] = [
|
||||||
|
'name' => trans($this->daysOfWeek[$index]),
|
||||||
|
'slots' => isset($availabileDays[$index]) ? $this->conver24To12Hours($slots) : []
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
return $slotsByDays;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns html of slots for a current day
|
||||||
|
*
|
||||||
|
* @param BookingProduct $bookingProduct
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getTodaySlotsHtml($bookingProduct)
|
||||||
|
{
|
||||||
|
$slots = [];
|
||||||
|
|
||||||
|
foreach ($this->getTodaySlots($bookingProduct) as $slot) {
|
||||||
|
$slots[] = $slot['from'] . ' - ' . $slot['to'];
|
||||||
|
}
|
||||||
|
|
||||||
|
return count($slots)
|
||||||
|
? implode(' | ', $slots)
|
||||||
|
: '<span class="text-danger">' . trans('bookingproduct::app.shop.products.closed') . '</span>';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns slots for a current day
|
||||||
|
*
|
||||||
|
* @param BookingProduct $bookingProduct
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getTodaySlots($bookingProduct)
|
||||||
|
{
|
||||||
|
$weekSlots = $this->getWeekSlotDurations($bookingProduct);
|
||||||
|
|
||||||
|
return $weekSlots[Carbon::now()->format('w')]['slots'];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the available week days
|
||||||
|
*
|
||||||
|
* @param Object $bookingProductSlot
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getAvailableWeekDays($bookingProductSlot)
|
||||||
|
{
|
||||||
|
if ($bookingProductSlot->available_every_week)
|
||||||
|
return $this->daysOfWeek;
|
||||||
|
|
||||||
|
$days = [];
|
||||||
|
|
||||||
|
$currentTime = Carbon::now();
|
||||||
|
|
||||||
|
$availableFrom = Carbon::createFromTimeString($bookingProductSlot->available_from . " 00:00:01");
|
||||||
|
|
||||||
|
$availableTo = Carbon::createFromTimeString($bookingProductSlot->available_to . " 23:59:59");
|
||||||
|
|
||||||
|
for ($i = 0; $i < 7; $i++) {
|
||||||
|
$date = clone $currentTime;
|
||||||
|
$date->addDays($i);
|
||||||
|
|
||||||
|
if ($date >= $availableFrom && $date <= $availableTo)
|
||||||
|
$days[$i] = $date->format('l');
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->sortDaysOfWeek($days);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sort days
|
||||||
|
*
|
||||||
|
* @param array $days
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function sortDaysOfWeek($days)
|
||||||
|
{
|
||||||
|
$daysAux = [];
|
||||||
|
|
||||||
|
foreach ($days as $day) {
|
||||||
|
$key = array_search($day, $this->daysOfWeek);
|
||||||
|
|
||||||
|
if ($key !== FALSE) {
|
||||||
|
$daysAux[$key] = $day;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ksort($daysAux);
|
||||||
|
|
||||||
|
return $daysAux;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert time from 24 to 12 hour format
|
||||||
|
*
|
||||||
|
* @param array $slots
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function conver24To12Hours($slots)
|
||||||
|
{
|
||||||
|
if (! $slots)
|
||||||
|
return [];
|
||||||
|
|
||||||
|
foreach ($slots as $index => $slot) {
|
||||||
|
$slots[$index]['from'] = Carbon::createFromTimeString($slot['from'])->format("h:i a");
|
||||||
|
$slots[$index]['to'] = Carbon::createFromTimeString($slot['to'])->format("h:i a");
|
||||||
|
}
|
||||||
|
|
||||||
|
return $slots;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns slots for a perticular day
|
||||||
|
*
|
||||||
|
* @param BookingProduct $bookingProduct
|
||||||
|
* @param string $date
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getSlotsByDate($bookingProduct, $date)
|
||||||
|
{
|
||||||
|
$bookingProductSlot = $this->typeRepositories[$bookingProduct->type]->findOneByField('booking_product_id', $bookingProduct->id);
|
||||||
|
|
||||||
|
if (! is_array($bookingProductSlot->slots) || ! count($bookingProductSlot->slots))
|
||||||
|
return [];
|
||||||
|
|
||||||
|
$requestedDate = Carbon::createFromTimeString($date . " 00:00:00");
|
||||||
|
|
||||||
|
$currentTime = Carbon::now();
|
||||||
|
|
||||||
|
$availableFrom = ! $bookingProductSlot->available_every_week
|
||||||
|
? Carbon::createFromTimeString($bookingProductSlot->available_from . " 00:00:00")
|
||||||
|
: Carbon::createFromTimeString($currentTime->format('Y-m-d') . ' 00:00:00');
|
||||||
|
|
||||||
|
$availableTo = ! $bookingProductSlot->available_every_week
|
||||||
|
? Carbon::createFromTimeString($bookingProductSlot->available_to . ' 23:59:59')
|
||||||
|
: Carbon::createFromTimeString('2080-01-01 00:00:00');
|
||||||
|
|
||||||
|
$timeDurations = $bookingProductSlot->same_slot_all_days
|
||||||
|
? $bookingProductSlot->slots
|
||||||
|
: ($bookingProductSlot->slots[$requestedDate->format('w')] ?? []);
|
||||||
|
|
||||||
|
$slots = [];
|
||||||
|
|
||||||
|
foreach ($timeDurations as $timeDuration) {
|
||||||
|
$fromChunks = explode(':', $timeDuration['from']);
|
||||||
|
$toChunks = explode(':', $timeDuration['to']);
|
||||||
|
|
||||||
|
$startDayTime = Carbon::createFromTimeString($requestedDate->format('Y-m-d') . ' 00:00:00');
|
||||||
|
$startDayTime->addMinutes(($fromChunks[0] * 60) + $fromChunks[1]);
|
||||||
|
$tempStartDayTime = clone $startDayTime;
|
||||||
|
|
||||||
|
$endDayTime = Carbon::createFromTimeString($requestedDate->format('Y-m-d') . ' 00:00:00');
|
||||||
|
$endDayTime->addMinutes(($toChunks[0] * 60) + $toChunks[1]);
|
||||||
|
|
||||||
|
$isFirstIteration = true;
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
$from = clone $tempStartDayTime;
|
||||||
|
$tempStartDayTime->addMinutes($bookingProductSlot->duration);
|
||||||
|
|
||||||
|
if ($isFirstIteration) {
|
||||||
|
$isFirstIteration = false;
|
||||||
|
} else {
|
||||||
|
$from->modify('+' . $bookingProductSlot->break_time . ' minutes');
|
||||||
|
$tempStartDayTime->modify('+' . $bookingProductSlot->break_time . ' minutes');
|
||||||
|
}
|
||||||
|
|
||||||
|
$to = clone $tempStartDayTime;
|
||||||
|
|
||||||
|
if (($startDayTime <= $from && $from <= $availableTo)
|
||||||
|
&& ($availableTo >= $to && $to >= $startDayTime)
|
||||||
|
&& ($startDayTime <= $from && $from <= $endDayTime)
|
||||||
|
&& ($endDayTime >= $to && $to >= $startDayTime)) {
|
||||||
|
|
||||||
|
// Get already ordered qty for this slot
|
||||||
|
$orderedQty = 0;
|
||||||
|
|
||||||
|
$qty = isset($timeDuration['qty']) ? ( $timeDuration['qty'] - $orderedQty ) : 1;
|
||||||
|
|
||||||
|
if ($qty && $currentTime <= $from) {
|
||||||
|
$slots[] = [
|
||||||
|
'from' => $from->format('h:i A'),
|
||||||
|
'to' => $to->format('h:i A'),
|
||||||
|
'timestamp' => $from->getTimestamp() . '-' . $to->getTimestamp(),
|
||||||
|
'qty' => $qty,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $slots;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,154 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Webkul\BookingProduct\Helpers;
|
||||||
|
|
||||||
|
use Carbon\Carbon;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DefaultSlot Helper
|
||||||
|
*
|
||||||
|
* @author Jitendra Singh <jitendra@webkul.com>
|
||||||
|
* @copyright 2018 Webkul Software Pvt Ltd (http://www.webkul.com)
|
||||||
|
*/
|
||||||
|
class DefaultSlot extends Booking
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
protected $daysOfWeek = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns slots for a perticular day
|
||||||
|
*
|
||||||
|
* @param BookingProduct $bookingProduct
|
||||||
|
* @param string $date
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getSlotsByDate($bookingProduct, $date)
|
||||||
|
{
|
||||||
|
$bookingProductSlot = $this->typeRepositories[$bookingProduct->type]->findOneByField('booking_product_id', $bookingProduct->id);
|
||||||
|
|
||||||
|
if (! is_array($bookingProductSlot->slots) || ! count($bookingProductSlot->slots))
|
||||||
|
return [];
|
||||||
|
|
||||||
|
$requestedDate = Carbon::createFromTimeString($date . " 00:00:00");
|
||||||
|
|
||||||
|
$currentTime = Carbon::now();
|
||||||
|
|
||||||
|
$availableFrom = Carbon::createFromTimeString($bookingProductSlot->available_from . " 00:00:00");
|
||||||
|
|
||||||
|
$availableTo = Carbon::createFromTimeString($bookingProductSlot->available_to . ' 23:59:59');
|
||||||
|
|
||||||
|
if ($requestedDate < $currentTime
|
||||||
|
|| $requestedDate < $availableFrom
|
||||||
|
|| $requestedDate > $availableTo)
|
||||||
|
return [];
|
||||||
|
|
||||||
|
$slots = [];
|
||||||
|
|
||||||
|
return $bookingProductSlot->booking_type == 'one'
|
||||||
|
? $this->getOneBookingForManyDaysSlots($bookingProductSlot, $requestedDate)
|
||||||
|
: $this->getManyBookingsforOneDaySlots($bookingProductSlot, $requestedDate);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns slots for One Booking For Many Days
|
||||||
|
*
|
||||||
|
* @param BookingProductSlot $bookingProductSlot
|
||||||
|
* @param string $requestedDate
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getOneBookingForManyDaysSlots($bookingProductSlot, $requestedDate)
|
||||||
|
{
|
||||||
|
$slots = [];
|
||||||
|
|
||||||
|
foreach ($bookingProductSlot->slots as $timeDuration) {
|
||||||
|
if ($requestedDate->dayOfWeek != $timeDuration['from_day'])
|
||||||
|
continue;
|
||||||
|
|
||||||
|
$startDate = clone $requestedDate->modify('this ' . $this->daysOfWeek[$timeDuration['from_day']]);
|
||||||
|
$endDate = clone $requestedDate->modify('this ' . $this->daysOfWeek[$timeDuration['to_day']]);
|
||||||
|
|
||||||
|
$slots[] = [
|
||||||
|
'from' => $startDate->format('d F, Y h:i A'),
|
||||||
|
'to' => $endDate->format('d F, Y h:i A'),
|
||||||
|
'timestamp' => $startDate->getTimestamp() . '-' . $endDate->getTimestamp(),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
return $slots;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns slots for Many Bookings for One Day
|
||||||
|
*
|
||||||
|
* @param BookingProductSlot $bookingProductSlot
|
||||||
|
* @param string $requestedDate
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getManyBookingsforOneDaySlots($bookingProductSlot, $requestedDate)
|
||||||
|
{
|
||||||
|
$currentTime = Carbon::now();
|
||||||
|
|
||||||
|
$availableFrom = Carbon::createFromTimeString($bookingProductSlot->available_from . ' 00:00:00');
|
||||||
|
|
||||||
|
$availableTo = Carbon::createFromTimeString($bookingProductSlot->available_to . ' 23:59:59');
|
||||||
|
|
||||||
|
$timeDuration = $bookingProductSlot->slots[$requestedDate->format('w')] ?? [];
|
||||||
|
|
||||||
|
if (! count($timeDuration) || ! $timeDuration['status'])
|
||||||
|
return [];
|
||||||
|
|
||||||
|
$slots = [];
|
||||||
|
|
||||||
|
$fromChunks = explode(':', $timeDuration['from']);
|
||||||
|
$toChunks = explode(':', $timeDuration['to']);
|
||||||
|
|
||||||
|
$startDayTime = Carbon::createFromTimeString($requestedDate->format('Y-m-d') . ' 00:00:00');
|
||||||
|
$startDayTime->addMinutes(($fromChunks[0] * 60) + $fromChunks[1]);
|
||||||
|
$tempStartDayTime = clone $startDayTime;
|
||||||
|
|
||||||
|
$endDayTime = Carbon::createFromTimeString($requestedDate->format('Y-m-d') . ' 00:00:00');
|
||||||
|
$endDayTime->addMinutes(($toChunks[0] * 60) + $toChunks[1]);
|
||||||
|
|
||||||
|
$isFirstIteration = true;
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
$from = clone $tempStartDayTime;
|
||||||
|
$tempStartDayTime->addMinutes($bookingProductSlot->duration);
|
||||||
|
|
||||||
|
if ($isFirstIteration) {
|
||||||
|
$isFirstIteration = false;
|
||||||
|
} else {
|
||||||
|
$from->modify('+' . $bookingProductSlot->break_time . ' minutes');
|
||||||
|
$tempStartDayTime->modify('+' . $bookingProductSlot->break_time . ' minutes');
|
||||||
|
}
|
||||||
|
|
||||||
|
$to = clone $tempStartDayTime;
|
||||||
|
|
||||||
|
if (($startDayTime <= $from && $from <= $availableTo)
|
||||||
|
&& ($availableTo >= $to && $to >= $startDayTime)
|
||||||
|
&& ($startDayTime <= $from && $from <= $endDayTime)
|
||||||
|
&& ($endDayTime >= $to && $to >= $startDayTime)) {
|
||||||
|
|
||||||
|
// Get already ordered qty for this slot
|
||||||
|
$orderedQty = 0;
|
||||||
|
|
||||||
|
$qty = isset($timeDuration['qty']) ? ( $timeDuration['qty'] - $orderedQty ) : 1;
|
||||||
|
|
||||||
|
if ($qty && $currentTime <= $from) {
|
||||||
|
$slots[] = [
|
||||||
|
'from' => $from->format('h:i A'),
|
||||||
|
'to' => $to->format('h:i A'),
|
||||||
|
'timestamp' => $from->getTimestamp() . '-' . $to->getTimestamp(),
|
||||||
|
'qty' => $qty,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $slots;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,60 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Webkul\BookingProduct\Helpers;
|
||||||
|
|
||||||
|
use Carbon\Carbon;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* EventSlot Helper
|
||||||
|
*
|
||||||
|
* @author Jitendra Singh <jitendra@webkul.com>
|
||||||
|
* @copyright 2018 Webkul Software Pvt Ltd (http://www.webkul.com)
|
||||||
|
*/
|
||||||
|
class EventSlot extends Booking
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Returns event date
|
||||||
|
*
|
||||||
|
* @param BookingProduct $bookingProduct
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getEventDate($bookingProduct)
|
||||||
|
{
|
||||||
|
$from = Carbon::createFromTimeString($bookingProduct->event_slot->available_from)->format('d F, Y h:i A');
|
||||||
|
|
||||||
|
$to = Carbon::createFromTimeString($bookingProduct->event_slot->available_to)->format('d F, Y h:i A');
|
||||||
|
|
||||||
|
return $from . ' - ' . $to;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns tickets
|
||||||
|
*
|
||||||
|
* @param BookingProduct $bookingProduct
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getTickets($bookingProduct)
|
||||||
|
{
|
||||||
|
if (! $bookingProduct->event_slot)
|
||||||
|
return;
|
||||||
|
|
||||||
|
return $this->formatPrice($bookingProduct->event_slot->slots);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Format ticket price
|
||||||
|
*
|
||||||
|
* @param array $tickets
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function formatPrice($tickets)
|
||||||
|
{
|
||||||
|
foreach ($tickets as $index => $ticket) {
|
||||||
|
$tickets[$index]['converted_price'] = core()->convertPrice($ticket['price']);
|
||||||
|
$tickets[$index]['formated_price'] = $formatedPrice = core()->currency($ticket['price']);
|
||||||
|
$tickets[$index]['formated_price_text'] = trans('bookingproduct::app.shop.products.per-ticket-price', ['price' => $formatedPrice]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $tickets;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,94 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Webkul\BookingProduct\Helpers;
|
||||||
|
|
||||||
|
use Carbon\Carbon;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* RentalSlot Helper
|
||||||
|
*
|
||||||
|
* @author Jitendra Singh <jitendra@webkul.com>
|
||||||
|
* @copyright 2018 Webkul Software Pvt Ltd (http://www.webkul.com)
|
||||||
|
*/
|
||||||
|
class RentalSlot extends Booking
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Returns slots for a perticular day
|
||||||
|
*
|
||||||
|
* @param BookingProduct $bookingProduct
|
||||||
|
* @param string $date
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getSlotsByDate($bookingProduct, $date)
|
||||||
|
{
|
||||||
|
$bookingProductSlot = $this->typeRepositories[$bookingProduct->type]->findOneByField('booking_product_id', $bookingProduct->id);
|
||||||
|
|
||||||
|
if (! is_array($bookingProductSlot->slots) || ! count($bookingProductSlot->slots))
|
||||||
|
return [];
|
||||||
|
|
||||||
|
$requestedDate = Carbon::createFromTimeString($date . " 00:00:00");
|
||||||
|
|
||||||
|
$currentTime = Carbon::now();
|
||||||
|
|
||||||
|
$availableFrom = ! $bookingProductSlot->available_every_week
|
||||||
|
? Carbon::createFromTimeString($bookingProductSlot->available_from . ' 00:00:00')
|
||||||
|
: Carbon::createFromTimeString($currentTime->format('Y-m-d') . ' 00:00:00');
|
||||||
|
|
||||||
|
$availableTo = ! $bookingProductSlot->available_every_week
|
||||||
|
? Carbon::createFromTimeString($bookingProductSlot->available_to . ' 23:59:59')
|
||||||
|
: Carbon::createFromTimeString('2080-01-01 00:00:00');
|
||||||
|
|
||||||
|
$timeDurations = $bookingProductSlot->same_slot_all_days
|
||||||
|
? $bookingProductSlot->slots
|
||||||
|
: $bookingProductSlot->slots[$requestedDate->format('w')];
|
||||||
|
|
||||||
|
$slots = [];
|
||||||
|
|
||||||
|
foreach ($timeDurations as $index => $timeDuration) {
|
||||||
|
$fromChunks = explode(':', $timeDuration['from']);
|
||||||
|
$toChunks = explode(':', $timeDuration['to']);
|
||||||
|
|
||||||
|
$startDayTime = Carbon::createFromTimeString($requestedDate->format('Y-m-d') . ' 00:00:00');
|
||||||
|
$startDayTime->addMinutes(($fromChunks[0] * 60) + $fromChunks[1]);
|
||||||
|
$tempStartDayTime = clone $startDayTime;
|
||||||
|
|
||||||
|
$endDayTime = Carbon::createFromTimeString($requestedDate->format('Y-m-d') . ' 00:00:00');
|
||||||
|
$endDayTime->addMinutes(($toChunks[0] * 60) + $toChunks[1]);
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
$from = clone $tempStartDayTime;
|
||||||
|
$tempStartDayTime->addMinutes(60);
|
||||||
|
|
||||||
|
$to = clone $tempStartDayTime;
|
||||||
|
|
||||||
|
if (($startDayTime <= $from && $from <= $availableTo)
|
||||||
|
&& ($availableTo >= $to && $to >= $startDayTime)
|
||||||
|
&& ($startDayTime <= $from && $from <= $endDayTime)
|
||||||
|
&& ($endDayTime >= $to && $to >= $startDayTime)) {
|
||||||
|
|
||||||
|
// Get already ordered qty for this slot
|
||||||
|
$orderedQty = 0;
|
||||||
|
|
||||||
|
$qty = isset($timeDuration['qty']) ? ( $timeDuration['qty'] - $orderedQty ) : 1;
|
||||||
|
|
||||||
|
if ($qty && $currentTime <= $from) {
|
||||||
|
if (! isset($slots[$index]))
|
||||||
|
$slots[$index]['time'] = $startDayTime->format('h:i A') . ' - ' . $endDayTime->format('h:i A');
|
||||||
|
|
||||||
|
$slots[$index]['slots'][] = [
|
||||||
|
'from' => $from->format('h:i A'),
|
||||||
|
'to' => $to->format('h:i A'),
|
||||||
|
'from_timestamp' => $from->getTimestamp(),
|
||||||
|
'to_timestamp' => $to->getTimestamp(),
|
||||||
|
'qty' => $qty
|
||||||
|
];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $slots;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Webkul\BookingProduct\Helpers;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TableSlot Helper
|
||||||
|
*
|
||||||
|
* @author Jitendra Singh <jitendra@webkul.com>
|
||||||
|
* @copyright 2018 Webkul Software Pvt Ltd (http://www.webkul.com)
|
||||||
|
*/
|
||||||
|
class TableSlot extends Booking
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,78 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Webkul\BookingProduct\Http\Controllers\Shop;
|
||||||
|
|
||||||
|
use Webkul\BookingProduct\Repositories\BookingProductRepository;
|
||||||
|
use Webkul\BookingProduct\Helpers\DefaultSlot as DefaultSlotHelper;
|
||||||
|
use Webkul\BookingProduct\Helpers\AppointmentSlot as AppointmentSlotHelper;
|
||||||
|
use Webkul\BookingProduct\Helpers\RentalSlot as RentalSlotHelper;
|
||||||
|
use Webkul\BookingProduct\Helpers\EventSlot as EventSlotHelper;
|
||||||
|
use Webkul\BookingProduct\Helpers\TableSlot as TableSlotHelper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* BookingProduct page controller
|
||||||
|
*
|
||||||
|
* @author Jitendra Singh <jitendra@webkul.com>
|
||||||
|
* @copyright 2018 Webkul Software Pvt Ltd (http://www.webkul.com)
|
||||||
|
*/
|
||||||
|
class BookingProductController extends Controller
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Booking object
|
||||||
|
*
|
||||||
|
* @var Object
|
||||||
|
*/
|
||||||
|
protected $bookingHelper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
protected $bookingHelpers = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new helper instance.
|
||||||
|
*
|
||||||
|
* @param Webkul\BookingProduct\Repositories\BookingProductRepository $bookingProductRepository
|
||||||
|
* @param Webkul\BookingProduct\Helpers\DefaultSlot $defaultSlotHelper
|
||||||
|
* @param Webkul\BookingProduct\Helpers\AppointmentSlot $appointmentSlotHelper
|
||||||
|
* @param Webkul\BookingProduct\Helpers\RentalSlot $rentalSlotHelper
|
||||||
|
* @param Webkul\BookingProduct\Helpers\EventSlot $eventSlotHelper
|
||||||
|
* @param Webkul\BookingProduct\Helpers\TableSlot $tableSlotHelper
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function __construct(
|
||||||
|
BookingProductRepository $bookingProductRepository,
|
||||||
|
DefaultSlotHelper $defaultSlotHelper,
|
||||||
|
AppointmentSlotHelper $appointmentSlotHelper,
|
||||||
|
RentalSlotHelper $rentalSlotHelper,
|
||||||
|
EventSlotHelper $eventSlotHelper,
|
||||||
|
TableSlotHelper $tableSlotHelper
|
||||||
|
)
|
||||||
|
{
|
||||||
|
$this->bookingProductRepository = $bookingProductRepository;
|
||||||
|
|
||||||
|
$this->bookingHelpers['default'] = $defaultSlotHelper;
|
||||||
|
|
||||||
|
$this->bookingHelpers['appointment'] = $appointmentSlotHelper;
|
||||||
|
|
||||||
|
$this->bookingHelpers['rental'] = $rentalSlotHelper;
|
||||||
|
|
||||||
|
$this->bookingHelpers['event'] = $eventSlotHelper;
|
||||||
|
|
||||||
|
$this->bookingHelpers['table'] = $tableSlotHelper;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Display the specified resource.
|
||||||
|
*
|
||||||
|
* @return \Illuminate\Http\Response
|
||||||
|
*/
|
||||||
|
public function index()
|
||||||
|
{
|
||||||
|
$bookingProduct = $this->bookingProductRepository->find(request('id'));
|
||||||
|
|
||||||
|
return response()->json([
|
||||||
|
'data' => $this->bookingHelpers[$bookingProduct->type]->getSlotsByDate($bookingProduct, request()->get('date'))
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,12 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Webkul\BookingProduct\Http\Controllers\Shop;
|
||||||
|
|
||||||
|
use Illuminate\Foundation\Bus\DispatchesJobs;
|
||||||
|
use Illuminate\Routing\Controller as BaseController;
|
||||||
|
use Illuminate\Foundation\Validation\ValidatesRequests;
|
||||||
|
|
||||||
|
class Controller extends BaseController
|
||||||
|
{
|
||||||
|
use DispatchesJobs, ValidatesRequests;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
Route::group(['middleware' => ['web', 'theme', 'locale', 'currency']], function () {
|
||||||
|
Route::get('/booking-slots/{id}', 'Webkul\BookingProduct\Http\Controllers\Shop\BookingProductController@index')->name('booking_product.slots.index');
|
||||||
|
});
|
||||||
|
|
@ -0,0 +1,53 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Webkul\BookingProduct\Listeners;
|
||||||
|
|
||||||
|
use Webkul\BookingProduct\Repositories\BookingProductRepository;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Product Event handler
|
||||||
|
*
|
||||||
|
* @author Jitendra Singh <jitendra@webkul.com>
|
||||||
|
* @copyright 2018 Webkul Software Pvt Ltd (http://www.webkul.com)
|
||||||
|
*/
|
||||||
|
class Product
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* BookingProductRepository Object
|
||||||
|
*
|
||||||
|
* @var Object
|
||||||
|
*/
|
||||||
|
protected $bookingProductRepository;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new listener instance.
|
||||||
|
*
|
||||||
|
* @param Webkul\BookingProduct\Repositories\BookingProductRepository $bookingProductRepository
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function __construct(BookingProductRepository $bookingProductRepository)
|
||||||
|
{
|
||||||
|
$this->bookingProductRepository = $bookingProductRepository;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* After the product is updated
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function afterProductUpdated($product)
|
||||||
|
{
|
||||||
|
if ($product->type != 'booking' || ! request('booking'))
|
||||||
|
return;
|
||||||
|
|
||||||
|
$bookingProduct = $this->bookingProductRepository->findOneByField('product_id', $product->id);
|
||||||
|
|
||||||
|
if ($bookingProduct) {
|
||||||
|
$this->bookingProductRepository->update(request('booking'), $bookingProduct->id);
|
||||||
|
} else {
|
||||||
|
$this->bookingProductRepository->create(array_merge(request('booking'), [
|
||||||
|
'product_id' => $product->id
|
||||||
|
]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,54 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Webkul\BookingProduct\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
use Webkul\Product\Models\ProductProxy;
|
||||||
|
use Webkul\BookingProduct\Contracts\BookingProduct as BookingProductContract;
|
||||||
|
|
||||||
|
class BookingProduct extends Model implements BookingProductContract
|
||||||
|
{
|
||||||
|
protected $fillable = ['location', 'show_location', 'type', 'product_id'];
|
||||||
|
|
||||||
|
protected $with = ['default_slot', 'appointment_slot', 'event_slot', 'rental_slot', 'table_slot'];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The Product Default Booking that belong to the product booking.
|
||||||
|
*/
|
||||||
|
public function default_slot()
|
||||||
|
{
|
||||||
|
return $this->hasOne(BookingProductDefaultSlotProxy::modelClass());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The Product Appointment Booking that belong to the product booking.
|
||||||
|
*/
|
||||||
|
public function appointment_slot()
|
||||||
|
{
|
||||||
|
return $this->hasOne(BookingProductAppointmentSlotProxy::modelClass());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The Product Event Booking that belong to the product booking.
|
||||||
|
*/
|
||||||
|
public function event_slot()
|
||||||
|
{
|
||||||
|
return $this->hasOne(BookingProductEventSlotProxy::modelClass());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The Product Rental Booking that belong to the product booking.
|
||||||
|
*/
|
||||||
|
public function rental_slot()
|
||||||
|
{
|
||||||
|
return $this->hasOne(BookingProductRentalSlotProxy::modelClass());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The Product Table Booking that belong to the product booking.
|
||||||
|
*/
|
||||||
|
public function table_slot()
|
||||||
|
{
|
||||||
|
return $this->hasOne(BookingProductTableSlotProxy::modelClass());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,15 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Webkul\BookingProduct\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
use Webkul\BookingProduct\Contracts\BookingProductAppointmentSlot as BookingProductAppointmentSlotContract;
|
||||||
|
|
||||||
|
class BookingProductAppointmentSlot extends Model implements BookingProductAppointmentSlotContract
|
||||||
|
{
|
||||||
|
public $timestamps = false;
|
||||||
|
|
||||||
|
protected $casts = ['slots' => 'array'];
|
||||||
|
|
||||||
|
protected $fillable = ['duration', 'break_time', 'available_every_week', 'slot_has_quantity', 'same_slot_all_days', 'slots', 'booking_product_id'];
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,10 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Webkul\BookingProduct\Models;
|
||||||
|
|
||||||
|
use Konekt\Concord\Proxies\ModelProxy;
|
||||||
|
|
||||||
|
class BookingProductAppointmentSlotProxy extends ModelProxy
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,25 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Webkul\BookingProduct\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
use Webkul\BookingProduct\Contracts\BookingProductDefaultSlot as BookingProductDefaultSlotContract;
|
||||||
|
|
||||||
|
class BookingProductDefaultSlot extends Model implements BookingProductDefaultSlotContract
|
||||||
|
{
|
||||||
|
protected $table = 'booking_product_default_slots';
|
||||||
|
|
||||||
|
public $timestamps = false;
|
||||||
|
|
||||||
|
protected $casts = ['slots' => 'array'];
|
||||||
|
|
||||||
|
protected $fillable = ['booking_type', 'duration', 'break_time', 'available_from', 'available_to', 'slots', 'booking_product_id'];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the product that owns the attribute value.
|
||||||
|
*/
|
||||||
|
public function booking_product()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(BookingProductProxy::modelClass());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,10 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Webkul\BookingProduct\Models;
|
||||||
|
|
||||||
|
use Konekt\Concord\Proxies\ModelProxy;
|
||||||
|
|
||||||
|
class BookingProductDefaultSlotProxy extends ModelProxy
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,15 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Webkul\BookingProduct\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
use Webkul\BookingProduct\Contracts\BookingProductEventSlot as BookingProductEventSlotContract;
|
||||||
|
|
||||||
|
class BookingProductEventSlot extends Model implements BookingProductEventSlotContract
|
||||||
|
{
|
||||||
|
public $timestamps = false;
|
||||||
|
|
||||||
|
protected $casts = ['slots' => 'array'];
|
||||||
|
|
||||||
|
protected $fillable = ['available_from', 'available_to', 'slots', 'booking_product_id'];
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,10 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Webkul\BookingProduct\Models;
|
||||||
|
|
||||||
|
use Konekt\Concord\Proxies\ModelProxy;
|
||||||
|
|
||||||
|
class BookingProductEventSlotProxy extends ModelProxy
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,10 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Webkul\BookingProduct\Models;
|
||||||
|
|
||||||
|
use Konekt\Concord\Proxies\ModelProxy;
|
||||||
|
|
||||||
|
class BookingProductProxy extends ModelProxy
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,15 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Webkul\BookingProduct\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
use Webkul\BookingProduct\Contracts\BookingProductRentalSlot as BookingProductRentalSlotContract;
|
||||||
|
|
||||||
|
class BookingProductRentalSlot extends Model implements BookingProductRentalSlotContract
|
||||||
|
{
|
||||||
|
public $timestamps = false;
|
||||||
|
|
||||||
|
protected $casts = ['slots' => 'array'];
|
||||||
|
|
||||||
|
protected $fillable = ['renting_type', 'daily_price', 'hourly_price', 'available_every_week', 'slot_has_quantity', 'same_slot_all_days', 'slots', 'booking_product_id'];
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,10 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Webkul\BookingProduct\Models;
|
||||||
|
|
||||||
|
use Konekt\Concord\Proxies\ModelProxy;
|
||||||
|
|
||||||
|
class BookingProductRentalSlotProxy extends ModelProxy
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,15 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Webkul\BookingProduct\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
use Webkul\BookingProduct\Contracts\BookingProductTableSlot as BookingProductTableSlotContract;
|
||||||
|
|
||||||
|
class BookingProductTableSlot extends Model implements BookingProductTableSlotContract
|
||||||
|
{
|
||||||
|
public $timestamps = false;
|
||||||
|
|
||||||
|
protected $casts = ['slots' => 'array'];
|
||||||
|
|
||||||
|
protected $fillable = ['price_type', 'guest_limit', 'duration', 'break_time', 'prevent_scheduling_before', 'available_every_week', 'available_from', 'available_to', 'same_slot_all_days', 'slots', 'booking_product_id'];
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,10 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Webkul\BookingProduct\Models;
|
||||||
|
|
||||||
|
use Konekt\Concord\Proxies\ModelProxy;
|
||||||
|
|
||||||
|
class BookingProductTableSlotProxy extends ModelProxy
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,42 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Webkul\BookingProduct\Providers;
|
||||||
|
|
||||||
|
use Illuminate\Support\ServiceProvider;
|
||||||
|
|
||||||
|
class BookingProductServiceProvider extends ServiceProvider
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Bootstrap services.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function boot()
|
||||||
|
{
|
||||||
|
$this->loadRoutesFrom(__DIR__ . '/../Http/front-routes.php');
|
||||||
|
|
||||||
|
$this->loadMigrationsFrom(__DIR__ . '/../Database/Migrations');
|
||||||
|
|
||||||
|
$this->loadTranslationsFrom(__DIR__ . '/../Resources/lang', 'bookingproduct');
|
||||||
|
|
||||||
|
$this->loadViewsFrom(__DIR__ . '/../Resources/views', 'bookingproduct');
|
||||||
|
|
||||||
|
$this->publishes([
|
||||||
|
__DIR__ . '/../../publishable/assets' => public_path('themes/default/assets'),
|
||||||
|
], 'public');
|
||||||
|
|
||||||
|
$this->app->register(EventServiceProvider::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register services.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function register()
|
||||||
|
{
|
||||||
|
$this->mergeConfigFrom(
|
||||||
|
dirname(__DIR__) . '/Config/product_types.php', 'product_types'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,23 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Webkul\BookingProduct\Providers;
|
||||||
|
|
||||||
|
use Illuminate\Support\ServiceProvider;
|
||||||
|
use Illuminate\Support\Facades\Event;
|
||||||
|
|
||||||
|
class EventServiceProvider extends ServiceProvider
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Bootstrap services.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function boot()
|
||||||
|
{
|
||||||
|
Event::listen('bagisto.shop.products.view.short_description.after', function($viewRenderEventManager) {
|
||||||
|
$viewRenderEventManager->addTemplate('bookingproduct::shop.products.view.booking');
|
||||||
|
});
|
||||||
|
|
||||||
|
Event::listen('catalog.product.update.after', 'Webkul\BookingProduct\Listeners\Product@afterProductUpdated');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,17 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Webkul\BookingProduct\Providers;
|
||||||
|
|
||||||
|
use Konekt\Concord\BaseModuleServiceProvider;
|
||||||
|
|
||||||
|
class ModuleServiceProvider extends BaseModuleServiceProvider
|
||||||
|
{
|
||||||
|
protected $models = [
|
||||||
|
\Webkul\BookingProduct\Models\BookingProduct::class,
|
||||||
|
\Webkul\BookingProduct\Models\BookingProductDefaultSlot::class,
|
||||||
|
\Webkul\BookingProduct\Models\BookingProductAppointmentSlot::class,
|
||||||
|
\Webkul\BookingProduct\Models\BookingProductEventSlot::class,
|
||||||
|
\Webkul\BookingProduct\Models\BookingProductRentalSlot::class,
|
||||||
|
\Webkul\BookingProduct\Models\BookingProductTableSlot::class,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,24 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Webkul\BookingProduct\Repositories;
|
||||||
|
|
||||||
|
use Webkul\Core\Eloquent\Repository;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* BookingProductAppointmentSlot Repository
|
||||||
|
*
|
||||||
|
* @author Jitendra Singh <jitendra@webkul.com>
|
||||||
|
* @copyright 2018 Webkul Software Pvt Ltd (http://www.webkul.com)
|
||||||
|
*/
|
||||||
|
class BookingProductAppointmentSlotRepository extends Repository
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Specify Model class name
|
||||||
|
*
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
function model()
|
||||||
|
{
|
||||||
|
return 'Webkul\BookingProduct\Contracts\BookingProductAppointmentSlot';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,24 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Webkul\BookingProduct\Repositories;
|
||||||
|
|
||||||
|
use Webkul\Core\Eloquent\Repository;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* BookingProductDefaultSlot Repository
|
||||||
|
*
|
||||||
|
* @author Jitendra Singh <jitendra@webkul.com>
|
||||||
|
* @copyright 2018 Webkul Software Pvt Ltd (http://www.webkul.com)
|
||||||
|
*/
|
||||||
|
class BookingProductDefaultSlotRepository extends Repository
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Specify Model class name
|
||||||
|
*
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
function model()
|
||||||
|
{
|
||||||
|
return 'Webkul\BookingProduct\Contracts\BookingProductDefaultSlot';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,24 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Webkul\BookingProduct\Repositories;
|
||||||
|
|
||||||
|
use Webkul\Core\Eloquent\Repository;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* BookingProductEventSlot Repository
|
||||||
|
*
|
||||||
|
* @author Jitendra Singh <jitendra@webkul.com>
|
||||||
|
* @copyright 2018 Webkul Software Pvt Ltd (http://www.webkul.com)
|
||||||
|
*/
|
||||||
|
class BookingProductEventSlotRepository extends Repository
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Specify Model class name
|
||||||
|
*
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
function model()
|
||||||
|
{
|
||||||
|
return 'Webkul\BookingProduct\Contracts\BookingProductEventSlot';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,24 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Webkul\BookingProduct\Repositories;
|
||||||
|
|
||||||
|
use Webkul\Core\Eloquent\Repository;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* BookingProductRentalSlot Repository
|
||||||
|
*
|
||||||
|
* @author Jitendra Singh <jitendra@webkul.com>
|
||||||
|
* @copyright 2018 Webkul Software Pvt Ltd (http://www.webkul.com)
|
||||||
|
*/
|
||||||
|
class BookingProductRentalSlotRepository extends Repository
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Specify Model class name
|
||||||
|
*
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
function model()
|
||||||
|
{
|
||||||
|
return 'Webkul\BookingProduct\Contracts\BookingProductRentalSlot';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,135 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Webkul\BookingProduct\Repositories;
|
||||||
|
|
||||||
|
use Illuminate\Container\Container as App;
|
||||||
|
use Webkul\Core\Eloquent\Repository;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* BookingProduct Repository
|
||||||
|
*
|
||||||
|
* @author Jitendra Singh <jitendra@webkul.com>
|
||||||
|
* @copyright 2018 Webkul Software Pvt Ltd (http://www.webkul.com)
|
||||||
|
*/
|
||||||
|
class BookingProductRepository extends Repository
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
protected $typeRepositories = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new repository instance.
|
||||||
|
*
|
||||||
|
* @param Webkul\BookingProduct\Repositories\BookingProductDefaultSlotRepository $bookingProductDefaultSlotRepository
|
||||||
|
* @param Webkul\BookingProduct\Repositories\BookingProductAppointmentSlotRepository $bookingProductAppointmentSlotRepository
|
||||||
|
* @param Webkul\BookingProduct\Repositories\BookingProductEventSlotRepository $bookingProductEventSlotRepository
|
||||||
|
* @param Webkul\BookingProduct\Repositories\BookingProductRentalSlotRepository $bookingProductRentalSlotRepository
|
||||||
|
* @param Webkul\BookingProduct\Repositories\BookingProductTableSlotRepository $bookingProductTableSlotRepository
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function __construct(
|
||||||
|
BookingProductDefaultSlotRepository $bookingProductDefaultSlotRepository,
|
||||||
|
BookingProductAppointmentSlotRepository $bookingProductAppointmentSlotRepository,
|
||||||
|
BookingProductEventSlotRepository $bookingProductEventSlotRepository,
|
||||||
|
BookingProductRentalSlotRepository $bookingProductRentalSlotRepository,
|
||||||
|
BookingProductTableSlotRepository $bookingProductTableSlotRepository,
|
||||||
|
App $app
|
||||||
|
)
|
||||||
|
{
|
||||||
|
parent::__construct($app);
|
||||||
|
|
||||||
|
$this->typeRepositories['default'] = $bookingProductDefaultSlotRepository;
|
||||||
|
|
||||||
|
$this->typeRepositories['appointment'] = $bookingProductAppointmentSlotRepository;
|
||||||
|
|
||||||
|
$this->typeRepositories['event'] = $bookingProductEventSlotRepository;
|
||||||
|
|
||||||
|
$this->typeRepositories['rental'] = $bookingProductRentalSlotRepository;
|
||||||
|
|
||||||
|
$this->typeRepositories['table'] = $bookingProductTableSlotRepository;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Specify Model class name
|
||||||
|
*
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
function model()
|
||||||
|
{
|
||||||
|
return 'Webkul\BookingProduct\Contracts\BookingProduct';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param array $data
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
public function create(array $data)
|
||||||
|
{
|
||||||
|
$bookingProduct = parent::create($data);
|
||||||
|
|
||||||
|
$this->typeRepositories[$data['type']]->create(array_merge($data, ['booking_product_id' => $bookingProduct->id]));
|
||||||
|
|
||||||
|
return $bookingProduct;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param array $data
|
||||||
|
* @param integer $id
|
||||||
|
* @param string $attribute
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
public function update(array $data, $id, $attribute = "id")
|
||||||
|
{
|
||||||
|
parent::update($data, $id, $attribute);
|
||||||
|
|
||||||
|
foreach ($this->typeRepositories as $type => $repository) {
|
||||||
|
if ($type == $data['type'])
|
||||||
|
continue;
|
||||||
|
|
||||||
|
$repository->deleteWhere(['booking_product_id' => $id]);
|
||||||
|
}
|
||||||
|
|
||||||
|
$bookingProductTypeSlot = $this->typeRepositories[$data['type']]->findOneByField('booking_product_id', $id);
|
||||||
|
|
||||||
|
if (isset($data['slots']))
|
||||||
|
$data['slots'] = $this->formatSlots($data);
|
||||||
|
|
||||||
|
if (! $bookingProductTypeSlot) {
|
||||||
|
$this->typeRepositories[$data['type']]->create(array_merge($data, ['booking_product_id' => $id]));
|
||||||
|
} else {
|
||||||
|
$this->typeRepositories[$data['type']]->update($data, $bookingProductTypeSlot->id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param array $data
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function formatSlots($data)
|
||||||
|
{
|
||||||
|
if (isset($data['slots']) && isset($data['same_slot_all_days']) && ! $data['same_slot_all_days']) {
|
||||||
|
for ($i = 0; $i < 7; $i++) {
|
||||||
|
if (! isset($data['slots'][$i])) {
|
||||||
|
$data['slots'][$i] = [];
|
||||||
|
} else {
|
||||||
|
$count = 0;
|
||||||
|
|
||||||
|
$slots = [];
|
||||||
|
|
||||||
|
foreach ($data['slots'][$i] as $slot) {
|
||||||
|
$slots[] = array_merge($slot, ['id' => $i . '_slot_' . $count]);
|
||||||
|
|
||||||
|
$count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
$data['slots'][$i] = $slots;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ksort($data['slots']);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $data['slots'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,24 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Webkul\BookingProduct\Repositories;
|
||||||
|
|
||||||
|
use Webkul\Core\Eloquent\Repository;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* BookingProductTableSlot Repository
|
||||||
|
*
|
||||||
|
* @author Jitendra Singh <jitendra@webkul.com>
|
||||||
|
* @copyright 2018 Webkul Software Pvt Ltd (http://www.webkul.com)
|
||||||
|
*/
|
||||||
|
class BookingProductTableSlotRepository extends Repository
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Specify Model class name
|
||||||
|
*
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
function model()
|
||||||
|
{
|
||||||
|
return 'Webkul\BookingProduct\Contracts\BookingProductTableSlot';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,10 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<svg width="8px" height="8px" viewBox="0 0 8 8" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||||
|
<!-- Generator: Sketch 51.1 (57501) - http://www.bohemiancoding.com/sketch -->
|
||||||
|
<title>icon-dropdown</title>
|
||||||
|
<desc>Created with Sketch.</desc>
|
||||||
|
<defs></defs>
|
||||||
|
<g id="icon-dropdown" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||||
|
<polygon id="›" fill="#242424" transform="translate(4.000000, 4.514496) rotate(-270.000000) translate(-4.000000, -4.514496) " points="1.48080444 8.51449585 4.54690552 4.51449585 1.48080444 0.51449585 3.48550415 0.51449585 6.51919556 4.51449585 3.48550415 8.51449585"></polygon>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 745 B |
|
|
@ -0,0 +1,10 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<svg width="8px" height="8px" viewBox="0 0 8 8" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||||
|
<!-- Generator: Sketch 50 (54983) - http://www.bohemiancoding.com/sketch -->
|
||||||
|
<title>icon-dropdown-up</title>
|
||||||
|
<desc>Created with Sketch.</desc>
|
||||||
|
<defs></defs>
|
||||||
|
<g id="icon-dropdown-up" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||||
|
<polygon id="›" fill="#242424" transform="translate(4.000000, 3.519196) scale(1, -1) rotate(-270.000000) translate(-4.000000, -3.519196) " points="1.48080444 7.51919556 4.54690552 3.51919556 1.48080444 -0.480804443 3.48550415 -0.480804443 6.51919556 3.51919556 3.48550415 7.51919556"></polygon>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 766 B |
|
|
@ -0,0 +1,11 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<svg width="32px" height="32px" viewBox="0 0 32 32" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||||
|
<!-- Generator: Sketch 51.1 (57501) - http://www.bohemiancoding.com/sketch -->
|
||||||
|
<title>tab/heading/icon/address</title>
|
||||||
|
<desc>Created with Sketch.</desc>
|
||||||
|
<defs></defs>
|
||||||
|
<g id="tab/heading/icon/address" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||||
|
<path d="M15.5,23.897235 C20.2087657,20.0716385 22.5,16.8805311 22.5,14.5 C22.5,10.6340068 19.3659932,7.5 15.5,7.5 C11.6340068,7.5 8.5,10.6340068 8.5,14.5 C8.5,16.8805311 10.7912343,20.0716385 15.5,23.897235 Z" id="Oval" stroke="#242424" stroke-width="3"></path>
|
||||||
|
<circle id="Oval-2" fill="#242424" cx="15.5" cy="14.5" r="2.5"></circle>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 835 B |
|
|
@ -0,0 +1,18 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<svg width="24px" height="24px" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||||
|
<!-- Generator: Sketch 51.1 (57501) - http://www.bohemiancoding.com/sketch -->
|
||||||
|
<title>icon-menu copy</title>
|
||||||
|
<desc>Created with Sketch.</desc>
|
||||||
|
<defs></defs>
|
||||||
|
<g id="icon-menu-copy" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" stroke-linecap="round">
|
||||||
|
<g id="Group-3" transform="translate(7.000000, 5.000000)" stroke="#242424" stroke-width="3">
|
||||||
|
<g id="Group-2">
|
||||||
|
<g id="Group">
|
||||||
|
<path d="M0,1 C0,6.2 2.66666667,10.5333333 8,14" id="Path-24"></path>
|
||||||
|
<path d="M0,0.860920013 L3.33066907e-16,0.860920013 C0.692541156,0.399225909 1.62823371,0.58636442 2.08992781,1.27890558 C2.0981214,1.29119595 2.10613384,1.30360612 2.11396256,1.31613206 L2.36753004,1.72184003 C2.99745806,2.72972486 2.84834566,4.03901444 2.00791685,4.87944325 L1.29138002,5.59598008" id="Path-25" fill="#242424"></path>
|
||||||
|
<path d="M8.63269516,13.7386314 L5,10.4383311 L5.96373991,10.125193 C7.09411415,9.75791214 8.32839532,10.2194571 8.94044595,11.2382972 L9.18681717,11.648415 C9.19442371,11.6610771 9.20184367,11.6738503 9.20907467,11.6867306 C9.61652862,12.4125102 9.35847472,13.3311774 8.63269516,13.7386314 Z" id="Path-25" stroke-linejoin="round"></path>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1.5 KiB |
|
|
@ -0,0 +1,15 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<svg width="32px" height="32px" viewBox="0 0 32 32" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||||
|
<!-- Generator: Sketch 51.1 (57501) - http://www.bohemiancoding.com/sketch -->
|
||||||
|
<title>tab/heading/icon/calender</title>
|
||||||
|
<desc>Created with Sketch.</desc>
|
||||||
|
<defs></defs>
|
||||||
|
<g id="tab/heading/icon/calender" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||||
|
<g id="Group" transform="translate(7.000000, 8.000000)" stroke="#242424" stroke-width="3">
|
||||||
|
<rect id="Rectangle-10" x="1.5" y="1.5" width="16" height="13"></rect>
|
||||||
|
</g>
|
||||||
|
<rect id="Rectangle" fill="#242424" x="7" y="13" width="19" height="3" rx="1.5"></rect>
|
||||||
|
<rect id="Rectangle-2" fill="#242424" x="11" y="5" width="3" height="6"></rect>
|
||||||
|
<rect id="Rectangle-2-Copy" fill="#242424" x="19" y="5" width="3" height="6"></rect>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 957 B |
|
|
@ -0,0 +1,213 @@
|
||||||
|
@import "icons";
|
||||||
|
|
||||||
|
.booking-information {
|
||||||
|
margin-bottom: 15px;
|
||||||
|
border-top: 1px solid #E8E8E8;
|
||||||
|
padding-top: 15px;
|
||||||
|
|
||||||
|
.booking-info-row {
|
||||||
|
padding-left: 32px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
top: -4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.title {
|
||||||
|
color: #5E5E5E;
|
||||||
|
display: block;
|
||||||
|
margin-bottom: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.value {
|
||||||
|
display: block;
|
||||||
|
margin-bottom: 5px;
|
||||||
|
|
||||||
|
.text-danger {
|
||||||
|
color: #ff5656;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.toggle {
|
||||||
|
color: #0041FF;
|
||||||
|
cursor: pointer;
|
||||||
|
-webkit-touch-callout: none;
|
||||||
|
-webkit-user-select: none;
|
||||||
|
-khtml-user-select: none;
|
||||||
|
-moz-user-select: none;
|
||||||
|
-ms-user-select: none;
|
||||||
|
user-select: none;
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
position: relative;
|
||||||
|
width: 10px;
|
||||||
|
height: 10px;
|
||||||
|
margin-left: 5px;
|
||||||
|
top: 0;
|
||||||
|
|
||||||
|
&.arrow-down-icon {
|
||||||
|
background-image: url(../images/arrow-down.svg) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.arrow-up-icon {
|
||||||
|
background-image: url(../images/arrow-up.svg) !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.days-availability {
|
||||||
|
table {
|
||||||
|
margin-top: 10px;
|
||||||
|
border-collapse: collapse;
|
||||||
|
|
||||||
|
tr {
|
||||||
|
td {
|
||||||
|
padding: 5px;
|
||||||
|
vertical-align: top;
|
||||||
|
|
||||||
|
&:first-child {
|
||||||
|
padding-left: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:last-child {
|
||||||
|
font-size: 14px;
|
||||||
|
padding-left: 15px;
|
||||||
|
padding-right: 0;
|
||||||
|
color: #5E5E5E;
|
||||||
|
}
|
||||||
|
|
||||||
|
.text-danger {
|
||||||
|
color: #ff5656;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.book-slots {
|
||||||
|
padding-top: 25px;
|
||||||
|
display: inline-block;
|
||||||
|
width: 100%;
|
||||||
|
border-top: solid 1px #e8e8e8;
|
||||||
|
|
||||||
|
h3 {
|
||||||
|
font-weight: 600;
|
||||||
|
font-size: 16px;
|
||||||
|
color: #242424;
|
||||||
|
margin-top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
label {
|
||||||
|
color: #3a3a3a;
|
||||||
|
}
|
||||||
|
|
||||||
|
.control-group {
|
||||||
|
label {
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.radio {
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.control-group-container {
|
||||||
|
width: 100%;
|
||||||
|
float: left;
|
||||||
|
|
||||||
|
.control-group:not(.quantity) {
|
||||||
|
width: 50%;
|
||||||
|
float: left;
|
||||||
|
|
||||||
|
.control {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.date {
|
||||||
|
padding-right: 5px;
|
||||||
|
|
||||||
|
&::after {
|
||||||
|
position: absolute;
|
||||||
|
top: 14px;
|
||||||
|
right: 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.slots {
|
||||||
|
&:first-child {
|
||||||
|
padding-right: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:last-child {
|
||||||
|
padding-left: 5px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.ticket-list {
|
||||||
|
|
||||||
|
.ticket-item {
|
||||||
|
width: 100%;
|
||||||
|
display: inline-block;
|
||||||
|
padding: 16px 0;
|
||||||
|
border-bottom: solid 1px #e8e8e8;
|
||||||
|
|
||||||
|
.ticket-info {
|
||||||
|
width: 50%;
|
||||||
|
float: left;
|
||||||
|
|
||||||
|
.ticket-name {
|
||||||
|
color: #242424;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ticket-price {
|
||||||
|
color: #5E5E5E;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.ticket-quantity {
|
||||||
|
width: 50%;
|
||||||
|
display: inline-block;
|
||||||
|
|
||||||
|
.control-group {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
color: #242424;
|
||||||
|
margin-bottom: 0;
|
||||||
|
font-weight: 400;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.ticket-total {
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #242424;
|
||||||
|
padding-top: 16px;
|
||||||
|
// border-top: solid 1px #e8e8e8;
|
||||||
|
|
||||||
|
> div {
|
||||||
|
margin-bottom: 12px;
|
||||||
|
|
||||||
|
&:last-child {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
color: #242424;
|
||||||
|
font-weight: 400;
|
||||||
|
margin-top: 4px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,17 @@
|
||||||
|
.bp-location-icon {
|
||||||
|
background-image: url("../images/location.svg");
|
||||||
|
width: 32px;
|
||||||
|
height: 32px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bp-slot-icon {
|
||||||
|
background-image: url("../images/slot.svg");
|
||||||
|
width: 32px;
|
||||||
|
height: 32px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bp-phone-icon {
|
||||||
|
background-image: url("../images/phone.svg");
|
||||||
|
width: 32px;
|
||||||
|
height: 32px;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,109 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
return [
|
||||||
|
'admin' => [
|
||||||
|
'catalog' => [
|
||||||
|
'products' => [
|
||||||
|
'booking' => 'Booking Information',
|
||||||
|
'booking-type' => 'Booking Type',
|
||||||
|
'default' => 'Default',
|
||||||
|
'appointment-booking' => 'Appointment Booking',
|
||||||
|
'event-booking' => 'Event Booking',
|
||||||
|
'rental-booking' => 'Rental Booking',
|
||||||
|
'table-booking' => 'Table Booking',
|
||||||
|
'slot-duration' => 'Slot Duration (Mins)',
|
||||||
|
'break-time' => 'Break Time b/w Slots (Mins)',
|
||||||
|
'available-every-week' => 'Available Every Week',
|
||||||
|
'yes' => 'Yes',
|
||||||
|
'no' => 'No',
|
||||||
|
'available-from' => 'Available From',
|
||||||
|
'available-to' => 'Available To',
|
||||||
|
'same-slot-all-days' => 'Same Slot All Days',
|
||||||
|
'slot-has-quantity' => 'Slot has Quantity',
|
||||||
|
'slots' => 'Slots',
|
||||||
|
'from' => 'From',
|
||||||
|
'to' => 'To',
|
||||||
|
'qty' => 'Qty',
|
||||||
|
'add-slot' => 'Add Slot',
|
||||||
|
'sunday' => 'Sunday',
|
||||||
|
'monday' => 'Monday',
|
||||||
|
'tuesday' => 'Tuesday',
|
||||||
|
'wednesday' => 'Wednesday',
|
||||||
|
'thursday' => 'Thursday',
|
||||||
|
'friday' => 'Friday',
|
||||||
|
'saturday' => 'Saturday',
|
||||||
|
'renting-type' => 'Renting Type',
|
||||||
|
'daily' => 'Daily Basis',
|
||||||
|
'hourly' => 'Hourly Basis',
|
||||||
|
'daily-hourly' => 'Both (Daily and Hourly Basis)',
|
||||||
|
'daily-price' => 'Daily Price',
|
||||||
|
'hourly-price' => 'Hourly Price',
|
||||||
|
'location' => 'Location',
|
||||||
|
'show-location' => 'Show Location',
|
||||||
|
'event-start-date' => 'Event Start Date',
|
||||||
|
'event-end-date' => 'Event End Date',
|
||||||
|
'tickets' => 'Tickets',
|
||||||
|
'add-ticket' => 'Add Ticket',
|
||||||
|
'name' => 'Name',
|
||||||
|
'price' => 'Price',
|
||||||
|
'quantity' => 'Quantity',
|
||||||
|
'description' => 'Description',
|
||||||
|
'charged-per' => 'Charged Per',
|
||||||
|
'guest' => 'Guest',
|
||||||
|
'table' => 'Table',
|
||||||
|
'prevent-scheduling-before' => 'Prevent Scheduling Before',
|
||||||
|
'guest-limit' => 'Guest Limit',
|
||||||
|
'type' => 'Type',
|
||||||
|
'many-bookings-for-one-day' => 'Many Bookings for One Day',
|
||||||
|
'one-booking-for-many-days' => 'One Booking for Many Days',
|
||||||
|
'day' => 'Day',
|
||||||
|
'status' => 'Status',
|
||||||
|
'open' => 'Open',
|
||||||
|
'close' => 'Close'
|
||||||
|
]
|
||||||
|
]
|
||||||
|
],
|
||||||
|
|
||||||
|
'shop' => [
|
||||||
|
'products' => [
|
||||||
|
'location' => 'Location',
|
||||||
|
'contact' => 'Contact',
|
||||||
|
'email' => 'Email',
|
||||||
|
'slot-duration' => 'Slot Duration',
|
||||||
|
'slot-duration-in-minutes' => ':minutes Minutes',
|
||||||
|
'today-availability' => 'Today Availability',
|
||||||
|
'sunday' => 'Sunday',
|
||||||
|
'monday' => 'Monday',
|
||||||
|
'tuesday' => 'Tuesday',
|
||||||
|
'wednesday' => 'Wednesday',
|
||||||
|
'thursday' => 'Thursday',
|
||||||
|
'friday' => 'Friday',
|
||||||
|
'saturday' => 'Saturday',
|
||||||
|
'closed' => 'Closed',
|
||||||
|
'book-an-appointment' => 'Book an Appointment',
|
||||||
|
'date' => 'Date',
|
||||||
|
'slot' => 'Slot',
|
||||||
|
'rent-an-item' => 'Rent an Item',
|
||||||
|
'choose-rent-option' => 'Choose Rent Option',
|
||||||
|
'daily-basis' => 'Daily Basis',
|
||||||
|
'hourly-basis' => 'Hourly Basis',
|
||||||
|
'select-time-slot'=> 'Select time slot',
|
||||||
|
'select-slot' => 'Select Slot',
|
||||||
|
'select-date' => 'Select date',
|
||||||
|
'select-rent-time' => 'Select Rent Time',
|
||||||
|
'from' => 'From',
|
||||||
|
'to' => 'To',
|
||||||
|
'book-a-table' => 'Book a Table',
|
||||||
|
'number-of-tables' => 'Number of Tables',
|
||||||
|
'special-notes' => 'Special Request/Notes',
|
||||||
|
'event-on' => 'Event On',
|
||||||
|
'book-your-ticket' => 'Book Your Ticket',
|
||||||
|
'per-ticket-price' => ':price Per Ticket',
|
||||||
|
'number-of-tickets' => 'Number of Tickets',
|
||||||
|
'total-tickets' => 'Total Tickets',
|
||||||
|
'base-price' => 'Base Price',
|
||||||
|
'total-price' => 'Total Price',
|
||||||
|
'base-price-info' => '(This will be apply to each type of ticket for each quantity)'
|
||||||
|
]
|
||||||
|
]
|
||||||
|
];
|
||||||
|
|
@ -0,0 +1,84 @@
|
||||||
|
{!! view_render_event('bagisto.admin.catalog.product.edit_form_accordian.booking.before', ['product' => $product]) !!}
|
||||||
|
|
||||||
|
<accordian :title="'{{ __('bookingproduct::app.admin.catalog.products.booking') }}'" :active="true">
|
||||||
|
<div slot="body">
|
||||||
|
|
||||||
|
<booking-information></booking-information>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</accordian>
|
||||||
|
|
||||||
|
{!! view_render_event('bagisto.admin.catalog.product.edit_form_accordian.booking.after', ['product' => $product]) !!}
|
||||||
|
|
||||||
|
@push('scripts')
|
||||||
|
<?php $bookingProduct = app('\Webkul\BookingProduct\Repositories\BookingProductRepository')->findOneByField('product_id', $product->id) ?>
|
||||||
|
|
||||||
|
@parent
|
||||||
|
|
||||||
|
<script type="text/x-template" id="booking-information-template">
|
||||||
|
<div>
|
||||||
|
|
||||||
|
<div class="control-group" :class="[errors.has('booking[type]') ? 'has-error' : '']">
|
||||||
|
<label class="required">{{ __('bookingproduct::app.admin.catalog.products.booking-type') }}</label>
|
||||||
|
|
||||||
|
<select v-validate="'required'" name="booking[type]" v-model="booking_type" class="control" data-vv-as=""{{ __('bookingproduct::app.admin.catalog.products.booking-type') }}"">
|
||||||
|
<option value="default">{{ __('bookingproduct::app.admin.catalog.products.default') }}</option>
|
||||||
|
<option value="appointment">{{ __('bookingproduct::app.admin.catalog.products.appointment-booking') }}</option>
|
||||||
|
<option value="event">{{ __('bookingproduct::app.admin.catalog.products.event-booking') }}</option>
|
||||||
|
<option value="rental">{{ __('bookingproduct::app.admin.catalog.products.rental-booking') }}</option>
|
||||||
|
<option value="table">{{ __('bookingproduct::app.admin.catalog.products.table-booking') }}</option>
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<span class="control-error" v-if="errors.has('booking[type]')">@{{ errors.first('booking[type]') }}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="control-group">
|
||||||
|
<label>{{ __('bookingproduct::app.admin.catalog.products.location') }}</label>
|
||||||
|
<input type="text" name="booking[location]" v-model="location" class="control"/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="default-booking-section" v-if="booking_type == 'default'">
|
||||||
|
@include ('bookingproduct::admin.catalog.products.accordians.booking.default', ['bookingProduct' => $bookingProduct])
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="appointment-booking-section" v-if="booking_type == 'appointment'">
|
||||||
|
@include ('bookingproduct::admin.catalog.products.accordians.booking.appointment', ['bookingProduct' => $bookingProduct])
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="event-booking-section" v-if="booking_type == 'event'">
|
||||||
|
@include ('bookingproduct::admin.catalog.products.accordians.booking.event', ['bookingProduct' => $bookingProduct])
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="rental-booking-section" v-if="booking_type == 'rental'">
|
||||||
|
@include ('bookingproduct::admin.catalog.products.accordians.booking.rental', ['bookingProduct' => $bookingProduct])
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="table-booking-section" v-if="booking_type == 'table'">
|
||||||
|
@include ('bookingproduct::admin.catalog.products.accordians.booking.table', ['bookingProduct' => $bookingProduct])
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
var bookingProduct = @json($bookingProduct);
|
||||||
|
|
||||||
|
Vue.component('booking-information', {
|
||||||
|
|
||||||
|
template: '#booking-information-template',
|
||||||
|
|
||||||
|
inject: ['$validator'],
|
||||||
|
|
||||||
|
data: function() {
|
||||||
|
return {
|
||||||
|
booking_type: bookingProduct ? bookingProduct.type : 'default',
|
||||||
|
|
||||||
|
location: ''
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
@include ('bookingproduct::admin.catalog.products.accordians.booking.slots')
|
||||||
|
|
||||||
|
@endpush
|
||||||
|
|
@ -0,0 +1,131 @@
|
||||||
|
{!! view_render_event('bagisto.admin.catalog.product.edit_form_accordian.booking.appointment.before', ['product' => $product]) !!}
|
||||||
|
|
||||||
|
<appointment-booking></appointment-booking>
|
||||||
|
|
||||||
|
{!! view_render_event('bagisto.admin.catalog.product.edit_form_accordian.booking.appointment.after', ['product' => $product]) !!}
|
||||||
|
|
||||||
|
@push('scripts')
|
||||||
|
@parent
|
||||||
|
|
||||||
|
<script type="text/x-template" id="appointment-booking-template">
|
||||||
|
<div>
|
||||||
|
<div class="control-group" :class="[errors.has('booking[duration]') ? 'has-error' : '']">
|
||||||
|
<label class="required">{{ __('bookingproduct::app.admin.catalog.products.slot-duration') }}</label>
|
||||||
|
|
||||||
|
<input type="text" v-validate="'required|min_value:1'" name="booking[duration]" v-model="appointment_booking.duration" class="control" data-vv-as=""{{ __('bookingproduct::app.admin.catalog.products.slot-duration') }}""/>
|
||||||
|
|
||||||
|
<span class="control-error" v-if="errors.has('booking[duration]')">@{{ errors.first('booking[duration]') }}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="control-group" :class="[errors.has('booking[break_time]') ? 'has-error' : '']">
|
||||||
|
<label class="required">{{ __('bookingproduct::app.admin.catalog.products.break-time') }}</label>
|
||||||
|
|
||||||
|
<input type="text" v-validate="'required|min_value:1'" name="booking[break_time]" v-model="appointment_booking.break_time" class="control" data-vv-as=""{{ __('bookingproduct::app.admin.catalog.products.break-time') }}""/>
|
||||||
|
|
||||||
|
<span class="control-error" v-if="errors.has('booking[break_time]')">@{{ errors.first('booking[break_time]') }}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="control-group" :class="[errors.has('booking[available_every_week]') ? 'has-error' : '']">
|
||||||
|
<label class="required">{{ __('bookingproduct::app.admin.catalog.products.available-every-week') }}</label>
|
||||||
|
|
||||||
|
<select v-validate="'required'" name="booking[available_every_week]" v-model="appointment_booking.available_every_week" class="control" data-vv-as=""{{ __('bookingproduct::app.admin.catalog.products.available-every-week') }}"">
|
||||||
|
<option value="1">{{ __('bookingproduct::app.admin.catalog.products.yes') }}</option>
|
||||||
|
<option value="0">{{ __('bookingproduct::app.admin.catalog.products.no') }}</option>
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<span class="control-error" v-if="errors.has('booking[available_every_week]')">@{{ errors.first('booking[available_every_week]') }}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-if="! parseInt(appointment_booking.available_every_week)">
|
||||||
|
<div class="control-group" :class="[errors.has('booking[available_from]') ? 'has-error' : '']">
|
||||||
|
<label class="required">{{ __('bookingproduct::app.admin.catalog.products.available-from') }}</label>
|
||||||
|
|
||||||
|
<date>
|
||||||
|
<input type="text" v-validate="'required'" name="booking[available_from]" v-model="appointment_booking.available_from" class="control" data-vv-as=""{{ __('bookingproduct::app.admin.catalog.products.available-from') }}""/>
|
||||||
|
</date>
|
||||||
|
|
||||||
|
<span class="control-error" v-if="errors.has('booking[available_from]')">@{{ errors.first('booking[available_from]') }}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="control-group" :class="[errors.has('booking[available_to]') ? 'has-error' : '']">
|
||||||
|
<label class="required">{{ __('bookingproduct::app.admin.catalog.products.available-to') }}</label>
|
||||||
|
|
||||||
|
<date>
|
||||||
|
<input type="text" v-validate="'required'" name="booking[available_to]" v-model="appointment_booking.available_to" class="control" data-vv-as=""{{ __('bookingproduct::app.admin.catalog.products.available-to') }}""/>
|
||||||
|
</date>
|
||||||
|
|
||||||
|
<span class="control-error" v-if="errors.has('booking[available_to]')">@{{ errors.first('booking[available_to]') }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="control-group" :class="[errors.has('booking[slot_has_quantity]') ? 'has-error' : '']">
|
||||||
|
<label class="required">{{ __('bookingproduct::app.admin.catalog.products.slot-has-quantity') }}</label>
|
||||||
|
|
||||||
|
<select v-validate="'required'" name="booking[slot_has_quantity]" v-model="appointment_booking.slot_has_quantity" class="control" data-vv-as=""{{ __('bookingproduct::app.admin.catalog.products.slot-has-quantity') }}"">
|
||||||
|
<option value="1">{{ __('bookingproduct::app.admin.catalog.products.yes') }}</option>
|
||||||
|
<option value="0">{{ __('bookingproduct::app.admin.catalog.products.no') }}</option>
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<span class="control-error" v-if="errors.has('booking[slot_has_quantity]')">@{{ errors.first('booking[slot_has_quantity]') }}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="control-group" :class="[errors.has('booking[same_slot_all_days]') ? 'has-error' : '']">
|
||||||
|
<label class="required">{{ __('bookingproduct::app.admin.catalog.products.same-slot-all-days') }}</label>
|
||||||
|
|
||||||
|
<select v-validate="'required'" name="booking[same_slot_all_days]" v-model="appointment_booking.same_slot_all_days" class="control" data-vv-as=""{{ __('bookingproduct::app.admin.catalog.products.same-slot-all-days') }}"">
|
||||||
|
<option value="1">{{ __('bookingproduct::app.admin.catalog.products.yes') }}</option>
|
||||||
|
<option value="0">{{ __('bookingproduct::app.admin.catalog.products.no') }}</option>
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<span class="control-error" v-if="errors.has('booking[same_slot_all_days]')">@{{ errors.first('booking[same_slot_all_days]') }}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="section">
|
||||||
|
<div class="secton-title">
|
||||||
|
<span>{{ __('bookingproduct::app.admin.catalog.products.slots') }}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="section-content">
|
||||||
|
|
||||||
|
<slot-list
|
||||||
|
booking-type="appointment_slot"
|
||||||
|
:same-slot-all-days="appointment_booking.same_slot_all_days"
|
||||||
|
:slot-has-quantity="appointment_booking.slot_has_quantity">
|
||||||
|
</slot-list>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
Vue.component('appointment-booking', {
|
||||||
|
|
||||||
|
template: '#appointment-booking-template',
|
||||||
|
|
||||||
|
inject: ['$validator'],
|
||||||
|
|
||||||
|
data: function() {
|
||||||
|
return {
|
||||||
|
appointment_booking: bookingProduct && bookingProduct.appointment_slot ? bookingProduct.appointment_slot : {
|
||||||
|
duration: 45,
|
||||||
|
|
||||||
|
break_time: 15,
|
||||||
|
|
||||||
|
available_every_week: 1,
|
||||||
|
|
||||||
|
available_from: '',
|
||||||
|
|
||||||
|
available_to: '',
|
||||||
|
|
||||||
|
same_slot_all_days: 1,
|
||||||
|
|
||||||
|
slot_has_quantity: 1,
|
||||||
|
|
||||||
|
slots: []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
@endpush
|
||||||
|
|
@ -0,0 +1,311 @@
|
||||||
|
{!! view_render_event('bagisto.admin.catalog.product.edit_form_accordian.booking.table.before', ['product' => $product]) !!}
|
||||||
|
|
||||||
|
<default-booking></default-booking>
|
||||||
|
|
||||||
|
{!! view_render_event('bagisto.admin.catalog.product.edit_form_accordian.booking.table.after', ['product' => $product]) !!}
|
||||||
|
|
||||||
|
|
||||||
|
@section('css')
|
||||||
|
<style>
|
||||||
|
.has-control-group .control-group {
|
||||||
|
width: 50%;
|
||||||
|
float: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.has-control-group .control-group:first-child {
|
||||||
|
padding-right: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.has-control-group .control-group:last-child {
|
||||||
|
padding-left: 10px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
@stop
|
||||||
|
|
||||||
|
@push('scripts')
|
||||||
|
@parent
|
||||||
|
|
||||||
|
<script type="text/x-template" id="default-booking-template">
|
||||||
|
<div>
|
||||||
|
<div class="control-group" :class="[errors.has('booking[booking_type]') ? 'has-error' : '']">
|
||||||
|
<label class="required">{{ __('bookingproduct::app.admin.catalog.products.type') }}</label>
|
||||||
|
|
||||||
|
<select v-validate="'required'" name="booking[booking_type]" v-model="default_booking.booking_type" class="control" data-vv-as=""{{ __('bookingproduct::app.admin.catalog.products.type') }}"">
|
||||||
|
<option value="many">{{ __('bookingproduct::app.admin.catalog.products.many-bookings-for-one-day') }}</option>
|
||||||
|
<option value="one">{{ __('bookingproduct::app.admin.catalog.products.one-booking-for-many-days') }}</option>
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<span class="control-error" v-if="errors.has('booking[booking_type]')">@{{ errors.first('booking[booking_type]') }}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="control-group" :class="[errors.has('booking[available_from]') ? 'has-error' : '']">
|
||||||
|
<label class="required">{{ __('bookingproduct::app.admin.catalog.products.available-from') }}</label>
|
||||||
|
|
||||||
|
<date>
|
||||||
|
<input type="text" v-validate="'required'" name="booking[available_from]" v-model="default_booking.available_from" class="control" data-vv-as=""{{ __('bookingproduct::app.admin.catalog.products.available-from') }}""/>
|
||||||
|
</date>
|
||||||
|
|
||||||
|
<span class="control-error" v-if="errors.has('booking[available_from]')">@{{ errors.first('booking[available_from]') }}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="control-group" :class="[errors.has('booking[available_to]') ? 'has-error' : '']">
|
||||||
|
<label class="required">{{ __('bookingproduct::app.admin.catalog.products.available-to') }}</label>
|
||||||
|
|
||||||
|
<date>
|
||||||
|
<input type="text" v-validate="'required'" name="booking[available_to]" v-model="default_booking.available_to" class="control" data-vv-as=""{{ __('bookingproduct::app.admin.catalog.products.available-to') }}""/>
|
||||||
|
</date>
|
||||||
|
|
||||||
|
<span class="control-error" v-if="errors.has('booking[available_to]')">@{{ errors.first('booking[available_to]') }}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-if="default_booking.booking_type == 'many'">
|
||||||
|
<div class="control-group" :class="[errors.has('booking[duration]') ? 'has-error' : '']">
|
||||||
|
<label class="required">{{ __('bookingproduct::app.admin.catalog.products.slot-duration') }}</label>
|
||||||
|
|
||||||
|
<input type="text" v-validate="'required|min_value:1'" name="booking[duration]" v-model="default_booking.duration" class="control" data-vv-as=""{{ __('bookingproduct::app.admin.catalog.products.slot-duration') }}""/>
|
||||||
|
|
||||||
|
<span class="control-error" v-if="errors.has('booking[duration]')">@{{ errors.first('booking[duration]') }}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="control-group" :class="[errors.has('booking[break_time]') ? 'has-error' : '']">
|
||||||
|
<label class="required">{{ __('bookingproduct::app.admin.catalog.products.break-time') }}</label>
|
||||||
|
|
||||||
|
<input type="text" v-validate="'required|min_value:1'" name="booking[break_time]" v-model="default_booking.break_time" class="control" data-vv-as=""{{ __('bookingproduct::app.admin.catalog.products.break-time') }}""/>
|
||||||
|
|
||||||
|
<span class="control-error" v-if="errors.has('booking[break_time]')">@{{ errors.first('booking[break_time]') }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="section">
|
||||||
|
<div class="secton-title">
|
||||||
|
<span>{{ __('bookingproduct::app.admin.catalog.products.slots') }}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="section-content">
|
||||||
|
|
||||||
|
<div class="slot-list table" v-if="default_booking.booking_type == 'many'">
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>{{ __('bookingproduct::app.admin.catalog.products.day') }}</th>
|
||||||
|
<th>{{ __('bookingproduct::app.admin.catalog.products.from') }}</th>
|
||||||
|
<th>{{ __('bookingproduct::app.admin.catalog.products.to') }}</th>
|
||||||
|
<th>{{ __('bookingproduct::app.admin.catalog.products.status') }}</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
|
||||||
|
<tbody>
|
||||||
|
|
||||||
|
<tr v-for="(day, index) in days">
|
||||||
|
<td>@{{ day }}</td>
|
||||||
|
|
||||||
|
<td>
|
||||||
|
<div class="control-group" :class="[errors.has('booking[slots][' + index + '][from]') ? 'has-error' : '']">
|
||||||
|
<time-component>
|
||||||
|
<input type="text" v-validate="parseInt(slots.many[index].status) ? 'required': ''" :name="'booking[slots][' + index + '][from]'" class="control" v-model="slots.many[index].from" data-vv-as=""{{ __('bookingproduct::app.admin.catalog.products.from') }}"">
|
||||||
|
</time-component>
|
||||||
|
|
||||||
|
<span class="control-error" v-if="errors.has('booking[slots][' + index + '][from]')">
|
||||||
|
@{{ errors.first('booking[slots][' + index + '][from]') }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
|
||||||
|
<td>
|
||||||
|
<div class="control-group" :class="[errors.has('booking[slots][' + index + '][to]') ? 'has-error' : '']">
|
||||||
|
<time-component>
|
||||||
|
<input type="text" v-validate="parseInt(slots.many[index].status) ? 'required': ''" :name="'booking[slots][' + index + '][to]'" class="control" v-model="slots.many[index].to" data-vv-as=""{{ __('bookingproduct::app.admin.catalog.products.to') }}"">
|
||||||
|
</time-component>
|
||||||
|
|
||||||
|
<span class="control-error" v-if="errors.has('booking[slots][' + index + '][to]')">
|
||||||
|
@{{ errors.first('booking[slots][' + index + '][to]') }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
|
||||||
|
<td>
|
||||||
|
<div class="control-group" :class="[errors.has('booking[slots][' + index + '][status]') ? 'has-error' : '']">
|
||||||
|
<select v-validate="'required'" :name="'booking[slots][' + index + '][status]'" class="control" v-model="slots.many[index].status" data-vv-as=""{{ __('bookingproduct::app.admin.catalog.products.status') }}"">
|
||||||
|
<option value="1">{{ __('bookingproduct::app.admin.catalog.products.open') }}</option>
|
||||||
|
<option value="0">{{ __('bookingproduct::app.admin.catalog.products.close') }}</option>
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<span class="control-error" v-if="errors.has('booking[slots][' + index + '][status]')">@{{ errors.first('booking[slots][' + index + '][status]') }}</span>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="slot-list table" v-if="default_booking.booking_type == 'one'">
|
||||||
|
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>{{ __('bookingproduct::app.admin.catalog.products.from') }}</th>
|
||||||
|
<th>{{ __('bookingproduct::app.admin.catalog.products.to') }}</th>
|
||||||
|
<th></th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
|
||||||
|
<tbody>
|
||||||
|
|
||||||
|
<default-slot-item
|
||||||
|
v-for="(slot, index) in slots.one"
|
||||||
|
:key="index"
|
||||||
|
:slot-item="slot"
|
||||||
|
:control-name="'booking[slots][' + index + ']'"
|
||||||
|
@onRemoveSlot="removeSlot($event)">
|
||||||
|
</default-slot-item>
|
||||||
|
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<button type="button" class="btn btn-lg btn-primary" style="margin-top: 20px" @click="addSlot()">
|
||||||
|
{{ __('bookingproduct::app.admin.catalog.products.add-slot') }}
|
||||||
|
</button>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script type="text/x-template" id="default-slot-item-template">
|
||||||
|
<tr>
|
||||||
|
<td class="has-control-group">
|
||||||
|
<div class="control-group" :class="[errors.has(controlName + '[from_day]') ? 'has-error' : '']">
|
||||||
|
<select v-validate="'required'" :name="controlName + '[from_day]'" v-model="slotItem.from_day" class="control" data-vv-as=""{{ __('bookingproduct::app.admin.catalog.products.day') }}"">
|
||||||
|
<option v-for="(day, index) in $parent.days" :value="index">@{{ day }}</option>
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<span class="control-error" v-if="errors.has(controlName + '[from_day]')">@{{ errors.first(controlName + '[from_day]') }}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="control-group" :class="[errors.has(controlName + '[from]') ? 'has-error' : '']">
|
||||||
|
<time-component>
|
||||||
|
<input type="text" v-validate="'required'" :name="controlName + '[from]'" v-model="slotItem.from" class="control" data-vv-as=""{{ __('bookingproduct::app.admin.catalog.products.from') }}"">
|
||||||
|
</time-component>
|
||||||
|
|
||||||
|
<span class="control-error" v-if="errors.has(controlName + '[from]')">
|
||||||
|
@{{ errors.first(controlName + '[from]') }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
|
||||||
|
<td class="has-control-group">
|
||||||
|
<div class="control-group" :class="[errors.has(controlName + '[to_day]') ? 'has-error' : '']">
|
||||||
|
<select v-validate="'required'" :name="controlName + '[to_day]'" v-model="slotItem.to_day" class="control" data-vv-as=""{{ __('bookingproduct::app.admin.catalog.products.day') }}"">
|
||||||
|
<option v-for="(day, index) in $parent.days" :value="index">@{{ day }}</option>
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<span class="control-error" v-if="errors.has(controlName + '[to_day]')">@{{ errors.first(controlName + '[to_day]') }}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="control-group" :class="[errors.has(controlName + '[to]') ? 'has-error' : '']">
|
||||||
|
<time-component>
|
||||||
|
<input type="text" v-validate="'required'" :name="controlName + '[to]'" v-model="slotItem.to" class="control" data-vv-as=""{{ __('bookingproduct::app.admin.catalog.products.to') }}"">
|
||||||
|
</time-component>
|
||||||
|
|
||||||
|
<span class="control-error" v-if="errors.has(controlName + '[to]')">
|
||||||
|
@{{ errors.first(controlName + '[to]') }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
|
||||||
|
<td>
|
||||||
|
<i class="icon remove-icon" @click="removeSlot()"></i>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
Vue.component('default-booking', {
|
||||||
|
|
||||||
|
template: '#default-booking-template',
|
||||||
|
|
||||||
|
inject: ['$validator'],
|
||||||
|
|
||||||
|
data: function() {
|
||||||
|
return {
|
||||||
|
default_booking: bookingProduct && bookingProduct.default_slot ? bookingProduct.default_slot : {
|
||||||
|
booking_type: 'one',
|
||||||
|
|
||||||
|
duration: 45,
|
||||||
|
|
||||||
|
break_time: 15,
|
||||||
|
|
||||||
|
available_from: '',
|
||||||
|
|
||||||
|
available_to: '',
|
||||||
|
|
||||||
|
slots: []
|
||||||
|
},
|
||||||
|
|
||||||
|
slots: {
|
||||||
|
'one': [],
|
||||||
|
|
||||||
|
'many': [
|
||||||
|
{'from': '', 'to': '', 'status': 0},
|
||||||
|
{'from': '', 'to': '', 'status': 1},
|
||||||
|
{'from': '', 'to': '', 'status': 1},
|
||||||
|
{'from': '', 'to': '', 'status': 1},
|
||||||
|
{'from': '', 'to': '', 'status': 1},
|
||||||
|
{'from': '', 'to': '', 'status': 1},
|
||||||
|
{'from': '', 'to': '', 'status': 1}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
|
||||||
|
days: [
|
||||||
|
"{{ __('bookingproduct::app.admin.catalog.products.sunday') }}",
|
||||||
|
"{{ __('bookingproduct::app.admin.catalog.products.monday') }}",
|
||||||
|
"{{ __('bookingproduct::app.admin.catalog.products.tuesday') }}",
|
||||||
|
"{{ __('bookingproduct::app.admin.catalog.products.wednesday') }}",
|
||||||
|
"{{ __('bookingproduct::app.admin.catalog.products.thursday') }}",
|
||||||
|
"{{ __('bookingproduct::app.admin.catalog.products.friday') }}",
|
||||||
|
"{{ __('bookingproduct::app.admin.catalog.products.saturday') }}"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
created: function() {
|
||||||
|
if (this.default_booking.booking_type == 'one') {
|
||||||
|
this.slots['one'] = this.default_booking.slots ? this.default_booking.slots : [];
|
||||||
|
} else {
|
||||||
|
if (this.default_booking.slots)
|
||||||
|
this.slots['many'] = this.default_booking.slots;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
addSlot: function () {
|
||||||
|
this.slots.one.push({ 'from_day': 0, 'from': '', 'to_day': 0, 'to': '' });
|
||||||
|
},
|
||||||
|
|
||||||
|
removeSlot: function(slot) {
|
||||||
|
let index = this.slots.one.indexOf(slot)
|
||||||
|
|
||||||
|
this.slots.one.splice(index, 1)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Vue.component('default-slot-item', {
|
||||||
|
|
||||||
|
template: '#default-slot-item-template',
|
||||||
|
|
||||||
|
props: ['slotItem', 'controlName'],
|
||||||
|
|
||||||
|
inject: ['$validator'],
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
removeSlot: function() {
|
||||||
|
this.$emit('onRemoveSlot', this.slotItem)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
@endpush
|
||||||
|
|
@ -0,0 +1,186 @@
|
||||||
|
{!! view_render_event('bagisto.admin.catalog.product.edit_form_accordian.booking.event.before', ['product' => $product]) !!}
|
||||||
|
|
||||||
|
<event-booking></event-booking>
|
||||||
|
|
||||||
|
{!! view_render_event('bagisto.admin.catalog.product.edit_form_accordian.booking.event.after', ['product' => $product]) !!}
|
||||||
|
|
||||||
|
@push('scripts')
|
||||||
|
@parent
|
||||||
|
|
||||||
|
<script type="text/x-template" id="event-booking-template">
|
||||||
|
<div>
|
||||||
|
<div class="control-group" :class="[errors.has('booking[available_from]') ? 'has-error' : '']">
|
||||||
|
<label class="required">{{ __('bookingproduct::app.admin.catalog.products.event-start-date') }}</label>
|
||||||
|
|
||||||
|
<datetime>
|
||||||
|
<input type="text" v-validate="'required'" name="booking[available_from]" v-model="event_booking.available_from" class="control" data-vv-as=""{{ __('bookingproduct::app.admin.catalog.products.event-start-date') }}""/>
|
||||||
|
</datetime>
|
||||||
|
|
||||||
|
<span class="control-error" v-if="errors.has('booking[available_from]')">@{{ errors.first('booking[available_from]') }}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="control-group" :class="[errors.has('booking[available_to]') ? 'has-error' : '']">
|
||||||
|
<label class="required">{{ __('bookingproduct::app.admin.catalog.products.event-end-date') }}</label>
|
||||||
|
|
||||||
|
<datetime>
|
||||||
|
<input type="text" v-validate="'required'" name="booking[available_to]" v-model="event_booking.available_to" class="control" data-vv-as=""{{ __('bookingproduct::app.admin.catalog.products.event-end-date') }}""/>
|
||||||
|
</datetime>
|
||||||
|
|
||||||
|
<span class="control-error" v-if="errors.has('booking[available_to]')">@{{ errors.first('booking[available_to]') }}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="section">
|
||||||
|
<div class="secton-title">
|
||||||
|
<span>{{ __('bookingproduct::app.admin.catalog.products.tickets') }}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="section-content">
|
||||||
|
|
||||||
|
<ticket-list :tickets="event_booking.slots"></ticket-list>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script type="text/x-template" id="ticket-list-template">
|
||||||
|
<div class="ticket-list table">
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>{{ __('bookingproduct::app.admin.catalog.products.name') }}</th>
|
||||||
|
<th>{{ __('bookingproduct::app.admin.catalog.products.price') }}</th>
|
||||||
|
<th>{{ __('bookingproduct::app.admin.catalog.products.quantity') }}</th>
|
||||||
|
<th>{{ __('bookingproduct::app.admin.catalog.products.description') }}</th>
|
||||||
|
<th class="actions"></th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
|
||||||
|
<tbody>
|
||||||
|
<ticket-item
|
||||||
|
v-for="(ticket, index) in tickets"
|
||||||
|
:key="index"
|
||||||
|
:ticket-item="ticket"
|
||||||
|
:control-name="'booking[slots][' + index + ']'"
|
||||||
|
@onRemoveTicket="removeTicket($event)"
|
||||||
|
></ticket-item>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<button type="button" class="btn btn-lg btn-primary" style="margin-top: 20px" @click="addTicket()">
|
||||||
|
{{ __('bookingproduct::app.admin.catalog.products.add-ticket') }}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script type="text/x-template" id="ticket-item-template">
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<div class="control-group" :class="[errors.has(controlName + '[name]') ? 'has-error' : '']">
|
||||||
|
<input type="text" v-validate="'required'" :name="controlName + '[name]'" v-model="ticketItem.name" class="control" data-vv-as=""{{ __('bookingproduct::app.admin.catalog.products.name') }}"">
|
||||||
|
|
||||||
|
<span class="control-error" v-if="errors.has(controlName + '[name]')">
|
||||||
|
@{{ errors.first(controlName + '[name]') }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
|
||||||
|
<td>
|
||||||
|
<div class="control-group" :class="[errors.has(controlName + '[price]') ? 'has-error' : '']">
|
||||||
|
<input type="text" v-validate="'required'" :name="controlName + '[price]'" v-model="ticketItem.price" class="control" data-vv-as=""{{ __('bookingproduct::app.admin.catalog.products.price') }}"">
|
||||||
|
|
||||||
|
<span class="control-error" v-if="errors.has(controlName + '[price]')">
|
||||||
|
@{{ errors.first(controlName + '[price]') }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
|
||||||
|
<td>
|
||||||
|
<div class="control-group" :class="[errors.has(controlName + '[qty]') ? 'has-error' : '']">
|
||||||
|
<input type="text" v-validate="'required|min_value:0'" :name="controlName + '[qty]'" v-model="ticketItem.qty" class="control" data-vv-as=""{{ __('bookingproduct::app.admin.catalog.products.qty') }}"">
|
||||||
|
|
||||||
|
<span class="control-error" v-if="errors.has(controlName + '[qty]')">
|
||||||
|
@{{ errors.first(controlName + '[qty]') }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
|
||||||
|
<td>
|
||||||
|
<div class="control-group" :class="[errors.has(controlName + '[description]') ? 'has-error' : '']">
|
||||||
|
<textarea type="text" v-validate="'required'" :name="controlName + '[description]'" v-model="ticketItem.description" class="control" data-vv-as=""{{ __('bookingproduct::app.admin.catalog.products.description') }}""></textarea>
|
||||||
|
|
||||||
|
<span class="control-error" v-if="errors.has(controlName + '[description]')">
|
||||||
|
@{{ errors.first(controlName + '[description]') }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
|
||||||
|
<td>
|
||||||
|
<i class="icon remove-icon" @click="removeTicket()"></i>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
Vue.component('event-booking', {
|
||||||
|
|
||||||
|
template: '#event-booking-template',
|
||||||
|
|
||||||
|
inject: ['$validator'],
|
||||||
|
|
||||||
|
data: function() {
|
||||||
|
return {
|
||||||
|
event_booking: bookingProduct && bookingProduct.event_slot ? bookingProduct.event_slot : {
|
||||||
|
available_from: '',
|
||||||
|
|
||||||
|
available_to: '',
|
||||||
|
|
||||||
|
slots: []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Vue.component('ticket-list', {
|
||||||
|
|
||||||
|
template: '#ticket-list-template',
|
||||||
|
|
||||||
|
props: ['tickets'],
|
||||||
|
|
||||||
|
inject: ['$validator'],
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
addTicket: function (dayIndex = null) {
|
||||||
|
this.tickets.push({
|
||||||
|
'name': '',
|
||||||
|
'price': '',
|
||||||
|
'qty': 0,
|
||||||
|
'description': ''
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
removeTicket: function(ticket) {
|
||||||
|
let index = this.tickets.indexOf(ticket)
|
||||||
|
|
||||||
|
this.tickets.splice(index, 1)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Vue.component('ticket-item', {
|
||||||
|
|
||||||
|
template: '#ticket-item-template',
|
||||||
|
|
||||||
|
props: ['ticketItem', 'controlName'],
|
||||||
|
|
||||||
|
inject: ['$validator'],
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
removeTicket: function() {
|
||||||
|
this.$emit('onRemoveTicket', this.ticketItem)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
@endpush
|
||||||
|
|
@ -0,0 +1,151 @@
|
||||||
|
{!! view_render_event('bagisto.admin.catalog.product.edit_form_accordian.booking.rental.before', ['product' => $product]) !!}
|
||||||
|
|
||||||
|
<rental-booking></rental-booking>
|
||||||
|
|
||||||
|
{!! view_render_event('bagisto.admin.catalog.product.edit_form_accordian.booking.rental.after', ['product' => $product]) !!}
|
||||||
|
|
||||||
|
@push('scripts')
|
||||||
|
@parent
|
||||||
|
|
||||||
|
<script type="text/x-template" id="rental-booking-template">
|
||||||
|
<div>
|
||||||
|
<div class="control-group" :class="[errors.has('booking[renting_type]') ? 'has-error' : '']">
|
||||||
|
<label class="required">{{ __('bookingproduct::app.admin.catalog.products.renting-type') }}</label>
|
||||||
|
|
||||||
|
<select v-validate="'required'" name="booking[renting_type]" v-model="rental_booking.renting_type" class="control" data-vv-as=""{{ __('bookingproduct::app.admin.catalog.products.renting-type') }}"">
|
||||||
|
<option value="daily">{{ __('bookingproduct::app.admin.catalog.products.daily') }}</option>
|
||||||
|
<option value="hourly">{{ __('bookingproduct::app.admin.catalog.products.hourly') }}</option>
|
||||||
|
<option value="daily_hourly">{{ __('bookingproduct::app.admin.catalog.products.daily-hourly') }}</option>
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<span class="control-error" v-if="errors.has('booking[renting_type]')">@{{ errors.first('booking[renting_type]') }}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-if="rental_booking.renting_type == 'daily' || rental_booking.renting_type == 'daily_hourly'">
|
||||||
|
<div class="control-group" :class="[errors.has('booking[daily_price]') ? 'has-error' : '']">
|
||||||
|
<label class="required">{{ __('bookingproduct::app.admin.catalog.products.daily-price') }}</label>
|
||||||
|
|
||||||
|
<input type="text" v-validate="'required'" name="booking[daily_price]" v-model="rental_booking.daily_price" class="control" data-vv-as=""{{ __('bookingproduct::app.admin.catalog.products.daily-price') }}""/>
|
||||||
|
|
||||||
|
<span class="control-error" v-if="errors.has('booking[daily_price]')">@{{ errors.first('booking[daily_price]') }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-if="rental_booking.renting_type == 'hourly' || rental_booking.renting_type == 'daily_hourly'">
|
||||||
|
<div class="control-group" :class="[errors.has('booking[hourly_price]') ? 'has-error' : '']">
|
||||||
|
<label class="required">{{ __('bookingproduct::app.admin.catalog.products.hourly-price') }}</label>
|
||||||
|
|
||||||
|
<input type="text" v-validate="'required'" name="booking[hourly_price]" v-model="rental_booking.hourly_price" class="control" data-vv-as=""{{ __('bookingproduct::app.admin.catalog.products.hourly-price') }}""/>
|
||||||
|
|
||||||
|
<span class="control-error" v-if="errors.has('booking[hourly_price]')">@{{ errors.first('booking[hourly_price]') }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="control-group" :class="[errors.has('booking[available_every_week]') ? 'has-error' : '']">
|
||||||
|
<label class="required">{{ __('bookingproduct::app.admin.catalog.products.available-every-week') }}</label>
|
||||||
|
|
||||||
|
<select v-validate="'required'" name="booking[available_every_week]" v-model="rental_booking.available_every_week" class="control" data-vv-as=""{{ __('bookingproduct::app.admin.catalog.products.available-every-week') }}"">
|
||||||
|
<option value="1">{{ __('bookingproduct::app.admin.catalog.products.yes') }}</option>
|
||||||
|
<option value="0">{{ __('bookingproduct::app.admin.catalog.products.no') }}</option>
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<span class="control-error" v-if="errors.has('booking[available_every_week]')">@{{ errors.first('booking[available_every_week]') }}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-if="! parseInt(rental_booking.available_every_week)">
|
||||||
|
<div class="control-group" :class="[errors.has('booking[available_from]') ? 'has-error' : '']">
|
||||||
|
<label class="required">{{ __('bookingproduct::app.admin.catalog.products.available-from') }}</label>
|
||||||
|
|
||||||
|
<date>
|
||||||
|
<input type="text" v-validate="'required'" name="booking[available_from]" v-model="rental_booking.available_from" class="control" data-vv-as=""{{ __('bookingproduct::app.admin.catalog.products.available-from') }}""/>
|
||||||
|
</date>
|
||||||
|
|
||||||
|
<span class="control-error" v-if="errors.has('booking[available_from]')">@{{ errors.first('booking[available_from]') }}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="control-group" :class="[errors.has('booking[available_to]') ? 'has-error' : '']">
|
||||||
|
<label class="required">{{ __('bookingproduct::app.admin.catalog.products.available-to') }}</label>
|
||||||
|
|
||||||
|
<date>
|
||||||
|
<input type="text" v-validate="'required'" name="booking[available_to]" v-model="rental_booking.available_to" class="control" data-vv-as=""{{ __('bookingproduct::app.admin.catalog.products.available-to') }}""/>
|
||||||
|
</date>
|
||||||
|
|
||||||
|
<span class="control-error" v-if="errors.has('booking[available_to]')">@{{ errors.first('booking[available_to]') }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-if="rental_booking.renting_type == 'hourly' || rental_booking.renting_type == 'daily_hourly'">
|
||||||
|
<div class="control-group" :class="[errors.has('booking[slot_has_quantity]') ? 'has-error' : '']">
|
||||||
|
<label class="required">{{ __('bookingproduct::app.admin.catalog.products.slot-has-quantity') }}</label>
|
||||||
|
|
||||||
|
<select v-validate="'required'" name="booking[slot_has_quantity]" v-model="rental_booking.slot_has_quantity" class="control" data-vv-as=""{{ __('bookingproduct::app.admin.catalog.products.slot-has-quantity') }}"">
|
||||||
|
<option value="1">{{ __('bookingproduct::app.admin.catalog.products.yes') }}</option>
|
||||||
|
<option value="0">{{ __('bookingproduct::app.admin.catalog.products.no') }}</option>
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<span class="control-error" v-if="errors.has('booking[slot_has_quantity]')">@{{ errors.first('booking[slot_has_quantity]') }}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="control-group" :class="[errors.has('booking[same_slot_all_days]') ? 'has-error' : '']">
|
||||||
|
<label class="required">{{ __('bookingproduct::app.admin.catalog.products.same-slot-all-days') }}</label>
|
||||||
|
|
||||||
|
<select v-validate="'required'" name="booking[same_slot_all_days]" v-model="rental_booking.same_slot_all_days" class="control" data-vv-as=""{{ __('bookingproduct::app.admin.catalog.products.same-slot-all-days') }}"">
|
||||||
|
<option value="1">{{ __('bookingproduct::app.admin.catalog.products.yes') }}</option>
|
||||||
|
<option value="0">{{ __('bookingproduct::app.admin.catalog.products.no') }}</option>
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<span class="control-error" v-if="errors.has('booking[same_slot_all_days]')">@{{ errors.first('booking[same_slot_all_days]') }}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="section">
|
||||||
|
<div class="secton-title">
|
||||||
|
<span>{{ __('bookingproduct::app.admin.catalog.products.slots') }}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="section-content">
|
||||||
|
|
||||||
|
<slot-list
|
||||||
|
booking-type="rental_slot"
|
||||||
|
:same-slot-all-days="rental_booking.same_slot_all_days"
|
||||||
|
:slot-has-quantity="rental_booking.slot_has_quantity">
|
||||||
|
</slot-list>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
Vue.component('rental-booking', {
|
||||||
|
|
||||||
|
template: '#rental-booking-template',
|
||||||
|
|
||||||
|
inject: ['$validator'],
|
||||||
|
|
||||||
|
data: function() {
|
||||||
|
return {
|
||||||
|
rental_booking: bookingProduct && bookingProduct.rental_slot ? bookingProduct.rental_slot : {
|
||||||
|
renting_type: 'daily',
|
||||||
|
|
||||||
|
daily_price: '',
|
||||||
|
|
||||||
|
hourly_price: '',
|
||||||
|
|
||||||
|
available_every_week: 1,
|
||||||
|
|
||||||
|
available_from: '',
|
||||||
|
|
||||||
|
available_to: '',
|
||||||
|
|
||||||
|
same_slot_all_days: 1,
|
||||||
|
|
||||||
|
slot_has_quantity: 1,
|
||||||
|
|
||||||
|
slots: []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
@endpush
|
||||||
|
|
@ -0,0 +1,211 @@
|
||||||
|
<script type="text/x-template" id="slot-list-template">
|
||||||
|
<div>
|
||||||
|
<div class="slot-list table" v-if="parseInt(sameSlotAllDays)">
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>{{ __('bookingproduct::app.admin.catalog.products.from') }}</th>
|
||||||
|
<th>{{ __('bookingproduct::app.admin.catalog.products.to') }}</th>
|
||||||
|
<th v-if="parseInt(slotHasQuantity)">{{ __('bookingproduct::app.admin.catalog.products.qty') }}</th>
|
||||||
|
<th class="actions"></th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
|
||||||
|
<tbody>
|
||||||
|
<slot-item
|
||||||
|
v-for="(slot, index) in slots['same_for_week']"
|
||||||
|
:key="index"
|
||||||
|
:slot-item="slot"
|
||||||
|
:control-name="'booking[slots][' + index + ']'"
|
||||||
|
:slot-has-quantity="slotHasQuantity"
|
||||||
|
@onRemoveSlot="removeSlot($event)">
|
||||||
|
</slot-item>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<button type="button" class="btn btn-lg btn-primary" style="margin-top: 20px" @click="addSlot()">
|
||||||
|
{{ __('bookingproduct::app.admin.catalog.products.add-slot') }}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="slot-list table" v-else>
|
||||||
|
<accordian
|
||||||
|
v-for="(day, dayIndex) in week_days"
|
||||||
|
:key="dayIndex"
|
||||||
|
:title="day"
|
||||||
|
:active="false">
|
||||||
|
|
||||||
|
<div slot="header">
|
||||||
|
<i class="icon expand-icon left"></i>
|
||||||
|
<h1>@{{ day }}</h1>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div slot="body">
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>{{ __('bookingproduct::app.admin.catalog.products.from') }}</th>
|
||||||
|
<th>{{ __('bookingproduct::app.admin.catalog.products.to') }}</th>
|
||||||
|
<th v-if="parseInt(slotHasQuantity)">{{ __('bookingproduct::app.admin.catalog.products.qty') }}</th>
|
||||||
|
<th class="actions"></th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
|
||||||
|
<tbody v-if="slots['different_for_week'][dayIndex] && slots['different_for_week'][dayIndex].length">
|
||||||
|
<slot-item
|
||||||
|
v-for="(slot, slotIndex) in slots['different_for_week'][dayIndex]"
|
||||||
|
:key="dayIndex + '_' + slotIndex"
|
||||||
|
:slot-item="slot"
|
||||||
|
:control-name="'booking[slots][' + dayIndex + '][' + slotIndex + ']'"
|
||||||
|
:slot-has-quantity="slotHasQuantity"
|
||||||
|
@onRemoveSlot="removeSlot($event, dayIndex)"
|
||||||
|
></slot-item>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<button type="button" class="btn btn-lg btn-primary" style="margin-top: 20px" @click="addSlot(dayIndex)">
|
||||||
|
{{ __('bookingproduct::app.admin.catalog.products.add-slot') }}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</accordian>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script type="text/x-template" id="slot-item-template">
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<div class="control-group" :class="[errors.has(controlName + '[from]') ? 'has-error' : '']">
|
||||||
|
<time-component>
|
||||||
|
<input type="text" v-validate="'required'" :name="controlName + '[from]'" v-model="slotItem.from" class="control" data-vv-as=""{{ __('bookingproduct::app.admin.catalog.products.from') }}"">
|
||||||
|
</time-component>
|
||||||
|
|
||||||
|
<span class="control-error" v-if="errors.has(controlName + '[from]')">
|
||||||
|
@{{ errors.first(controlName + '[from]') }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
|
||||||
|
<td>
|
||||||
|
<div class="control-group" :class="[errors.has(controlName + '[to]') ? 'has-error' : '']">
|
||||||
|
<time-component>
|
||||||
|
<input type="text" v-validate="'required'" :name="controlName + '[to]'" v-model="slotItem.to" class="control" data-vv-as=""{{ __('bookingproduct::app.admin.catalog.products.to') }}"">
|
||||||
|
</time-component>
|
||||||
|
|
||||||
|
<span class="control-error" v-if="errors.has(controlName + '[to]')">
|
||||||
|
@{{ errors.first(controlName + '[to]') }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
|
||||||
|
<td v-if="parseInt(slotHasQuantity)">
|
||||||
|
<div class="control-group" :class="[errors.has(controlName + '[qty]') ? 'has-error' : '']">
|
||||||
|
<input type="text" v-validate="'required|min_value:0'" :name="controlName + '[qty]'" v-model="slotItem.qty" class="control" data-vv-as=""{{ __('bookingproduct::app.admin.catalog.products.qty') }}"">
|
||||||
|
|
||||||
|
<span class="control-error" v-if="errors.has(controlName + '[qty]')">
|
||||||
|
@{{ errors.first(controlName + '[qty]') }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
|
||||||
|
<td>
|
||||||
|
<i class="icon remove-icon" @click="removeSlot()"></i>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
Vue.component('slot-list', {
|
||||||
|
|
||||||
|
template: '#slot-list-template',
|
||||||
|
|
||||||
|
props: ['bookingType', 'sameSlotAllDays', 'slotHasQuantity'],
|
||||||
|
|
||||||
|
inject: ['$validator'],
|
||||||
|
|
||||||
|
data: function() {
|
||||||
|
return {
|
||||||
|
slots: {
|
||||||
|
'same_for_week': [],
|
||||||
|
|
||||||
|
'different_for_week': [[], [], [], [], [], [], []]
|
||||||
|
},
|
||||||
|
|
||||||
|
week_days: [
|
||||||
|
"{{ __('bookingproduct::app.admin.catalog.products.sunday') }}",
|
||||||
|
"{{ __('bookingproduct::app.admin.catalog.products.monday') }}",
|
||||||
|
"{{ __('bookingproduct::app.admin.catalog.products.tuesday') }}",
|
||||||
|
"{{ __('bookingproduct::app.admin.catalog.products.wednesday') }}",
|
||||||
|
"{{ __('bookingproduct::app.admin.catalog.products.thursday') }}",
|
||||||
|
"{{ __('bookingproduct::app.admin.catalog.products.friday') }}",
|
||||||
|
"{{ __('bookingproduct::app.admin.catalog.products.saturday') }}"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
created: function() {
|
||||||
|
if (! bookingProduct || ! bookingProduct[this.bookingType].slots || ! bookingProduct[this.bookingType].slots)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (bookingProduct[this.bookingType].same_slot_all_days) {
|
||||||
|
this.slots['same_for_week'] = bookingProduct[this.bookingType].slots;
|
||||||
|
} else {
|
||||||
|
this.slots['different_for_week'] = bookingProduct[this.bookingType].slots;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
addSlot: function (dayIndex = null) {
|
||||||
|
if (dayIndex !== null) {
|
||||||
|
if (this.slots['different_for_week'][dayIndex] == undefined)
|
||||||
|
this.slots['different_for_week'][dayIndex] = [];
|
||||||
|
|
||||||
|
var slot = {
|
||||||
|
'from': '',
|
||||||
|
'to': '',
|
||||||
|
'qty': 0
|
||||||
|
};
|
||||||
|
|
||||||
|
this.slots['different_for_week'][dayIndex].push(slot)
|
||||||
|
|
||||||
|
Vue.set(this.slots['different_for_week'], dayIndex, this.slots['different_for_week'][dayIndex])
|
||||||
|
} else {
|
||||||
|
var slot = {
|
||||||
|
'from': '',
|
||||||
|
'to': '',
|
||||||
|
'qty': 0
|
||||||
|
};
|
||||||
|
|
||||||
|
this.slots['same_for_week'].push(slot);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
removeSlot: function(slot, dayIndex = null) {
|
||||||
|
if (dayIndex != null) {
|
||||||
|
let index = this.slots['different_for_week'][dayIndex].indexOf(slot)
|
||||||
|
|
||||||
|
this.slots['different_for_week'][dayIndex].splice(index, 1)
|
||||||
|
} else {
|
||||||
|
let index = this.slots['same_for_week'].indexOf(slot)
|
||||||
|
|
||||||
|
this.slots['same_for_week'].splice(index, 1)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Vue.component('slot-item', {
|
||||||
|
|
||||||
|
template: '#slot-item-template',
|
||||||
|
|
||||||
|
props: ['slotItem', 'controlName', 'slotHasQuantity'],
|
||||||
|
|
||||||
|
inject: ['$validator'],
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
removeSlot: function() {
|
||||||
|
this.$emit('onRemoveSlot', this.slotItem)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
@ -0,0 +1,150 @@
|
||||||
|
{!! view_render_event('bagisto.admin.catalog.product.edit_form_accordian.booking.table.before', ['product' => $product]) !!}
|
||||||
|
|
||||||
|
<table-booking></table-booking>
|
||||||
|
|
||||||
|
{!! view_render_event('bagisto.admin.catalog.product.edit_form_accordian.booking.table.after', ['product' => $product]) !!}
|
||||||
|
|
||||||
|
@push('scripts')
|
||||||
|
@parent
|
||||||
|
|
||||||
|
<script type="text/x-template" id="table-booking-template">
|
||||||
|
<div>
|
||||||
|
<div class="control-group" :class="[errors.has('booking[price_type]') ? 'has-error' : '']">
|
||||||
|
<label class="required">{{ __('bookingproduct::app.admin.catalog.products.charged-per') }}</label>
|
||||||
|
|
||||||
|
<select v-validate="'required'" name="booking[price_type]" v-model="table_booking.price_type" class="control" data-vv-as=""{{ __('bookingproduct::app.admin.catalog.products.charged-per') }}"">
|
||||||
|
<option value="guest">{{ __('bookingproduct::app.admin.catalog.products.guest') }}</option>
|
||||||
|
<option value="table">{{ __('bookingproduct::app.admin.catalog.products.table') }}</option>
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<span class="control-error" v-if="errors.has('booking[price_type]')">@{{ errors.first('booking[price_type]') }}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-if="table_booking.price_type == 'table'" class="control-group" :class="[errors.has('booking[guest_limit]') ? 'has-error' : '']">
|
||||||
|
<label class="required">{{ __('bookingproduct::app.admin.catalog.products.guest-limit') }}</label>
|
||||||
|
|
||||||
|
<input type="text" v-validate="'required|min_value:1'" name="booking[guest_limit]" v-model="table_booking.guest_limit" class="control" data-vv-as=""{{ __('bookingproduct::app.admin.catalog.products.guest-limit') }}""/>
|
||||||
|
|
||||||
|
<span class="control-error" v-if="errors.has('booking[guest_limit]')">@{{ errors.first('booking[guest_limit]') }}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="control-group" :class="[errors.has('booking[duration]') ? 'has-error' : '']">
|
||||||
|
<label class="required">{{ __('bookingproduct::app.admin.catalog.products.slot-duration') }}</label>
|
||||||
|
|
||||||
|
<input type="text" v-validate="'required|min_value:1'" name="booking[duration]" v-model="table_booking.duration" class="control" data-vv-as=""{{ __('bookingproduct::app.admin.catalog.products.slot-duration') }}""/>
|
||||||
|
|
||||||
|
<span class="control-error" v-if="errors.has('booking[duration]')">@{{ errors.first('booking[duration]') }}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="control-group" :class="[errors.has('booking[break_time]') ? 'has-error' : '']">
|
||||||
|
<label class="required">{{ __('bookingproduct::app.admin.catalog.products.break-time') }}</label>
|
||||||
|
|
||||||
|
<input type="text" v-validate="'required|min_value:1'" name="booking[break_time]" v-model="table_booking.break_time" class="control" data-vv-as=""{{ __('bookingproduct::app.admin.catalog.products.break-time') }}""/>
|
||||||
|
|
||||||
|
<span class="control-error" v-if="errors.has('booking[break_time]')">@{{ errors.first('booking[break_time]') }}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="control-group" :class="[errors.has('booking[prevent_scheduling_before]') ? 'has-error' : '']">
|
||||||
|
<label class="required">{{ __('bookingproduct::app.admin.catalog.products.prevent-scheduling-before') }}</label>
|
||||||
|
|
||||||
|
<input type="text" v-validate="'required|min_value:1'" name="booking[prevent_scheduling_before]" v-model="table_booking.prevent_scheduling_before" class="control" data-vv-as=""{{ __('bookingproduct::app.admin.catalog.products.prevent-scheduling-before') }}""/>
|
||||||
|
|
||||||
|
<span class="control-error" v-if="errors.has('booking[prevent_scheduling_before]')">@{{ errors.first('booking[prevent_scheduling_before]') }}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="control-group" :class="[errors.has('booking[available_every_week]') ? 'has-error' : '']">
|
||||||
|
<label class="required">{{ __('bookingproduct::app.admin.catalog.products.available-every-week') }}</label>
|
||||||
|
|
||||||
|
<select v-validate="'required'" name="booking[available_every_week]" v-model="table_booking.available_every_week" class="control" data-vv-as=""{{ __('bookingproduct::app.admin.catalog.products.available-every-week') }}"">
|
||||||
|
<option value="1">{{ __('bookingproduct::app.admin.catalog.products.yes') }}</option>
|
||||||
|
<option value="0">{{ __('bookingproduct::app.admin.catalog.products.no') }}</option>
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<span class="control-error" v-if="errors.has('booking[available_every_week]')">@{{ errors.first('booking[available_every_week]') }}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-if="! parseInt(table_booking.available_every_week)">
|
||||||
|
<div class="control-group" :class="[errors.has('booking[available_from]') ? 'has-error' : '']">
|
||||||
|
<label class="required">{{ __('bookingproduct::app.admin.catalog.products.available-from') }}</label>
|
||||||
|
|
||||||
|
<date>
|
||||||
|
<input type="text" v-validate="'required'" name="booking[available_from]" v-model="table_booking.available_from" class="control" data-vv-as=""{{ __('bookingproduct::app.admin.catalog.products.available-from') }}""/>
|
||||||
|
</date>
|
||||||
|
|
||||||
|
<span class="control-error" v-if="errors.has('booking[available_from]')">@{{ errors.first('booking[available_from]') }}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="control-group" :class="[errors.has('booking[available_to]') ? 'has-error' : '']">
|
||||||
|
<label class="required">{{ __('bookingproduct::app.admin.catalog.products.available-to') }}</label>
|
||||||
|
|
||||||
|
<date>
|
||||||
|
<input type="text" v-validate="'required'" name="booking[available_to]" v-model="table_booking.available_to" class="control" data-vv-as=""{{ __('bookingproduct::app.admin.catalog.products.available-to') }}""/>
|
||||||
|
</date>
|
||||||
|
|
||||||
|
<span class="control-error" v-if="errors.has('booking[available_to]')">@{{ errors.first('booking[available_to]') }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="control-group" :class="[errors.has('booking[same_slot_all_days]') ? 'has-error' : '']">
|
||||||
|
<label class="required">{{ __('bookingproduct::app.admin.catalog.products.same-slot-all-days') }}</label>
|
||||||
|
|
||||||
|
<select v-validate="'required'" name="booking[same_slot_all_days]" v-model="table_booking.same_slot_all_days" class="control" data-vv-as=""{{ __('bookingproduct::app.admin.catalog.products.same-slot-all-days') }}"">
|
||||||
|
<option value="1">{{ __('bookingproduct::app.admin.catalog.products.yes') }}</option>
|
||||||
|
<option value="0">{{ __('bookingproduct::app.admin.catalog.products.no') }}</option>
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<span class="control-error" v-if="errors.has('booking[same_slot_all_days]')">@{{ errors.first('booking[same_slot_all_days]') }}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="section">
|
||||||
|
<div class="secton-title">
|
||||||
|
<span>{{ __('bookingproduct::app.admin.catalog.products.slots') }}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="section-content">
|
||||||
|
|
||||||
|
<slot-list
|
||||||
|
booking-type="table_slot"
|
||||||
|
:same-slot-all-days="table_booking.same_slot_all_days">
|
||||||
|
</slot-list>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
Vue.component('table-booking', {
|
||||||
|
|
||||||
|
template: '#table-booking-template',
|
||||||
|
|
||||||
|
inject: ['$validator'],
|
||||||
|
|
||||||
|
data: function() {
|
||||||
|
return {
|
||||||
|
table_booking: bookingProduct && bookingProduct.table_slot ? bookingProduct.table_slot : {
|
||||||
|
price_type: 'guest',
|
||||||
|
|
||||||
|
guest_limit: 2,
|
||||||
|
|
||||||
|
duration: 45,
|
||||||
|
|
||||||
|
break_time: 15,
|
||||||
|
|
||||||
|
prevent_scheduling_before: 0,
|
||||||
|
|
||||||
|
available_every_week: 1,
|
||||||
|
|
||||||
|
available_from: '',
|
||||||
|
|
||||||
|
available_to: '',
|
||||||
|
|
||||||
|
same_slot_all_days: 1,
|
||||||
|
|
||||||
|
slots: []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
@endpush
|
||||||
|
|
@ -0,0 +1,60 @@
|
||||||
|
@if ($product->type == 'booking')
|
||||||
|
|
||||||
|
@if ($bookingProduct = app('\Webkul\BookingProduct\Repositories\BookingProductRepository')->findOneByField('product_id', $product->product_id))
|
||||||
|
|
||||||
|
@push('css')
|
||||||
|
<link rel="stylesheet" href="{{ bagisto_asset('css/booking-product.css') }}">
|
||||||
|
@endpush
|
||||||
|
|
||||||
|
<booking-information></booking-information>
|
||||||
|
|
||||||
|
@push('scripts')
|
||||||
|
|
||||||
|
<script type="text/x-template" id="booking-information-template">
|
||||||
|
<div class="booking-information">
|
||||||
|
|
||||||
|
<div class="booking-info-row">
|
||||||
|
<span class="icon bp-location-icon"></span>
|
||||||
|
<span class="title">{{ __('bookingproduct::app.shop.products.location') }}</span>
|
||||||
|
<span class="value">New Ashok Nagar</span>
|
||||||
|
<a href="" target="_blank">View on Map</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="booking-info-row">
|
||||||
|
<span class="icon bp-phone-icon"></span>
|
||||||
|
<span class="title">
|
||||||
|
{{ __('bookingproduct::app.shop.products.contact') }} :
|
||||||
|
|
||||||
|
<a href="">{{ __('bookingproduct::app.shop.products.email') }}</a>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
@include ('bookingproduct::shop.products.view.booking.' . $bookingProduct->type, ['bookingProduct' => $bookingProduct])
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
Vue.component('booking-information', {
|
||||||
|
|
||||||
|
template: '#booking-information-template',
|
||||||
|
|
||||||
|
inject: ['$validator'],
|
||||||
|
|
||||||
|
data: function() {
|
||||||
|
return {
|
||||||
|
showDaysAvailability: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
created: function() {
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
@endpush
|
||||||
|
|
||||||
|
@endif
|
||||||
|
|
||||||
|
@endif
|
||||||
|
|
@ -0,0 +1,55 @@
|
||||||
|
<div class="booking-info-row">
|
||||||
|
<span class="icon bp-slot-icon"></span>
|
||||||
|
<span class="title">
|
||||||
|
{{ __('bookingproduct::app.shop.products.slot-duration') }} :
|
||||||
|
|
||||||
|
{{ __('bookingproduct::app.shop.products.slot-duration-in-minutes', ['minutes' => 30]) }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
@inject ('bookingSlotHelper', 'Webkul\BookingProduct\Helpers\AppointmentSlot')
|
||||||
|
|
||||||
|
<div class="booking-info-row">
|
||||||
|
<span class="icon bp-slot-icon"></span>
|
||||||
|
<span class="title">
|
||||||
|
{{ __('bookingproduct::app.shop.products.today-availability') }}
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<span class="value">
|
||||||
|
|
||||||
|
{!! $bookingSlotHelper->getTodaySlotsHtml($bookingProduct) !!}
|
||||||
|
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<div class="toggle" @click="showDaysAvailability = ! showDaysAvailability">
|
||||||
|
Show for all days
|
||||||
|
|
||||||
|
<i class="icon arrow-down-icon"></i>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="days-availability" v-show="showDaysAvailability">
|
||||||
|
|
||||||
|
<table>
|
||||||
|
<tbody>
|
||||||
|
@foreach ($bookingSlotHelper->getWeekSlotDurations($bookingProduct) as $day)
|
||||||
|
<tr>
|
||||||
|
<td>{{ $day['name'] }}</td>
|
||||||
|
|
||||||
|
<td>
|
||||||
|
@if ($day['slots'] && count($day['slots']))
|
||||||
|
@foreach ($day['slots'] as $slot)
|
||||||
|
{{ $slot['from'] . ' - ' . $slot['to'] }}</br>
|
||||||
|
@endforeach
|
||||||
|
@else
|
||||||
|
<span class="text-danger">{{ __('bookingproduct::app.shop.products.closed') }}</span>
|
||||||
|
@endif
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
@endforeach
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
@include ('bookingproduct::shop.products.view.booking.slots', ['bookingProduct' => $bookingProduct])
|
||||||
|
|
@ -0,0 +1,10 @@
|
||||||
|
<div class="booking-info-row">
|
||||||
|
<span class="icon bp-slot-icon"></span>
|
||||||
|
<span class="title">
|
||||||
|
{{ __('bookingproduct::app.shop.products.slot-duration') }} :
|
||||||
|
|
||||||
|
{{ __('bookingproduct::app.shop.products.slot-duration-in-minutes', ['minutes' => 30]) }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
@include ('bookingproduct::shop.products.view.booking.slots', ['bookingProduct' => $bookingProduct])
|
||||||
|
|
@ -0,0 +1,80 @@
|
||||||
|
@inject ('bookingSlotHelper', 'Webkul\BookingProduct\Helpers\EventSlot')
|
||||||
|
|
||||||
|
<div class="booking-info-row">
|
||||||
|
<span class="icon bp-slot-icon"></span>
|
||||||
|
<span class="title">
|
||||||
|
{{ __('bookingproduct::app.shop.products.event-on') }}
|
||||||
|
</span>
|
||||||
|
<span class="value">
|
||||||
|
{!! $bookingSlotHelper->getEventDate($bookingProduct) !!}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<event-tickets></event-tickets>
|
||||||
|
|
||||||
|
@push('scripts')
|
||||||
|
|
||||||
|
<script type="text/x-template" id="event-tickets-template">
|
||||||
|
<div class="book-slots">
|
||||||
|
<label style="font-weight: 600">{{ __('bookingproduct::app.shop.products.book-your-ticket') }}</label>
|
||||||
|
|
||||||
|
<div class="ticket-list">
|
||||||
|
<div class="ticket-item" v-for="(ticket, index) in tickets">
|
||||||
|
<div class="ticket-info">
|
||||||
|
<div class="ticket-name">
|
||||||
|
@{{ ticket.name }}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="ticket-price">
|
||||||
|
@{{ ticket.formated_price_text }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="ticket-quantity">
|
||||||
|
<div class="control-group" :class="[errors.has('booking[qty][' + index + ']') ? 'has-error' : '']">
|
||||||
|
<label class="required">{{ __('bookingproduct::app.shop.products.number-of-tickets') }}</label>
|
||||||
|
<input type="text" v-validate="'required'" :name="'booking[qty][' + index + ']'" class="control" data-vv-as=""{{ __('bookingproduct::app.shop.products.number-of-tickets') }}"" style="width: 100%"/>
|
||||||
|
<span class="control-error" v-if="errors.has('booking[qty][' + index + ']')">@{{ errors.first('booking[qty][' + index + ']') }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p>@{{ ticket.description }}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="ticket-total">
|
||||||
|
<!--<div class="total-tickets">
|
||||||
|
{{ __('bookingproduct::app.shop.products.total-tickets') }} - 1
|
||||||
|
</div>-->
|
||||||
|
|
||||||
|
<div class="ticket-base-price">
|
||||||
|
{{ __('bookingproduct::app.shop.products.base-price') }} - $100
|
||||||
|
|
||||||
|
<p>{{ __('bookingproduct::app.shop.products.base-price-info') }}</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!--<div class="ticket-total-price">
|
||||||
|
{{ __('bookingproduct::app.shop.products.total-price') }} - $100
|
||||||
|
</div>-->
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
|
||||||
|
Vue.component('event-tickets', {
|
||||||
|
|
||||||
|
template: '#event-tickets-template',
|
||||||
|
|
||||||
|
inject: ['$validator'],
|
||||||
|
|
||||||
|
data: function() {
|
||||||
|
return {
|
||||||
|
tickets: @json($bookingSlotHelper->getTickets($bookingProduct)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
@endpush
|
||||||
|
|
@ -0,0 +1,153 @@
|
||||||
|
<rental-slots></rental-slots>
|
||||||
|
|
||||||
|
@push('scripts')
|
||||||
|
<script type="text/x-template" id="rental-slots-template">
|
||||||
|
<div class="book-slots">
|
||||||
|
<h3>{{ __('bookingproduct::app.shop.products.rent-an-item') }}</h3>
|
||||||
|
|
||||||
|
<div v-if="renting_type == 'daily_hourly'">
|
||||||
|
<div class="control-group">
|
||||||
|
<label>{{ __('bookingproduct::app.shop.products.choose-rent-option') }}</label>
|
||||||
|
|
||||||
|
<span class="radio">
|
||||||
|
<input type="radio" id="daily-renting-type" name="booking[renting_type]" value="daily" v-model="sub_renting_type">
|
||||||
|
<label class="radio-view" for="daily-renting-type"></label>
|
||||||
|
{{ __('bookingproduct::app.shop.products.daily-basis') }}
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<span class="radio">
|
||||||
|
<input type="radio" id="hourly-renting-type" name="booking[renting_type]" value="hourly" v-model="sub_renting_type">
|
||||||
|
<label class="radio-view" for="hourly-renting-type"></label>
|
||||||
|
{{ __('bookingproduct::app.shop.products.hourly-basis') }}
|
||||||
|
</span>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-if="renting_type != 'daily' && sub_renting_type == 'hourly'">
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<label>{{ __('bookingproduct::app.shop.products.select-slot') }}</label>
|
||||||
|
|
||||||
|
<div class="control-group-container">
|
||||||
|
<div class="control-group date" :class="[errors.has('booking[date]') ? 'has-error' : '']">
|
||||||
|
<date @onChange="dateSelected($event)">
|
||||||
|
<input type="text" v-validate="'required'" name="booking[date]" class="control" data-vv-as=""{{ __('bookingproduct::app.shop.products.date') }}"" placeholder="{{ __('bookingproduct::app.shop.products.select-date') }}" data-min-date="today"/>
|
||||||
|
</date>
|
||||||
|
|
||||||
|
<span class="control-error" v-if="errors.has('booking[date]')">@{{ errors.first('booking[date]') }}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="control-group slots" :class="[errors.has('booking[slot]') ? 'has-error' : '']">
|
||||||
|
<select v-validate="'required'" name="booking[slot]" v-model="selected_slot" class="control" data-vv-as=""{{ __('bookingproduct::app.shop.products.slot') }}"">
|
||||||
|
<option value="">{{ __('bookingproduct::app.shop.products.select-time-slot') }}</option>
|
||||||
|
<option v-for="(slot, index) in slots" :value="index">@{{ slot.time }}</option>
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<span class="control-error" v-if="errors.has('booking[slot]')">@{{ errors.first('booking[slot]') }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-if="slots[selected_slot] && slots[selected_slot]['slots'].length">
|
||||||
|
<label>{{ __('bookingproduct::app.shop.products.select-rent-time') }}</label>
|
||||||
|
|
||||||
|
<div class="control-group-container">
|
||||||
|
<div class="control-group slots" :class="[errors.has('booking[slot][from]') ? 'has-error' : '']">
|
||||||
|
<select v-validate="'required'" name="booking[slot][from]" v-model="slot_from" class="control" data-vv-as=""{{ __('bookingproduct::app.shop.products.slot') }}"">
|
||||||
|
<option value="">{{ __('bookingproduct::app.shop.products.select-time-slot') }}</option>
|
||||||
|
|
||||||
|
<option v-for="slot in slots[selected_slot]['slots']" :value="slot.from_timestamp">
|
||||||
|
@{{ slot.from }}
|
||||||
|
</option>
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<span class="control-error" v-if="errors.has('booking[slot][from]')">@{{ errors.first('booking[slot][from]') }}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="control-group slots" :class="[errors.has('booking[slot][to]') ? 'has-error' : '']">
|
||||||
|
<select v-validate="'required'" name="booking[slot][to]" class="control" data-vv-as=""{{ __('bookingproduct::app.shop.products.slot') }}"">
|
||||||
|
<option value="">{{ __('bookingproduct::app.shop.products.select-time-slot') }}</option>
|
||||||
|
|
||||||
|
<option v-for="slot in slots[selected_slot]['slots']" :value="slot.to_timestamp" v-if="slot_from < slot.to_timestamp">
|
||||||
|
@{{ slot.to }}
|
||||||
|
</option>
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<span class="control-error" v-if="errors.has('booking[slot][to]')">@{{ errors.first('booking[slot][to]') }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-else>
|
||||||
|
<label>{{ __('bookingproduct::app.shop.products.select-date') }}</label>
|
||||||
|
|
||||||
|
<div class="control-group-container">
|
||||||
|
<div class="control-group date" :class="[errors.has('booking[date_from]') ? 'has-error' : '']">
|
||||||
|
<date @onChange="dateSelected($event)">
|
||||||
|
<input type="text" v-validate="'required'" name="booking[date_from]" v-model="date_from" class="control" data-vv-as=""{{ __('bookingproduct::app.shop.products.from') }}"" placeholder="{{ __('bookingproduct::app.shop.products.from') }}" data-min-date="today"/>
|
||||||
|
</date>
|
||||||
|
|
||||||
|
<span class="control-error" v-if="errors.has('booking[date_from]')">@{{ errors.first('booking[date_from]') }}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="control-group date" :class="[errors.has('booking[date_to]') ? 'has-error' : '']">
|
||||||
|
<date @onChange="dateSelected($event)">
|
||||||
|
<input type="text" v-validate="'required'" name="booking[date_to]" v-model="date_to" class="control" data-vv-as=""{{ __('bookingproduct::app.shop.products.to') }}"" placeholder="{{ __('bookingproduct::app.shop.products.to') }}"/>
|
||||||
|
</date>
|
||||||
|
|
||||||
|
<span class="control-error" v-if="errors.has('booking[date_to]')">@{{ errors.first('booking[date_to]') }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
|
||||||
|
Vue.component('rental-slots', {
|
||||||
|
|
||||||
|
template: '#rental-slots-template',
|
||||||
|
|
||||||
|
inject: ['$validator'],
|
||||||
|
|
||||||
|
data: function() {
|
||||||
|
return {
|
||||||
|
renting_type: "{{ $bookingProduct->rental_slot->renting_type }}",
|
||||||
|
|
||||||
|
sub_renting_type: 'hourly',
|
||||||
|
|
||||||
|
slots: [],
|
||||||
|
|
||||||
|
selected_slot: '',
|
||||||
|
|
||||||
|
slot_from: 0,
|
||||||
|
|
||||||
|
date_from: '',
|
||||||
|
|
||||||
|
date_to: ''
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
dateSelected: function(date) {
|
||||||
|
var this_this = this;
|
||||||
|
|
||||||
|
this.$http.get("{{ route('booking_product.slots.index', $bookingProduct->id) }}", {params: {date: date}})
|
||||||
|
.then (function(response) {
|
||||||
|
this_this.selected_slot = '';
|
||||||
|
|
||||||
|
this_this.slot_from = 0;
|
||||||
|
|
||||||
|
this_this.slots = response.data.data;
|
||||||
|
})
|
||||||
|
.catch (function (error) {})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
</script>
|
||||||
|
@endpush
|
||||||
|
|
@ -0,0 +1,58 @@
|
||||||
|
<book-slots></book-slots>
|
||||||
|
|
||||||
|
@push('scripts')
|
||||||
|
<script type="text/x-template" id="book-slots-template">
|
||||||
|
|
||||||
|
<div class="book-slots">
|
||||||
|
<label>{{ $title ?? __('bookingproduct::app.shop.products.book-an-appointment') }} :</label>
|
||||||
|
|
||||||
|
<div class="control-group-container">
|
||||||
|
<div class="control-group date" :class="[errors.has('booking[date]') ? 'has-error' : '']">
|
||||||
|
<date @onChange="dateSelected($event)">
|
||||||
|
<input type="text" v-validate="'required'" name="booking[date]" class="control" data-vv-as=""{{ __('bookingproduct::app.shop.products.date') }}""/>
|
||||||
|
</date>
|
||||||
|
|
||||||
|
<span class="control-error" v-if="errors.has('booking[date]')">@{{ errors.first('booking[date]') }}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="control-group slots" :class="[errors.has('booking[slot]') ? 'has-error' : '']">
|
||||||
|
<select v-validate="'required'" name="booking[slot]" class="control" data-vv-as=""{{ __('bookingproduct::app.shop.products.slot') }}"">
|
||||||
|
<option v-for="slot in slots" :value="slot.timestamp">@{{ slot.from + ' - ' + slot.to }}</option>
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<span class="control-error" v-if="errors.has('booking[slot]')">@{{ errors.first('booking[slot]') }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
|
||||||
|
Vue.component('book-slots', {
|
||||||
|
|
||||||
|
template: '#book-slots-template',
|
||||||
|
|
||||||
|
inject: ['$validator'],
|
||||||
|
|
||||||
|
data: function() {
|
||||||
|
return {
|
||||||
|
slots: []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
dateSelected: function(date) {
|
||||||
|
var this_this = this;
|
||||||
|
|
||||||
|
this.$http.get("{{ route('booking_product.slots.index', $bookingProduct->id) }}", {params: {date: date}})
|
||||||
|
.then (function(response) {
|
||||||
|
this_this.slots = response.data.data;
|
||||||
|
})
|
||||||
|
.catch (function (error) {})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
</script>
|
||||||
|
@endpush
|
||||||
|
|
@ -0,0 +1,69 @@
|
||||||
|
<div class="booking-info-row">
|
||||||
|
<span class="icon bp-slot-icon"></span>
|
||||||
|
<span class="title">
|
||||||
|
{{ __('bookingproduct::app.shop.products.slot-duration') }} :
|
||||||
|
|
||||||
|
{{ __('bookingproduct::app.shop.products.slot-duration-in-minutes', ['minutes' => 30]) }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
@inject ('bookingSlotHelper', 'Webkul\BookingProduct\Helpers\TableSlot')
|
||||||
|
|
||||||
|
<div class="booking-info-row">
|
||||||
|
<span class="icon bp-slot-icon"></span>
|
||||||
|
<span class="title">
|
||||||
|
{{ __('bookingproduct::app.shop.products.today-availability') }}
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<span class="value">
|
||||||
|
|
||||||
|
{!! $bookingSlotHelper->getTodaySlotsHtml($bookingProduct) !!}
|
||||||
|
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<div class="toggle" @click="showDaysAvailability = ! showDaysAvailability">
|
||||||
|
Show for all days
|
||||||
|
|
||||||
|
<i class="icon arrow-down-icon"></i>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="days-availability" v-show="showDaysAvailability">
|
||||||
|
|
||||||
|
<table>
|
||||||
|
<tbody>
|
||||||
|
@foreach ($bookingSlotHelper->getWeekSlotDurations($bookingProduct) as $day)
|
||||||
|
<tr>
|
||||||
|
<td>{{ $day['name'] }}</td>
|
||||||
|
|
||||||
|
<td>
|
||||||
|
@if ($day['slots'] && count($day['slots']))
|
||||||
|
@foreach ($day['slots'] as $slot)
|
||||||
|
{{ $slot['from'] . ' - ' . $slot['to'] }}</br>
|
||||||
|
@endforeach
|
||||||
|
@else
|
||||||
|
<span class="text-danger">{{ __('bookingproduct::app.shop.products.closed') }}</span>
|
||||||
|
@endif
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
@endforeach
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
@include ('bookingproduct::shop.products.view.booking.slots', [
|
||||||
|
'bookingProduct' => $bookingProduct,
|
||||||
|
'title' => __('bookingproduct::app.shop.products.book-a-table')
|
||||||
|
])
|
||||||
|
|
||||||
|
<div class="control-group" :class="[errors.has('booking[qty]') ? 'has-error' : '']">
|
||||||
|
<label>{{ __('bookingproduct::app.shop.products.number-of-tables') }}</label>
|
||||||
|
<input type="text" v-validate="'required'" name="booking[qty]" class="control" data-vv-as=""{{ __('bookingproduct::app.shop.products.number-of-tables') }}"" style="width: 100%"/>
|
||||||
|
<span class="control-error" v-if="errors.has('booking[qty]')">@{{ errors.first('booking[qty]') }}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="control-group">
|
||||||
|
<label>{{ __('bookingproduct::app.shop.products.special-notes') }}</label>
|
||||||
|
<textarea name="booking[note]" class="control" style="width: 100%"/>
|
||||||
|
</div>
|
||||||
|
|
@ -0,0 +1,169 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Webkul\BookingProduct\Type;
|
||||||
|
|
||||||
|
use Webkul\Attribute\Repositories\AttributeRepository;
|
||||||
|
use Webkul\Product\Repositories\ProductRepository;
|
||||||
|
use Webkul\Product\Repositories\ProductAttributeValueRepository;
|
||||||
|
use Webkul\Product\Repositories\ProductInventoryRepository;
|
||||||
|
use Webkul\Product\Repositories\ProductImageRepository;
|
||||||
|
use Webkul\Product\Helpers\ProductImage;
|
||||||
|
use Webkul\BookingProduct\Helpers\Booking as BookingHelper;
|
||||||
|
use Webkul\Product\Type\AbstractType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class Booking.
|
||||||
|
*
|
||||||
|
* @author Jitendra Singh <jitendra@webkul.com>
|
||||||
|
* @copyright 2018 Webkul Software Pvt Ltd (http://www.webkul.com)
|
||||||
|
*/
|
||||||
|
class Booking extends AbstractType
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Booking helper instance
|
||||||
|
*
|
||||||
|
* @var Booking
|
||||||
|
*/
|
||||||
|
protected $bookingHelper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Skip attribute for virtual product type
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
protected $skipAttributes = ['width', 'height', 'depth', 'weight'];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show quantity box
|
||||||
|
*
|
||||||
|
* @var boolean
|
||||||
|
*/
|
||||||
|
protected $showQuantityBox = true;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
protected $additionalViews = [
|
||||||
|
'admin::catalog.products.accordians.images',
|
||||||
|
'admin::catalog.products.accordians.categories',
|
||||||
|
'bookingproduct::admin.catalog.products.accordians.booking',
|
||||||
|
'admin::catalog.products.accordians.product-links'
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new product type instance.
|
||||||
|
*
|
||||||
|
* @param Webkul\Attribute\Repositories\AttributeRepository $attributeRepository
|
||||||
|
* @param Webkul\Product\Repositories\ProductRepository $productRepository
|
||||||
|
* @param Webkul\Product\Repositories\ProductAttributeValueRepository $attributeValueRepository
|
||||||
|
* @param Webkul\Product\Repositories\ProductInventoryRepository $productInventoryRepository
|
||||||
|
* @param Webkul\Product\Repositories\ProductImageRepository $productImageRepository
|
||||||
|
* @param Webkul\BookingProduct\Helpers\BookingHelper $bookingHelper
|
||||||
|
* @param Webkul\Product\Helpers\ProductImage $productImageHelper
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function __construct(
|
||||||
|
AttributeRepository $attributeRepository,
|
||||||
|
ProductRepository $productRepository,
|
||||||
|
ProductAttributeValueRepository $attributeValueRepository,
|
||||||
|
ProductInventoryRepository $productInventoryRepository,
|
||||||
|
ProductImageRepository $productImageRepository,
|
||||||
|
BookingHelper $bookingHelper,
|
||||||
|
ProductImage $productImageHelper
|
||||||
|
)
|
||||||
|
{
|
||||||
|
parent::__construct(
|
||||||
|
$attributeRepository,
|
||||||
|
$productRepository,
|
||||||
|
$attributeValueRepository,
|
||||||
|
$productInventoryRepository,
|
||||||
|
$productImageRepository,
|
||||||
|
$productImageHelper
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->bookingHelper = $bookingHelper;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return true if this product type is saleable
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function isSaleable()
|
||||||
|
{
|
||||||
|
if (! $this->product->status)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return true if this product can have inventory
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function isStockable()
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return true if item can be moved to cart from wishlist
|
||||||
|
*
|
||||||
|
* @param CartItem $item
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public function canBeMovedFromWishlistToCart($item)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add product. Returns error message if can't prepare product.
|
||||||
|
*
|
||||||
|
* @param array $data
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function prepareForCart($data)
|
||||||
|
{
|
||||||
|
$products = parent::prepareForCart($data);
|
||||||
|
|
||||||
|
dd($products);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param array $options1
|
||||||
|
* @param array $options2
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public function compareOptions($options1, $options2)
|
||||||
|
{
|
||||||
|
if ($this->product->id != $options2['product_id'])
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return $options1['booking'] == $options2['booking'];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns additional information for items
|
||||||
|
*
|
||||||
|
* @param array $data
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getAdditionalOptions($data)
|
||||||
|
{
|
||||||
|
$data['attributes'] = [
|
||||||
|
[
|
||||||
|
'attribute_name' => 'From',
|
||||||
|
'option_id' => 0,
|
||||||
|
'option_label' => "",
|
||||||
|
], [
|
||||||
|
'attribute_name' => 'To',
|
||||||
|
'option_id' => 0,
|
||||||
|
'option_label' => "",
|
||||||
|
]];
|
||||||
|
|
||||||
|
return $data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,31 @@
|
||||||
|
const mix = require("laravel-mix");
|
||||||
|
|
||||||
|
if (mix == 'undefined') {
|
||||||
|
const { mix } = require("laravel-mix");
|
||||||
|
}
|
||||||
|
|
||||||
|
require("laravel-mix-merge-manifest");
|
||||||
|
|
||||||
|
if (mix.inProduction()) {
|
||||||
|
var publicPath = 'publishable/assets';
|
||||||
|
} else {
|
||||||
|
var publicPath = "../../../public/themes/default/assets";
|
||||||
|
}
|
||||||
|
|
||||||
|
mix.setPublicPath(publicPath).mergeManifest();
|
||||||
|
mix.disableNotifications();
|
||||||
|
|
||||||
|
mix.copyDirectory(__dirname + "/src/Resources/assets/images", publicPath + "/images")
|
||||||
|
.sass(__dirname + "/src/Resources/assets/sass/app.scss", "css/booking-product.css")
|
||||||
|
.options({
|
||||||
|
processCssUrls: false
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
if (!mix.inProduction()) {
|
||||||
|
mix.sourceMaps();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mix.inProduction()) {
|
||||||
|
mix.version();
|
||||||
|
}
|
||||||