diff --git a/app/Console/Commands/Install.php b/app/Console/Commands/Install.php index 9fc98115..1d0b643d 100644 --- a/app/Console/Commands/Install.php +++ b/app/Console/Commands/Install.php @@ -124,6 +124,16 @@ class Install extends Command /_/ \_\__|\__\___|_| |_|\__,_|_/___\___| "); - $this->comment('Success! You can now run Attendize'); + + +// $a = " _ +// | | +// /\ /\ ___ _ __ __| | __ _ _ __ +// / \/ \ / _ \ '_ \ / _` |/ _' | '_ \ +// / /\ /\ \ __/ | '-| (_| | (_| | | | | +// /_/ \/ \_\___|_| \__,_|\__,_|_| |_| +// +// "; + $this->comment('Success! You can now run Attendize'); } } diff --git a/app/Helpers/helpers.php b/app/Helpers/helpers.php index e7beef58..726a906d 100644 --- a/app/Helpers/helpers.php +++ b/app/Helpers/helpers.php @@ -28,6 +28,17 @@ if(!function_exists('main_categories')){ } } +if(!function_exists('venues_list')){ + function venues_list(){ + return \App\Models\Venue::where('active',1)->pluck('venue_name','id'); + } +} +if(!function_exists('sections_list')){ + function sections_list($venue_id){ + return \App\Models\Section::where('venue_id',$venue_id)->pluck('section_no','id'); + } +} + if(!function_exists('category_menu')){ /** * make menu from categories diff --git a/app/Http/Controllers/API/CheckoutController.php b/app/Http/Controllers/API/CheckoutController.php new file mode 100644 index 00000000..49593c37 --- /dev/null +++ b/app/Http/Controllers/API/CheckoutController.php @@ -0,0 +1,26 @@ +addMinutes(config('attendize.checkout_timeout_after')); + $event = Event::findOrFail($event_id); + + $ticket_ids = $request->get('tickets'); + } +} \ No newline at end of file diff --git a/app/Http/Controllers/API/PublicController.php b/app/Http/Controllers/API/PublicController.php index e087f7f8..ead31ad5 100644 --- a/app/Http/Controllers/API/PublicController.php +++ b/app/Http/Controllers/API/PublicController.php @@ -16,8 +16,8 @@ class PublicController extends Controller $categories->children($parent_id); else $categories->main(); - - return $categories->get(); + return response()->json(['categories' => $categories->get()]); +// return $categories->get(); } public function getEvents($cat_id = null, Request $request){ diff --git a/app/Http/Controllers/Admin/SectionCrudController.php b/app/Http/Controllers/Admin/SectionCrudController.php new file mode 100644 index 00000000..ba8f2279 --- /dev/null +++ b/app/Http/Controllers/Admin/SectionCrudController.php @@ -0,0 +1,89 @@ +crud->setModel('App\Models\Section'); + $this->crud->setRoute(config('backpack.base.route_prefix') . '/section'); + $this->crud->setEntityNameStrings('section', 'sections'); + + /* + |-------------------------------------------------------------------------- + | CrudPanel Configuration + |-------------------------------------------------------------------------- + */ + + // TODO: remove setFromDb() and manually define Fields and Columns +// $this->crud->setFromDb(); + $this->crud->addColumns([ + ['name'=>'section_no','type'=>'text','label'=>'Section No'], + ['name'=>'description','type'=>'text','label'=>'Description'], + ]); + + $this->crud->addFields([ + ['name'=>'section_no','type'=>'text','label'=>'Section No'], + ['name'=>'description','type'=>'text','label'=>'Description'], + ['name' => 'venue_id', 'type'=>'select','entity'=>'venue','attribute'=>'venue_name'], + [ // image + 'label' => "Section Image", + 'name' => "section_image", + 'type' => 'image', + 'upload' => true, +// 'crop' => true, // set to true to allow cropping, false to disable +// 'aspect_ratio' => 1, // ommit or set to 0 to allow any aspect ratio + // 'disk' => 's3_bucket', // in case you need to show images from a different disk + 'prefix' => 'user_content/' // in case your db value is only the file name (no path), you can use this to prepend your path to the image src (in HTML), before it's shown to the user; + ], + ['name'=>'seats','type'=>'table','label'=>'Seats', + 'columns' => [ + 'row' => 'Row', + 'start_no' => 'Starts at', + 'end_no' => 'Ends at' + ] + ] + + ]); + + // add asterisk for fields that are required in SectionRequest + $this->crud->setRequiredFields(StoreRequest::class, 'create'); + $this->crud->setRequiredFields(UpdateRequest::class, 'edit'); + } + + public function store(StoreRequest $request) + { + // your additional operations before save here + $redirect_location = parent::storeCrud($request); + // your additional operations after save here + // use $this->data['entry'] or $this->crud->entry + return $redirect_location; + } + + public function update(UpdateRequest $request) + { + // your additional operations before save here + $redirect_location = parent::updateCrud($request); + // your additional operations after save here + // use $this->data['entry'] or $this->crud->entry + return $redirect_location; + } +} diff --git a/app/Http/Controllers/Admin/VenueCrudController.php b/app/Http/Controllers/Admin/VenueCrudController.php new file mode 100644 index 00000000..4c312381 --- /dev/null +++ b/app/Http/Controllers/Admin/VenueCrudController.php @@ -0,0 +1,86 @@ +crud->setModel('App\Models\Venue'); + $this->crud->setRoute(config('backpack.base.route_prefix') . '/venue'); + $this->crud->setEntityNameStrings('venue', 'venues'); + + /* + |-------------------------------------------------------------------------- + | CrudPanel Configuration + |-------------------------------------------------------------------------- + */ + + // TODO: remove setFromDb() and manually define Fields and Columns + $this->crud->addColumns([ + ['name'=>'venue_name','type'=>'text','label'=>'Venue Name'], + ['name'=>'active','type'=>'boolean','label'=>'Active'] + ]); + + $this->crud->addFields([ + ['name'=>'venue_name','type'=>'text','label'=>'Venue Name'], + [ // Address + 'name' => 'address', + 'label' => 'Address', + 'type' => 'address_google', + // optional + 'store_as_json' => true + ], + [ // image + 'label' => "Seats Image", + 'name' => "seats_image", + 'type' => 'image', + 'upload' => true, +// 'crop' => true, // set to true to allow cropping, false to disable +// 'aspect_ratio' => 1, // ommit or set to 0 to allow any aspect ratio + // 'disk' => 's3_bucket', // in case you need to show images from a different disk + 'prefix' => 'user_content/' // in case your db value is only the file name (no path), you can use this to prepend your path to the image src (in HTML), before it's shown to the user; + ], + ['name'=>'active','type'=>'checkbox','label'=>'Active'] + ]); + + // add asterisk for fields that are required in VenueRequest + $this->crud->setRequiredFields(StoreRequest::class, 'create'); + $this->crud->setRequiredFields(UpdateRequest::class, 'edit'); + } + + public function store(StoreRequest $request) + { + // your additional operations before save here + $redirect_location = parent::storeCrud($request); + // your additional operations after save here + // use $this->data['entry'] or $this->crud->entry + return $redirect_location; + } + + public function update(UpdateRequest $request) + { + // your additional operations before save here + $redirect_location = parent::updateCrud($request); + // your additional operations after save here + // use $this->data['entry'] or $this->crud->entry + return $redirect_location; + } +} diff --git a/app/Http/Controllers/EventCheckoutController.php b/app/Http/Controllers/EventCheckoutController.php index 2ca2b3b6..5e719ad4 100644 --- a/app/Http/Controllers/EventCheckoutController.php +++ b/app/Http/Controllers/EventCheckoutController.php @@ -15,6 +15,7 @@ use App\Models\OrderItem; use App\Models\QuestionAnswer; use App\Models\ReservedTickets; use App\Models\Ticket; +use App\Models\Venue; use App\Payment\CardPayment; use App\Services\Order as OrderService; use Carbon\Carbon; @@ -54,6 +55,34 @@ class EventCheckoutController extends Controller $this->gateway = $gateway; } + public function postValidateDate(Request $request, $event_id){ + + $this->validate($request,['ticket_date'=>'required|date']); +// $validator = Validator::make($request->all(),['ticket_date'=>'required|date']); +// if($validator->fails()){ +// return response()->json([ +// 'status' => 'error', +// 'message' => 'Please choose date', +// ]); +// } + $event = Event::with('venue')->findOrFail($event_id); + $tickets = Ticket::with('section') + ->where('event_id',$event_id) + ->where('ticket_date',$request->get('ticket_date')) + ->where('is_hidden', false) +// ->where('is_paused', false) +// ->whereDate('start_sale_date','=<',Carbon::now()) + ->orderBy('sort_order','asc') + ->get(); + if($tickets->count()>0){ + return view('Bilettm.ViewEvent.SeatsPage',compact('event','tickets')); + } + else{ + //todo flash message + session()->flash('error','There is no tickets available'); + return redirect()->back(); + } + } /** * Validate a ticket request. If successful reserve the tickets and redirect to checkout * @@ -63,20 +92,18 @@ class EventCheckoutController extends Controller */ public function postValidateTickets(Request $request, $event_id) { - /* - * Order expires after X min - */ - $order_expires_time = Carbon::now()->addMinutes(config('attendize.checkout_timeout_after')); - - $event = Event::findOrFail($event_id); - if (!$request->has('tickets')) { return response()->json([ 'status' => 'error', 'message' => 'No tickets selected', ]); } + /* + * Order expires after X min + */ + $order_expires_time = Carbon::now()->addMinutes(config('attendize.checkout_timeout_after')); + $event = Event::findOrFail($event_id); $ticket_ids = $request->get('tickets'); /* @@ -315,28 +342,6 @@ class EventCheckoutController extends Controller $order->rules = $order->rules + $validation_rules; $order->messages = $order->messages + $validation_messages; -// if ($request->has('is_business') && $request->get('is_business')) { -// // Dynamic validation on the new business fields, only gets validated if business selected -// $businessRules = [ -// 'business_name' => 'required', -// 'business_tax_number' => 'required', -// 'business_address_line1' => 'required', -// 'business_address_city' => 'required', -// 'business_address_code' => 'required', -// ]; -// -// $businessMessages = [ -// 'business_name.required' => 'Please enter a valid business name', -// 'business_tax_number.required' => 'Please enter a valid business tax number', -// 'business_address_line1.required' => 'Please enter a valid street address', -// 'business_address_city.required' => 'Please enter a valid city', -// 'business_address_code.required' => 'Please enter a valid code', -// ]; -// -// $order->rules = $order->rules + $businessRules; -// $order->messages = $order->messages + $businessMessages; -// } - if (!$order->validate($request->all())) { return response()->json([ 'status' => 'error', @@ -360,23 +365,6 @@ class EventCheckoutController extends Controller try { //more transaction data being put in here. $transaction_data = []; -// if (config('attendize.enable_dummy_payment_gateway') == TRUE) { -// $formData = config('attendize.fake_card_data'); -// $transaction_data = [ -// 'card' => $formData -// ]; -// -// $gateway = Omnipay::create('Dummy'); -// $gateway->initialize(); -// -// } else { -//// $gateway = Omnipay::create($ticket_order['payment_gateway']->name); -//// $gateway->initialize($ticket_order['account_payment_gateway']->config + [ -//// 'testMode' => config('attendize.enable_test_payments'), -//// ]); -// $gateway = Omnipay::create('Dummy'); -// $gateway->initialize(); -// } $orderService = new OrderService($ticket_order['order_total'], $ticket_order['total_booking_fee'], $event); $orderService->calculateFinalCosts(); $secondsToExpire = Carbon::now()->diffInSeconds($order_session['expires']); @@ -397,59 +385,9 @@ class EventCheckoutController extends Controller ]; - //TODO: class with an interface that builds the transaction data. -// switch ($ticket_order['payment_gateway']->id) { -// case config('attendize.payment_gateway_dummy'): -// $token = uniqid(); -// $transaction_data += [ -// 'token' => $token, -// 'receipt_email' => $request->get('order_email'), -// 'card' => $formData -// ]; -// break; -// case config('attendize.payment_gateway_paypal'): -// -// $transaction_data += [ -// 'cancelUrl' => route('showEventCheckoutPaymentReturn', [ -// 'event_id' => $event_id, -// 'is_payment_cancelled' => 1 -// ]), -// 'returnUrl' => route('showEventCheckoutPaymentReturn', [ -// 'event_id' => $event_id, -// 'is_payment_successful' => 1 -// ]), -// 'brandName' => isset($ticket_order['account_payment_gateway']->config['brandingName']) -// ? $ticket_order['account_payment_gateway']->config['brandingName'] -// : $event->organiser->name -// ]; -// break; -// case config('attendize.payment_gateway_stripe'): -// $token = $request->get('stripeToken'); -// $transaction_data += [ -// 'token' => $token, -// 'receipt_email' => $request->get('order_email'), -// ]; -// break; -// default: -// Log::error('No payment gateway configured.'); -// return response()->json([ -// 'status' => 'error', -// 'message' => 'No payment gateway configured.' -// ]); -// break; -// } - $response = $this->gateway->registerPayment($transaction_data); //todo start resolving payment here ///////////////////////////////////////////////////// -// if ($response->isSuccessful()) { -// -// session()->push('ticket_order_' . $event_id . '.transaction_id', -// $response->getTransactionReference()); -// -// return $this->completeOrder($event_id); -// -// } elseif ($response->isRedirect()) { if($response->isSuccessfull()){ /* * As we're going off-site for payment we need to store some data in a session so it's available @@ -494,7 +432,6 @@ class EventCheckoutController extends Controller } - /** * Attempt to complete a user's payment when they return from * an off-site gateway diff --git a/app/Http/Controllers/EventController.php b/app/Http/Controllers/EventController.php index 67cfecbe..714f2345 100644 --- a/app/Http/Controllers/EventController.php +++ b/app/Http/Controllers/EventController.php @@ -23,6 +23,7 @@ class EventController extends MyBaseController */ public function showCreateEvent(Request $request) { + $data = [ 'modal_id' => $request->get('modal_id'), 'organisers' => Organiser::scope()->pluck('name', 'id'), @@ -60,30 +61,30 @@ class EventController extends MyBaseController */ $is_auto_address = (trim($request->get('place_id')) !== ''); - - if ($is_auto_address) { /* Google auto filled */ - $event->venue_name = $request->get('name'); - $event->venue_name_full = $request->get('venue_name_full'); - $event->location_lat = $request->get('lat'); - $event->location_long = $request->get('lng'); - $event->location_address = $request->get('formatted_address'); - $event->location_country = $request->get('country'); - $event->location_country_code = $request->get('country_short'); - $event->location_state = $request->get('administrative_area_level_1'); - $event->location_address_line_1 = $request->get('route'); - $event->location_address_line_2 = $request->get('locality'); - $event->location_post_code = $request->get('postal_code'); - $event->location_street_number = $request->get('street_number'); - $event->location_google_place_id = $request->get('place_id'); - $event->location_is_manual = 0; - } else { /* Manually entered */ - $event->venue_name = $request->get('location_venue_name'); - $event->location_address_line_1 = $request->get('location_address_line_1'); - $event->location_address_line_2 = $request->get('location_address_line_2'); - $event->location_state = $request->get('location_state'); - $event->location_post_code = $request->get('location_post_code'); - $event->location_is_manual = 1; - } + $event->venue_id = $request->get('venue_id'); +// if ($is_auto_address) { /* Google auto filled */ +// $event->venue_name = $request->get('name'); +// $event->venue_name_full = $request->get('venue_name_full'); +// $event->location_lat = $request->get('lat'); +// $event->location_long = $request->get('lng'); +// $event->location_address = $request->get('formatted_address'); +// $event->location_country = $request->get('country'); +// $event->location_country_code = $request->get('country_short'); +// $event->location_state = $request->get('administrative_area_level_1'); +// $event->location_address_line_1 = $request->get('route'); +// $event->location_address_line_2 = $request->get('locality'); +// $event->location_post_code = $request->get('postal_code'); +// $event->location_street_number = $request->get('street_number'); +// $event->location_google_place_id = $request->get('place_id'); +// $event->location_is_manual = 0; +// } else { /* Manually entered */ +// $event->venue_name = $request->get('location_venue_name'); +// $event->location_address_line_1 = $request->get('location_address_line_1'); +// $event->location_address_line_2 = $request->get('location_address_line_2'); +// $event->location_state = $request->get('location_state'); +// $event->location_post_code = $request->get('location_post_code'); +// $event->location_is_manual = 1; +// } $event->end_date = $request->get('end_date'); diff --git a/app/Http/Controllers/EventTicketsController.php b/app/Http/Controllers/EventTicketsController.php index 715e471b..d25b8204 100644 --- a/app/Http/Controllers/EventTicketsController.php +++ b/app/Http/Controllers/EventTicketsController.php @@ -37,7 +37,7 @@ class EventTicketsController extends MyBaseController } // Find event or return 404 error. - $event = Event::scope()->findOrFail($event_id); + $event = Event::with('venue')->scope()->findOrFail($event_id); // Get tickets for event. $tickets = empty($q) === false @@ -107,6 +107,7 @@ class EventTicketsController extends MyBaseController $ticket->description = strip_tags($request->get('description')); $ticket->is_hidden = $request->get('is_hidden') ? 1 : 0; $ticket->account_id = auth()->user()->account_id; + $ticket->section_id = $request->get('section_id'); $ticket->save(); // Attach the access codes to the ticket if it's hidden and the code ids have come from the front @@ -243,7 +244,7 @@ class EventTicketsController extends MyBaseController $ticket->min_per_person = $request->get('min_per_person'); $ticket->max_per_person = $request->get('max_per_person'); $ticket->is_hidden = $request->get('is_hidden') ? 1 : 0; - + $ticket->section_id = $request->get('section_id'); $ticket->save(); // Attach the access codes to the ticket if it's hidden and the code ids have come from the front diff --git a/app/Http/Controllers/EventViewController.php b/app/Http/Controllers/EventViewController.php index 8de47233..6f525c32 100644 --- a/app/Http/Controllers/EventViewController.php +++ b/app/Http/Controllers/EventViewController.php @@ -27,15 +27,18 @@ class EventViewController extends Controller */ public function showEventHome(Request $request, $event_id, $slug = '', $preview = false) { - $event = Event::findOrFail($event_id); + $event = Event::with('venue')->findOrFail($event_id); if (!Utils::userOwns($event) && !$event->is_live) { return view('Public.ViewEvent.EventNotLivePage'); } - $tickets = $event->tickets()->where('is_hidden', false) + $tickets = $event->tickets()->select('id','ticket_date') + ->where('is_hidden', false) ->whereDate('ticket_date','>=',Carbon::now(config('app.timezone'))) - ->orderBy('sort_order', 'asc')->get(); + ->orderBy('ticket_date', 'asc') + ->groupBy('ticket_date') + ->distinct()->get(); $ticket_dates = array(); @@ -43,7 +46,7 @@ class EventViewController extends Controller $date = $ticket->ticket_date->format('d M'); $ticket_dates[$date][] = $ticket; } - +// dd($ticket_dates); $data = [ 'event' => $event, 'ticket_dates' =>$ticket_dates, diff --git a/app/Http/routes.php b/app/Http/routes.php index 084d9dfa..f8f82329 100644 --- a/app/Http/routes.php +++ b/app/Http/routes.php @@ -161,6 +161,11 @@ Route::group( 'uses' => 'EventViewController@showEventHomePreview', ]); + Route::post('{event_id}/checkout/date',[ + 'as' => 'postValidateDate', + 'uses' => 'EventCheckoutController@postValidateDate' + ]); + Route::post('{event_id}/checkout/', [ 'as' => 'postValidateTickets', 'uses' => 'EventCheckoutController@postValidateTickets', diff --git a/app/Models/Event.php b/app/Models/Event.php index d641614e..318665fc 100644 --- a/app/Models/Event.php +++ b/app/Models/Event.php @@ -25,8 +25,9 @@ class Event extends MyBaseModel return [ 'title' => 'required', 'description' => 'required', - 'location_venue_name' => 'required_without:venue_name_full', - 'venue_name_full' => 'required_without:location_venue_name', + 'venue_id' => 'required', +// 'location_venue_name' => 'required_without:venue_name_full', +// 'venue_name_full' => 'required_without:location_venue_name', 'start_date' => 'required|date_format:"'.$format.'"', 'end_date' => 'required|date_format:"'.$format.'"', 'organiser_name' => 'required_without:organiser_id', @@ -197,6 +198,9 @@ class Event extends MyBaseModel return $this->belongsToMany(\App\Models\Tag::class); } + public function venue(){ + return $this->belongsTo(Venue::class); + } /** * Category associated with the event * @return \Illuminate\Database\Eloquent\Relations\BelongsTo @@ -490,8 +494,5 @@ ICSTemplate; ->orderBy('created_at','desc') ->limit(1); }] ); - - } - } diff --git a/app/Models/Section.php b/app/Models/Section.php new file mode 100644 index 00000000..e0514aa5 --- /dev/null +++ b/app/Models/Section.php @@ -0,0 +1,99 @@ + 'array']; + /* + |-------------------------------------------------------------------------- + | FUNCTIONS + |-------------------------------------------------------------------------- + */ + public static function boot() + { + parent::boot(); + static::deleting(function($obj) { + $disk = config('filesystems.default'); + \Storage::disk($disk)->delete($obj->section_image); + }); + } + /* + |-------------------------------------------------------------------------- + | RELATIONS + |-------------------------------------------------------------------------- + */ + public function venue(){ + return $this->belongsTo(Venue::class); + } + + public function tickets(){ + return $this->hasMany(Ticket::class); + } + /* + |-------------------------------------------------------------------------- + | SCOPES + |-------------------------------------------------------------------------- + */ + + /* + |-------------------------------------------------------------------------- + | ACCESORS + |-------------------------------------------------------------------------- + */ + + /* + |-------------------------------------------------------------------------- + | MUTATORS + |-------------------------------------------------------------------------- + */ + public function setSectionImageAttribute($value){ + $attribute_name = "section_image"; + $disk = config('filesystems.default'); // or use your own disk, defined in config/filesystems.php + $destination_path = "venues"; // path relative to the disk above + + // if the image was erased + if ($value==null) { + // delete the image from disk + \Storage::disk($disk)->delete($this->{$attribute_name}); + + // set null in the database column + $this->attributes[$attribute_name] = null; + } + + // if a base64 was sent, store it in the db + if (starts_with($value, 'data:image')) + { + // 0. Make the image + $image = \Image::make($value)->encode('jpg', 90); + // 1. Generate a filename. + $filename = md5($value.time()).'.jpg'; + // 2. Store the image on disk. + \Storage::disk($disk)->put($destination_path.'/'.$filename, $image->stream()); + // 3. Save the public path to the database + // but first, remove "public/" from the path, since we're pointing to it from the root folder + // that way, what gets saved in the database is the user-accesible URL + $public_destination_path = Str::replaceFirst('public/', '', $destination_path); + $this->attributes[$attribute_name] = $public_destination_path.'/'.$filename; + } + } +} diff --git a/app/Models/Ticket.php b/app/Models/Ticket.php index 584679f9..d01a048d 100644 --- a/app/Models/Ticket.php +++ b/app/Models/Ticket.php @@ -22,6 +22,7 @@ class Ticket extends MyBaseModel $format = config('attendize.default_datetime_format'); return [ 'title' => 'required', + 'section_id' => 'required', 'price' => 'required|numeric|min:0', 'description' => '', 'ticket_date' => 'required|date_format:"'.$format.'"', @@ -39,6 +40,7 @@ class Ticket extends MyBaseModel public $messages = [ 'price.numeric' => 'The price must be a valid number (e.g 12.50)', 'title.required' => 'You must at least give a title for your ticket. (e.g Early Bird)', + 'section_id.required' => 'You must select section', 'quantity_available.integer' => 'Please ensure the quantity available is a number.', ]; protected $perPage = 10; @@ -53,6 +55,9 @@ class Ticket extends MyBaseModel return $this->belongsTo(\App\Models\Event::class); } + public function section(){ + return $this->belongsTo(Section::class); + } /** * The order associated with the ticket. * diff --git a/app/Models/Venue.php b/app/Models/Venue.php new file mode 100644 index 00000000..a8d25a0f --- /dev/null +++ b/app/Models/Venue.php @@ -0,0 +1,119 @@ + 'array']; + protected $table = 'venues'; + // protected $primaryKey = 'id'; + public $timestamps = false; + // protected $guarded = ['id']; + protected $fillable = [ + 'venue_name', + 'venue_name_full', + 'location_address', + 'location_address_line_1', + 'location_address_line_2', + 'location_country', + 'location_country_code', + 'location_state', + 'location_post_code', + 'location_street_number', + 'location_lat', + 'location_long', + 'location_google_place_id', + 'seats_image', + 'active', + 'address' + ]; + // protected $hidden = []; + // protected $dates = []; + + /* + |-------------------------------------------------------------------------- + | FUNCTIONS + |-------------------------------------------------------------------------- + */ + public static function boot() + { + parent::boot(); + static::deleting(function($obj) { + $disk = config('filesystems.default'); + \Storage::disk($disk)->delete($obj->seats_image); + }); + } + + + + /* + |-------------------------------------------------------------------------- + | RELATIONS + |-------------------------------------------------------------------------- + */ + public function events(){ + return $this->hasMany(Event::class); + } + + public function sections(){ + return $this->hasMany(Section::class); + } + /* + |-------------------------------------------------------------------------- + | SCOPES + |-------------------------------------------------------------------------- + */ + + /* + |-------------------------------------------------------------------------- + | ACCESORS + |-------------------------------------------------------------------------- + */ + + /* + |-------------------------------------------------------------------------- + | MUTATORS + |-------------------------------------------------------------------------- + */ + public function setSeatsImageAttribute($value){ + $attribute_name = "seats_image"; + $disk = config('filesystems.default'); // or use your own disk, defined in config/filesystems.php + $destination_path = "venues"; // path relative to the disk above + + // if the image was erased + if ($value==null) { + // delete the image from disk + \Storage::disk($disk)->delete($this->{$attribute_name}); + + // set null in the database column + $this->attributes[$attribute_name] = null; + } + + // if a base64 was sent, store it in the db + if (starts_with($value, 'data:image')) + { + // 0. Make the image + $image = \Image::make($value)->encode('jpg', 90); + // 1. Generate a filename. + $filename = md5($value.time()).'.jpg'; + // 2. Store the image on disk. + \Storage::disk($disk)->put($destination_path.'/'.$filename, $image->stream()); + // 3. Save the public path to the database + // but first, remove "public/" from the path, since we're pointing to it from the root folder + // that way, what gets saved in the database is the user-accesible URL + $public_destination_path = Str::replaceFirst('public/', '', $destination_path); + $this->attributes[$attribute_name] = $public_destination_path.'/'.$filename; + } + } +} diff --git a/config/backpack/base.php b/config/backpack/base.php index f88944be..230f34e1 100644 --- a/config/backpack/base.php +++ b/config/backpack/base.php @@ -67,7 +67,7 @@ return [ // The prefix used in all base routes (the 'admin' in admin/dashboard) // You can make sure all your URLs use this prefix by using the backpack_url() helper instead of url() - 'route_prefix' => 'admin', + 'route_prefix' => 'panel', // Set this to false if you would like to use your own AuthController and PasswordController // (you then need to setup your auth routes manually in your routes.php file) diff --git a/config/services.php b/config/services.php index bda1e037..65aa11e4 100644 --- a/config/services.php +++ b/config/services.php @@ -40,5 +40,8 @@ return [ 'sparkpost' => [ 'secret' => env('SPARKPOST_SECRET') - ] + ], + 'google_places' => [ + 'key' => env('GOOGLE_MAPS_GEOCODING_KEY') + ], ]; diff --git a/database/migrations/2014_03_26_180116_create_users_table.php b/database/migrations/2014_03_26_180116_create_users_table.php index 42bba3c3..fc59937b 100644 --- a/database/migrations/2014_03_26_180116_create_users_table.php +++ b/database/migrations/2014_03_26_180116_create_users_table.php @@ -194,19 +194,7 @@ class CreateUsersTable extends Migration $t->unsignedInteger('organiser_id'); $t->foreign('organiser_id')->references('id')->on('organisers'); - $t->string('venue_name'); - $t->string('venue_name_full')->nullable(); - $t->string('location_address', 355)->nullable(); - $t->string('location_address_line_1', 355); - $t->string('location_address_line_2', 355); - $t->string('location_country')->nullable(); - $t->string('location_country_code')->nullable(); - $t->string('location_state'); - $t->string('location_post_code'); - $t->string('location_street_number')->nullable(); - $t->string('location_lat')->nullable(); - $t->string('location_long')->nullable(); - $t->string('location_google_place_id')->nullable(); + $t->unsignedInteger('ask_for_all_attendees_info')->default(0); diff --git a/database/migrations/2019_10_23_151735_create_venues_table.php b/database/migrations/2019_10_23_151735_create_venues_table.php new file mode 100644 index 00000000..00e354f4 --- /dev/null +++ b/database/migrations/2019_10_23_151735_create_venues_table.php @@ -0,0 +1,56 @@ +increments('id'); + $t->string('venue_name'); + $t->string('venue_name_full')->nullable(); + $t->string('location_address', 355)->nullable(); + $t->string('location_address_line_1', 355); + $t->string('location_address_line_2', 355); + $t->string('location_country')->nullable(); + $t->string('location_country_code')->nullable(); + $t->string('location_state'); + $t->string('location_post_code'); + $t->string('location_street_number')->nullable(); + $t->string('location_lat')->nullable(); + $t->string('location_long')->nullable(); + $t->string('location_google_place_id')->nullable(); + $t->string('seats_image')->nullable(); + $t->boolean('active')->default(1); + $t->json('address')->nullable(); + }); + + Schema::table('events', function (Blueprint $table) { + $table->integer('venue_id')->nullable(); + $table->foreign('venue_id')->references('id')->on('venues'); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('events', function (Blueprint $table){ + $table->dropForeign('venue_id'); + $table->dropColumn('venue_id'); + }); + + Schema::dropIfExists('venues'); + } +} diff --git a/database/migrations/2019_10_30_163805_create_sections_table.php b/database/migrations/2019_10_30_163805_create_sections_table.php new file mode 100644 index 00000000..be70328d --- /dev/null +++ b/database/migrations/2019_10_30_163805_create_sections_table.php @@ -0,0 +1,37 @@ +increments('id'); + $table->string('section_no')->nullable(); + $table->string('description')->nullable(); + $table->json('seats')->nullable(); + $table->string('section_image')->nullable(); + $table->unsignedInteger('venue_id'); + $table->foreign('venue_id')->references('id')->on('venues')->onDelete('cascade'); +// $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('sections'); + } +} diff --git a/database/migrations/2019_10_30_170931_add_ticket_section_id_to_tickets_table.php b/database/migrations/2019_10_30_170931_add_ticket_section_id_to_tickets_table.php new file mode 100644 index 00000000..f437ba74 --- /dev/null +++ b/database/migrations/2019_10_30_170931_add_ticket_section_id_to_tickets_table.php @@ -0,0 +1,33 @@ +unsignedInteger('section_id')->nullable(); + $table->foreign('section_id')->references('id')->on('sections'); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('tickets', function (Blueprint $table) { + // + }); + } +} diff --git a/database/migrations/2019_10_31_173838_add_seat_to_attendees_table.php b/database/migrations/2019_10_31_173838_add_seat_to_attendees_table.php new file mode 100644 index 00000000..66fe5275 --- /dev/null +++ b/database/migrations/2019_10_31_173838_add_seat_to_attendees_table.php @@ -0,0 +1,34 @@ +string('row')->nullable(); + $table->string('no')->nullable(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('attendees', function (Blueprint $table) { + $table->dropColumn('row'); + $table->dropColumn('no'); + }); + } +} diff --git a/resources/views/Bilettm/ViewEvent/EventPage.blade.php b/resources/views/Bilettm/ViewEvent/EventPage.blade.php index 5fe2f0f3..414483d6 100644 --- a/resources/views/Bilettm/ViewEvent/EventPage.blade.php +++ b/resources/views/Bilettm/ViewEvent/EventPage.blade.php @@ -29,11 +29,13 @@ {{$event->organiser->name}} @lang("Public_ViewEvent.presents") @lang("Public_ViewEvent.at") - {{$event->venue_name}} - + {{$event->venue->venue_name}} + - @include('Bilettm.ViewEvent.Partials.TicketSchedule') +
+ @include('Bilettm.ViewEvent.Partials.Schedule') +
@@ -61,8 +63,4 @@ -@endsection -@section('after_scripts') - @include("Shared.Partials.LangScript") - {!!HTML::script(config('attendize.cdn_url_static_assets').'/assets/javascript/frontend.js')!!} @endsection \ No newline at end of file diff --git a/resources/views/Bilettm/ViewEvent/Partials/Schedule.blade.php b/resources/views/Bilettm/ViewEvent/Partials/Schedule.blade.php new file mode 100644 index 00000000..c2aa56f7 --- /dev/null +++ b/resources/views/Bilettm/ViewEvent/Partials/Schedule.blade.php @@ -0,0 +1,66 @@ +

Расписание

+
+@if($event->end_date->isPast()) +
+

+ @lang("Public_ViewEvent.event_already", ['started' => trans('Public_ViewEvent.event_already_ended')]) +

+
+@else + @if(count($ticket_dates) > 0) + +

Дата проведения

+
+ +
+

Время проведения

+
+ +
+ {!! Form::open(['url' => route('postValidateDate', ['event_id' => $event->id])]) !!} + @csrf + @foreach($ticket_dates as $date =>$tickets) +
+
+ + @foreach($tickets as $ticket) +
+ first)checked @endif name="ticket_date" value="{{$ticket->ticket_date}}"> + +
+ + @endforeach + +
+
+ @endforeach + {!!Form::submit('Kupit bilet', ['class' => 'btn btn-lg btn-danger'])!!} + {!! Form::close() !!} +
+
+ @endif +@endif +@push('after_scripts') + +@endpush \ No newline at end of file diff --git a/resources/views/Bilettm/ViewEvent/Partials/Seats.blade.php b/resources/views/Bilettm/ViewEvent/Partials/Seats.blade.php new file mode 100644 index 00000000..37371912 --- /dev/null +++ b/resources/views/Bilettm/ViewEvent/Partials/Seats.blade.php @@ -0,0 +1,33 @@ +@foreach($tickets as $ticket) +
+
+ {{$ticket->section->section_no}} +
+
+
{{$ticket->title }} {{$ticket->description}} {{$ticket->section->section_no}}
+ + + @foreach($ticket->section->seats as $row) + + + + + @for($i = $row['start_no'];$i<=$row['end_no'];$i++) + + @endfor + + + @endforeach +
{{$row['row']}} + + +
+
+
+
+@endforeach diff --git a/resources/views/Bilettm/ViewEvent/SeatsPage.blade.php b/resources/views/Bilettm/ViewEvent/SeatsPage.blade.php new file mode 100644 index 00000000..39f96db5 --- /dev/null +++ b/resources/views/Bilettm/ViewEvent/SeatsPage.blade.php @@ -0,0 +1,70 @@ +@extends('Bilettm.Layouts.BilettmLayout') +@section('content') + {{\DaveJamesMiller\Breadcrumbs\Facades\Breadcrumbs::render('seats',$event)}} +
+
+ +
+
+
+ +
+ Available + Booked + Reserved + Your Selection +
+ + + + + + + + + + + + + + +
+ @include('Bilettm.ViewEvent.Partials.Seats') +
+
+
You Have Selected 4 Standard Seats
+
Your Seats:
+
+ @csrf +
+ G-12 + G-13 + G-14 + G-15 +
+ Confirm seats +
+
+
+
+
+ +
+
+@endsection +@section('after_scripts') + @include("Shared.Partials.LangScript") + {!!HTML::script(config('attendize.cdn_url_static_assets').'/assets/javascript/frontend.js')!!} +@endsection \ No newline at end of file diff --git a/resources/views/ManageEvent/Customize.blade.php b/resources/views/ManageEvent/Customize.blade.php index 03f75dc9..f08166f5 100644 --- a/resources/views/ManageEvent/Customize.blade.php +++ b/resources/views/ManageEvent/Customize.blade.php @@ -28,8 +28,8 @@ @stop @section('head') - {!! HTML::script('https://maps.googleapis.com/maps/api/js?sensor=false&libraries=places&key='.env("GOOGLE_MAPS_GEOCODING_KEY")) !!} - {!! HTML::script('vendor/geocomplete/jquery.geocomplete.min.js') !!} + {{--{!! HTML::script('https://maps.googleapis.com/maps/api/js?sensor=false&libraries=places&key='.config("services.google_places.key")) !!}--}} + {{--{!! HTML::script('vendor/geocomplete/jquery.geocomplete.min.js') !!}--}} - {!! HTML::script('https://maps.googleapis.com/maps/api/js?sensor=false&libraries=places&key='.env("GOOGLE_MAPS_GEOCODING_KEY")) !!} + {!! HTML::script('https://maps.googleapis.com/maps/api/js?sensor=false&libraries=places&key='.config("services.google_places.key")) !!} {!! HTML::script('vendor/geocomplete/jquery.geocomplete.min.js')!!} {!! HTML::script('vendor/moment/moment.js')!!} {!! HTML::script('vendor/fullcalendar/dist/fullcalendar.min.js')!!} diff --git a/resources/views/ManageOrganiser/Events.blade.php b/resources/views/ManageOrganiser/Events.blade.php index 7f149884..d3dda3f2 100644 --- a/resources/views/ManageOrganiser/Events.blade.php +++ b/resources/views/ManageOrganiser/Events.blade.php @@ -13,10 +13,10 @@ @include('ManageOrganiser.Partials.TopNav') @stop -@section('head') - {!! HTML::script('https://maps.googleapis.com/maps/api/js?sensor=false&libraries=places&key='.env("GOOGLE_MAPS_GEOCODING_KEY")) !!} - {!! HTML::script('vendor/geocomplete/jquery.geocomplete.min.js')!!} -@stop +{{--@section('head')--}} + {{--{!! HTML::script('https://maps.googleapis.com/maps/api/js?sensor=false&libraries=places&key='.config("services.google_places.key")) !!}--}} + {{--{!! HTML::script('vendor/geocomplete/jquery.geocomplete.min.js')!!}--}} +{{--@stop--}} @section('menu') @include('ManageOrganiser.Partials.Sidebar') diff --git a/resources/views/ManageOrganiser/Modals/CreateEvent.blade.php b/resources/views/ManageOrganiser/Modals/CreateEvent.blade.php index 3ea189f2..e5de80be 100644 --- a/resources/views/ManageOrganiser/Modals/CreateEvent.blade.php +++ b/resources/views/ManageOrganiser/Modals/CreateEvent.blade.php @@ -16,12 +16,12 @@
{!! Form::label('title', trans("Event.event_title"), array('class'=>'control-label required')) !!} - {!! Form::text('title', Input::old('title'),array('class'=>'form-control','placeholder'=>trans("Event.event_title_placeholder", ["name"=>Auth::user()->first_name]) )) !!} + {!! Form::text('title', Input::old('title'),array('class'=>'form-control','placeholder'=>trans("Event.event_title_placeholder", ["name"=>Auth::user()->first_name]) )) !!}
{!! Form::label('description', trans("Event.event_description"), array('class'=>'control-label required')) !!} - {!! Form::textarea('description', Input::old('description'), + {!! Form::textarea('description', Input::old('description'), array( 'class'=>'form-control editable', 'rows' => 5 @@ -78,90 +78,92 @@
- {!! Form::label('name', trans("Event.venue_name"), array('class'=>'control-label required ')) !!} - {!! Form::text('venue_name_full', Input::old('venue_name_full'), - array( - 'class'=>'form-control geocomplete location_field', - 'placeholder'=>trans("Event.venue_name_placeholder") - )) !!} + {!! Form::label('venue_name', trans("Event.venue_name"), array('class'=>'control-label required ')) !!} + {!! Form::select('venue_id',venues_list(), Input::old('venue_id'), ['class' => 'form-control','id'=>'venue_name']) !!} - -
- {!! Form::hidden('formatted_address', '', ['class' => 'location_field']) !!} - {!! Form::hidden('street_number', '', ['class' => 'location_field']) !!} - {!! Form::hidden('country', '', ['class' => 'location_field']) !!} - {!! Form::hidden('country_short', '', ['class' => 'location_field']) !!} - {!! Form::hidden('place_id', '', ['class' => 'location_field']) !!} - {!! Form::hidden('name', '', ['class' => 'location_field']) !!} - {!! Form::hidden('location', '', ['class' => 'location_field']) !!} - {!! Form::hidden('postal_code', '', ['class' => 'location_field']) !!} - {!! Form::hidden('route', '', ['class' => 'location_field']) !!} - {!! Form::hidden('lat', '', ['class' => 'location_field']) !!} - {!! Form::hidden('lng', '', ['class' => 'location_field']) !!} - {!! Form::hidden('administrative_area_level_1', '', ['class' => 'location_field']) !!} - {!! Form::hidden('sublocality', '', ['class' => 'location_field']) !!} - {!! Form::hidden('locality', '', ['class' => 'location_field']) !!} -
- + {{--{!! Form::text('venue_name_full', Input::old('venue_name_full'),--}} + {{--array(--}} + {{--'class'=>'form-control geocomplete location_field',--}} + {{--'placeholder'=>trans("Event.venue_name_placeholder")--}} + {{--)) !!}--}} + + {{----}} + {{--
--}} + {{--{!! Form::hidden('formatted_address', '', ['class' => 'location_field']) !!}--}} + {{--{!! Form::hidden('street_number', '', ['class' => 'location_field']) !!}--}} + {{--{!! Form::hidden('country', '', ['class' => 'location_field']) !!}--}} + {{--{!! Form::hidden('country_short', '', ['class' => 'location_field']) !!}--}} + {{--{!! Form::hidden('place_id', '', ['class' => 'location_field']) !!}--}} + {{--{!! Form::hidden('name', '', ['class' => 'location_field']) !!}--}} + {{--{!! Form::hidden('location', '', ['class' => 'location_field']) !!}--}} + {{--{!! Form::hidden('postal_code', '', ['class' => 'location_field']) !!}--}} + {{--{!! Form::hidden('route', '', ['class' => 'location_field']) !!}--}} + {{--{!! Form::hidden('lat', '', ['class' => 'location_field']) !!}--}} + {{--{!! Form::hidden('lng', '', ['class' => 'location_field']) !!}--}} + {{--{!! Form::hidden('administrative_area_level_1', '', ['class' => 'location_field']) !!}--}} + {{--{!! Form::hidden('sublocality', '', ['class' => 'location_field']) !!}--}} + {{--{!! Form::hidden('locality', '', ['class' => 'location_field']) !!}--}} + {{--
--}} + {{----}}
- --}} - - @lang("Event.enter_existing")" href="javascript:void(0);" - class="in-form-link show-more-options clear_location"> - @lang("Event.or(manual/existing_venue)") @lang("Event.enter_manual") - - + {{----}} + {{--@lang("Event.enter_existing")" href="javascript:void(0);"--}} + {{--class="in-form-link show-more-options clear_location">--}} + {{--@lang("Event.or(manual/existing_venue)") @lang("Event.enter_manual")--}} + {{----}} + {{----}} @if($organiser_id) {!! Form::hidden('organiser_id', $organiser_id) !!} diff --git a/resources/views/ManageOrganiser/Partials/EventCreateAndEditJS.blade.php b/resources/views/ManageOrganiser/Partials/EventCreateAndEditJS.blade.php index 71b7ac5a..f95feba4 100644 --- a/resources/views/ManageOrganiser/Partials/EventCreateAndEditJS.blade.php +++ b/resources/views/ManageOrganiser/Partials/EventCreateAndEditJS.blade.php @@ -3,17 +3,17 @@ {!!HTML::style('assets/vendor/icon-awesome/css/font-awesome.min.css')!!} + + + @endpush + +@endif +{{-- End of Extra CSS and JS --}} +{{-- ########################################## --}} diff --git a/routes/backpack/custom.php b/routes/backpack/custom.php index 975c7959..e3898af1 100644 --- a/routes/backpack/custom.php +++ b/routes/backpack/custom.php @@ -18,4 +18,6 @@ Route::group([ CRUD::resource('tag', 'TagCrudController'); CRUD::resource('subscriber', 'SubscriberCrudController'); CRUD::resource('event_request', 'EventRequestCrudController'); + CRUD::resource('venue', 'VenueCrudController'); + CRUD::resource('section', 'SectionCrudController'); }); // this should be the absolute last line of this file \ No newline at end of file diff --git a/routes/breadcrumbs.php b/routes/breadcrumbs.php index babf701a..995df9e1 100644 --- a/routes/breadcrumbs.php +++ b/routes/breadcrumbs.php @@ -25,6 +25,11 @@ Breadcrumbs::for('event',function($trail, $event){ $trail->push($event->title,$event->event_url); }); +Breadcrumbs::for('seats',function ($trail,$event){ + $trail->parent('event',$event); + $trail->push('Pokupka'); +}); + Breadcrumbs::for('search',function($trail){ $trail->parent('home'); $trail->push('Результат поиска');