diff --git a/.env.travis b/.env.travis new file mode 100755 index 00000000..3758e435 --- /dev/null +++ b/.env.travis @@ -0,0 +1,15 @@ +APP_ENV=testing +APP_KEY=woofpoowflabs + + +DB_CONNECTION=mysql +DB_HOST=localhost +DB_PORT=3306 +DB_DATABASE=invoiceplz_test +DB_USERNAME=root +DB_PASSWORD=poowf + +BROADCAST_DRIVER=log +CACHE_DRIVER=file +SESSION_DRIVER=file +QUEUE_DRIVER=sync \ No newline at end of file diff --git a/.gitignore b/.gitignore index 159483b4..a2c390d4 100755 --- a/.gitignore +++ b/.gitignore @@ -12,6 +12,7 @@ npm-debug.log yarn-error.log .env .env.dusk.local +.env.testing .phpunit.result.cache .DS_Store diff --git a/.travis.yml b/.travis.yml new file mode 100755 index 00000000..081480c8 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,37 @@ +language: php +sudo: true +php: + - '7.1' + - '7.2' + +before_script: + - cp .env.travis .env + - mysql -u root -ppoowf -e 'create database invoiceplz_test;' + - composer self-update + - composer install --no-interaction + - php artisan key:generate + - php artisan migrate + +script: + - vendor/bin/phpunit + +addons: + apt: + sources: + - mysql-5.7-trusty + packages: + - mysql-server + - mysql-client + +before_install: +- sudo mysql -e "use mysql; update user set authentication_string=PASSWORD('poowf') where User='root'; update user set plugin='mysql_native_password';FLUSH PRIVILEGES;" +- sudo mysql_upgrade -u root -ppoowf +- sudo service mysql restart + +services: + - mysql + +cache: + directories: + - node_modules + - vendor \ No newline at end of file diff --git a/app/Http/Controllers/CompanyAddressController.php b/app/Http/Controllers/CompanyAddressController.php index 6c973571..63b0e58e 100755 --- a/app/Http/Controllers/CompanyAddressController.php +++ b/app/Http/Controllers/CompanyAddressController.php @@ -70,7 +70,6 @@ public function edit() $companyaddress = null; } - return view('pages.company.address.edit', compact('companyaddress', 'ownedcompany')); } @@ -93,6 +92,8 @@ public function update(UpdateCompanyAddressRequest $request) $companyaddress->fill($request->all()); $ownedcompany->address()->save($companyaddress); + flash('Company Address Updated', 'success'); + return redirect()->back(); } diff --git a/app/Http/Controllers/CompanyController.php b/app/Http/Controllers/CompanyController.php index 221ea2f1..c05e0b28 100755 --- a/app/Http/Controllers/CompanyController.php +++ b/app/Http/Controllers/CompanyController.php @@ -3,7 +3,11 @@ namespace App\Http\Controllers; use App\Http\Requests\CreateCompanyRequest; +use App\Http\Requests\CreateCompanyUserRequest; +use App\Http\Requests\UpdateCompanyOwnerRequest; use App\Http\Requests\UpdateCompanyRequest; +use App\Http\Requests\UpdateCompanyUserRequest; +use App\Notifications\NewCompanyUserNotification; use Illuminate\Http\Request; use App\Models\Company; use App\Models\User; @@ -115,7 +119,8 @@ public function store(CreateCompanyRequest $request) */ public function show() { - // + $company = auth()->user()->company; + return view('pages.company.show', compact('company')); } /** @@ -145,6 +150,7 @@ public function update(UpdateCompanyRequest $request) } else { + //TODO: Prevent User from registering a company if the domain name has already been registered. $company = new Company; $company->user_id = auth()->user()->id; $isnew = true; @@ -164,7 +170,9 @@ public function update(UpdateCompanyRequest $request) if (!Storage::exists($storedirectory . 'logo_' . $filename)) { - $image = Image::make($file)->fit(420, 220, function ($constraint) { + $image = Image::make($file) + ->encode('png', 100) + ->fit(420, 220, function ($constraint) { $constraint->upsize(); }, 'center'); Storage::put($storedirectory . 'logo_' . $filename, $image->stream('jpg')->detach()); @@ -183,7 +191,9 @@ public function update(UpdateCompanyRequest $request) if (!Storage::exists($storedirectory . 'smlogo_' . $filename)) { - $image = Image::make($file)->fit(200, 200, function ($constraint) { + $image = Image::make($file) + ->encode('png', 100) + ->fit(200, 200, function ($constraint) { $constraint->upsize(); }, 'center'); Storage::put($storedirectory . 'smlogo_' . $filename, $image->stream('jpg')->detach()); @@ -217,4 +227,139 @@ public function destroy() { // } + + public function edit_owner() { + $company = auth()->user()->company; + + if($company) + { + $owner = $company->owner; + $users = $company->users; + } + else + { + $owner = collect(); + $users = collect(); + } + + return view('pages.company.owner.edit', compact('company', 'owner', 'users')); + } + + public function update_owner(UpdateCompanyOwnerRequest $request) { + $company = auth()->user()->ownedcompany; + $user = User::find($request->input('user_id')); + $company->user_id = $user->id; + $company->save(); + + return redirect()->back(); + } + + public function index_users() { + $company = auth()->user()->company; + + if($company) + { + $users = $company->users()->paginate(12); + } + else + { + $users = collect(); + } + + return view('pages.company.users.index', compact('users', 'company')); + } + + public function create_users() { + $company = auth()->user()->company; + + return view('pages.company.users.create', compact('company')); + } + public function store_users(CreateCompanyUserRequest $request) { + $company = auth()->user()->company; + + $random_password = str_random(16); + + $user = new User; + $user->fill($request->all()); + $user->password = $random_password; + $user->company_id = $company->id; + $user->save(); + + $user->notify(new NewCompanyUserNotification($user, $random_password)); + + return redirect()->back(); + } + + public function edit_users(User $user) { + return view('pages.company.users.edit', compact('user')); + } + + public function update_users(UpdateCompanyUserRequest $request, User $user) { + $user->fill($request->all()); + if ($request->has('newpassword') && $request->input('newpassword') != null) { + $newpass = $request->input('newpassword'); + $user->password = $newpass; + } + $user->save(); + + return redirect()->back(); + } + + public function destroy_users(Request $request, User $user) { + + $auth_user = auth()->user(); + $usercompany = $user->company; + + //TODO: Probably need to rewrite/refactor this logic to somewhere else + if ($usercompany) + { + if ($usercompany->isOwner($auth_user)) + { + if($user->id != $auth_user->id) + { + $user->delete(); + flash('User Deleted', 'success'); + } + else + { + flash('You cannot delete the owner of the Company', 'error'); + } + } + else + { + flash('Unauthorised', 'error'); + } + } + else + { + flash('Nothing was done', 'error'); + } + + return redirect()->back(); + } + + public function show_check() + { + return view('pages.company.check'); + } + + public function check(Request $request) + { + $email = $request->input('email'); + +// $domain = preg_filter("/([^@]+)/","", $email); + + $explode = explode("@", $email); + $domain = array_pop($explode); + $company = Company::where('domain_name', $domain)->first(); + + if($company) + { + return redirect()->route('company.requests.create'); + } + else + { + return redirect()->route('user.create'); + } + } } diff --git a/app/Http/Controllers/CompanySettingsController.php b/app/Http/Controllers/CompanySettingsController.php index dce816ea..5b664036 100755 --- a/app/Http/Controllers/CompanySettingsController.php +++ b/app/Http/Controllers/CompanySettingsController.php @@ -91,6 +91,7 @@ public function update(UpdateCompanySettingsRequest $request) $companysettings->fill($request->all()); $ownedcompany->settings()->save($companysettings); + flash('Company Settings Updated', 'success'); return redirect()->back(); } diff --git a/app/Http/Controllers/CompanyUserRequestController.php b/app/Http/Controllers/CompanyUserRequestController.php new file mode 100755 index 00000000..9f8eae80 --- /dev/null +++ b/app/Http/Controllers/CompanyUserRequestController.php @@ -0,0 +1,143 @@ +user()->company; + + if($company) + { + $requests = $company->requests()->paginate(12); + } + else + { + $requests = collect(); + } + + return view('pages.company.requests.index', compact('requests')); + } + + /** + * Show the form for creating a new resource. + * + * @return \Illuminate\Http\Response + */ + public function create() + { + return view('pages.company.requests.create'); + } + + /** + * Store a newly created resource in storage. + * + * @param \Illuminate\Http\Request $request + * @return \Illuminate\Http\Response + */ + public function store(Request $request) + { + $email = $request->input('email'); + + $explode = explode("@", $email); + $domain = array_pop($explode); + $company = Company::where('domain_name', $domain)->first(); + + if($company) + { + $companyuserrequest = new CompanyUserRequest; + $companyuserrequest->fill($request->all()); + $company->user_requests()->save($companyuserrequest); + + $company->notify(new RequestCompanyAccessNotification($companyuserrequest->full_name, $companyuserrequest->email, $companyuserrequest->phone)); + + flash('The request has been sent to the current owner of the Company', "success"); + + return redirect()->route('main'); + } + else + { + flash('Unable to find your company', "error"); + + return redirect()->back(); + } + } + + public function approve(Request $request, CompanyUserRequest $companyUserRequest) + { + $companyUserRequest->status = CompanyUserRequest::STATUS_APPROVED; + $companyUserRequest->save(); + + $companyUserRequest->notify(new CompanyUserRequestApprovedNotification($companyUserRequest->token)); + + return redirect()->back(); + } + + public function reject(Request $request, CompanyUserRequest $companyUserRequest) + { + $companyUserRequest->status = CompanyUserRequest::STATUS_REJECTED; + $companyUserRequest->save(); + + $companyUserRequest->notify(new CompanyUserRequestRejectedNotification()); + + return redirect()->back(); + } + + /** + * Display the specified resource. + * + * @param \App\Models\CompanyUserRequest $companyUserRequest + * @return \Illuminate\Http\Response + */ + public function show(CompanyUserRequest $companyUserRequest) + { + // + } + + /** + * Show the form for editing the specified resource. + * + * @param \App\Models\CompanyUserRequest $companyUserRequest + * @return \Illuminate\Http\Response + */ + public function edit(CompanyUserRequest $companyUserRequest) + { + // + } + + /** + * Update the specified resource in storage. + * + * @param \Illuminate\Http\Request $request + * @param \App\Models\CompanyUserRequest $companyUserRequest + * @return \Illuminate\Http\Response + */ + public function update(Request $request, CompanyUserRequest $companyUserRequest) + { + // + } + + /** + * Remove the specified resource from storage. + * + * @param \App\Models\CompanyUserRequest $companyUserRequest + * @return \Illuminate\Http\Response + */ + public function destroy(CompanyUserRequest $companyUserRequest) + { + // + } +} diff --git a/app/Http/Controllers/MainController.php b/app/Http/Controllers/MainController.php index fe0f543b..58d4e3d8 100755 --- a/app/Http/Controllers/MainController.php +++ b/app/Http/Controllers/MainController.php @@ -17,6 +17,11 @@ public function main() return redirect()->route('auth.show'); } + public function start() + { + return view('pages.start'); + } + public function dashboard() { $user = auth()->user(); diff --git a/app/Http/Controllers/PaymentController.php b/app/Http/Controllers/PaymentController.php index 9dbb43c5..cb41e0d3 100755 --- a/app/Http/Controllers/PaymentController.php +++ b/app/Http/Controllers/PaymentController.php @@ -37,7 +37,7 @@ public function create() if($company) { - if ($company->invoices->count() == 0) + if ($company->invoices->count() <= 0) { return view('pages.payment.noinvoices'); } @@ -90,10 +90,23 @@ public function store(CreatePaymentRequest $request, Invoice $invoice) public function createsolo() { $company = auth()->user()->company; - $invoices = $company->invoices; - return view('pages.payment.createsolo', compact('invoices')); + if($company) + { + if ($invoices->count() <= 0) + { + return view('pages.payment.noinvoices'); + } + else + { + return view('pages.payment.createsolo', compact('invoices')); + } + } + else + { + return view('pages.invoice.nocompany'); + } } /** diff --git a/app/Http/Controllers/UserController.php b/app/Http/Controllers/UserController.php index e911aca7..d2fcb8ab 100755 --- a/app/Http/Controllers/UserController.php +++ b/app/Http/Controllers/UserController.php @@ -4,9 +4,11 @@ use App\Http\Requests\CreateUserRequest; use App\Http\Requests\UpdateUserRequest; +use App\Models\CompanyUserRequest; use Illuminate\Support\Facades\Hash; use Log; use App\Models\User; +use App\Models\Company; use Illuminate\Http\Request; class UserController extends Controller @@ -24,11 +26,23 @@ public function index() /** * Show the form for creating a new resource. * + * @param Request $request + * @param null $token * @return \Illuminate\Http\Response */ - public function create() + public function create(Request $request) { - return view('pages.user.create'); + $token = null; + if ($request->query->has('token')) + { + $token = $request->query->get('token'); + $companyUserRequest = CompanyUserRequest::where('token', $token)->first(); + session(['_old_input.full_name' => $companyUserRequest->full_name]); + session(['_old_input.email' => $companyUserRequest->email]); + session(['_old_input.phone' => $companyUserRequest->phone]); + } + + return view('pages.user.create', compact('token')); } /** @@ -44,6 +58,24 @@ public function store(CreateUserRequest $request) $user->password = $request->input('password'); $user->save(); + if ($request->query->has('token')) + { + $token = $request->query->get('token'); + $companyUserRequest = CompanyUserRequest::where('token', $token)->first(); + $user->company_id = $companyUserRequest->company_id; + $user->save(); + + $companyUserRequest->delete(); + + session()->forget('_old_input.full_name'); + session()->forget('_old_input.email'); + session()->forget('_old_input.phone'); + + flash('You can now sign in', 'success'); + + return redirect()->route('auth.show'); + } + $request->session()->put('user_id', $user->id); return redirect()->route('company.create'); @@ -70,6 +102,35 @@ public function edit() return view('pages.user.edit', compact('user')); } + /** + * Retrieve the user and return as object + * + * @param \App\Models\User $user + * @return ItemTemplate + */ + public function retrieve(User $user) + { + $auth_user = auth()->user(); + $usercompany = $user->company; + + //TODO: Probably need to rewrite/refactor this logic to somewhere else + if ($usercompany) + { + if ($usercompany->isOwner($auth_user)) + { + return response()->json($user); + } + else + { + return abort(401); + } + } + else + { + return abort(401); + } + } + /** * Update the specified resource in storage. * diff --git a/app/Http/Requests/CreateCompanyUserRequest.php b/app/Http/Requests/CreateCompanyUserRequest.php new file mode 100755 index 00000000..1b554d6b --- /dev/null +++ b/app/Http/Requests/CreateCompanyUserRequest.php @@ -0,0 +1,34 @@ + 'required|min:4|unique:users', + 'email' => 'required|email|unique:users', + 'full_name' => 'required', + 'phone' => 'required|unique:users', + 'gender' => 'required|in:male,female', + ]; + } +} diff --git a/app/Http/Requests/UpdateCompanyOwnerRequest.php b/app/Http/Requests/UpdateCompanyOwnerRequest.php new file mode 100755 index 00000000..93673380 --- /dev/null +++ b/app/Http/Requests/UpdateCompanyOwnerRequest.php @@ -0,0 +1,30 @@ + 'required', + ]; + } +} diff --git a/app/Http/Requests/UpdateCompanyUserRequest.php b/app/Http/Requests/UpdateCompanyUserRequest.php new file mode 100755 index 00000000..805031a2 --- /dev/null +++ b/app/Http/Requests/UpdateCompanyUserRequest.php @@ -0,0 +1,35 @@ + 'required|min:4|unique:users,username,' . $this->user->id, + 'email' => 'required|email|unique:users,email,' . $this->user->id, + 'phone' => 'required|unique:users,phone,' . $this->user->id, + 'gender' => 'required|in:male,female', + 'full_name' => 'required', + 'newpassword' => 'confirmed', + ]; + } +} diff --git a/app/Models/Client.php b/app/Models/Client.php index c2d7f097..522522d9 100755 --- a/app/Models/Client.php +++ b/app/Models/Client.php @@ -55,6 +55,11 @@ public function invoices() return $this->hasMany('App\Models\Invoice', 'client_id'); } + public function company() + { + return $this->belongsTo('App\Models\Company', 'company_id'); + } + public function scopeDuplicateCheck($query, $companyname) { return $query diff --git a/app/Models/Company.php b/app/Models/Company.php index 1d6497bd..a9587ee1 100755 --- a/app/Models/Company.php +++ b/app/Models/Company.php @@ -4,13 +4,14 @@ use Log; use App\Traits\UniqueSlug; +use Illuminate\Notifications\Notifiable; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\SoftDeletes; use Iatstuti\Database\Support\CascadeSoftDeletes; class Company extends Model { - use SoftDeletes, CascadeSoftDeletes, UniqueSlug; + use Notifiable, SoftDeletes, CascadeSoftDeletes, UniqueSlug; /** * The database table used by the model. @@ -27,6 +28,7 @@ class Company extends Model protected $fillable = [ 'name', 'crn', + 'domain_name', 'phone', 'email', ]; @@ -51,6 +53,16 @@ protected static function boot() }); } + /** + * Route notifications for the mail channel. + * + * @return string + */ + public function routeNotificationForMail() + { + return $this->email; + } + public function niceInvoiceID() { $companysettings = $this->settings; @@ -94,6 +106,16 @@ public function lastquote() return $this->hasOne('App\Models\Quote')->latest()->limit(1)->first(); } + public function users() + { + return $this->hasMany('App\Models\User', 'company_id'); + } + + public function requests() + { + return $this->hasMany('App\Models\CompanyUserRequest', 'company_id'); + } + public function quotes() { return $this->hasMany('App\Models\Quote', 'company_id'); diff --git a/app/Models/CompanyUserRequest.php b/app/Models/CompanyUserRequest.php new file mode 100755 index 00000000..75f4f373 --- /dev/null +++ b/app/Models/CompanyUserRequest.php @@ -0,0 +1,77 @@ + self::STATUS_PENDING + ]; + + protected static function boot() + { + parent::boot(); + + static::creating(function ($companyuserrequest) { + $companyuserrequest->token = str_random(30); + }); + } + + public function company() + { + return $this->belongsTo('App\Models\Company', 'company_id'); + } + + public function statusText() + { + $status = $this->status; + + switch($status) + { + default: + $textstatus = "Pending"; + break; + case self::STATUS_PENDING: + $textstatus = "Pending"; + break; + case self::STATUS_APPROVED: + $textstatus = "Approved"; + break; + case self::STATUS_REJECTED: + $textstatus = "Rejected"; + break; + } + + return $textstatus; + } +} diff --git a/app/Models/User.php b/app/Models/User.php index ad317b79..9abb5d8b 100755 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -15,6 +15,10 @@ class User extends Authenticatable use HasRoles; + const STATUS_ACTIVE = 1; + const STATUS_DISABLED = 2; + const STATUS_BANNED = 3; + /** * The database table used by the model. * @@ -45,6 +49,9 @@ class User extends Authenticatable 'remember_token', ]; + protected $attributes = [ + 'status' => self::STATUS_ACTIVE + ]; /** * Get the route key for the model. @@ -118,6 +125,29 @@ public function confirmEmail() $this->save(); } + public function statusText() + { + $status = $this->status; + + switch($status) + { + default: + $textstatus = "Unknown"; + break; + case self::STATUS_ACTIVE: + $textstatus = "Active"; + break; + case self::STATUS_BANNED: + $textstatus = "Banned"; + break; + case self::STATUS_DISABLED: + $textstatus = "Disabled"; + break; + } + + return $textstatus; + } + public function sendConfirmEmailNotification() { $token = $this->confirmation_token; diff --git a/app/Notifications/CompanyUserRequestApprovedNotification.php b/app/Notifications/CompanyUserRequestApprovedNotification.php new file mode 100755 index 00000000..d3ed4007 --- /dev/null +++ b/app/Notifications/CompanyUserRequestApprovedNotification.php @@ -0,0 +1,64 @@ +token = $token; + } + + /** + * Get the notification's delivery channels. + * + * @param mixed $notifiable + * @return array + */ + public function via($notifiable) + { + return ['mail']; + } + + /** + * Get the mail representation of the notification. + * + * @param mixed $notifiable + * @return \Illuminate\Notifications\Messages\MailMessage + */ + public function toMail($notifiable) + { + $url = route('user.create', ['token' => $this->token]); + + return (new MailMessage) + ->subject("Your requested to be added to your company on " . config('app.name') . " has been approved") + ->line('Please fill in the rest of your details on' . config('app.name')) + ->action('Create Account', $url) + ->line('Thank you for using our application!'); + } + + /** + * Get the array representation of the notification. + * + * @param mixed $notifiable + * @return array + */ + public function toArray($notifiable) + { + return [ + // + ]; + } +} diff --git a/app/Notifications/CompanyUserRequestRejectedNotification.php b/app/Notifications/CompanyUserRequestRejectedNotification.php new file mode 100755 index 00000000..ba8c3a6b --- /dev/null +++ b/app/Notifications/CompanyUserRequestRejectedNotification.php @@ -0,0 +1,61 @@ +subject("Your requested to be added to your company on " . config('app.name') . " has been rejected") + ->line('Please contact your company administrator for the reason') + ->line('Thank you for using our application!'); + } + + /** + * Get the array representation of the notification. + * + * @param mixed $notifiable + * @return array + */ + public function toArray($notifiable) + { + return [ + // + ]; + } +} diff --git a/app/Notifications/NewCompanyUserNotification.php b/app/Notifications/NewCompanyUserNotification.php new file mode 100755 index 00000000..7c62d468 --- /dev/null +++ b/app/Notifications/NewCompanyUserNotification.php @@ -0,0 +1,72 @@ +user = $user; + $this->password = $password; + } + + /** + * Get the notification's delivery channels. + * + * @param mixed $notifiable + * @return array + */ + public function via($notifiable) + { + return ['mail']; + } + + /** + * Get the mail representation of the notification. + * + * @param mixed $notifiable + * @return \Illuminate\Notifications\Messages\MailMessage + */ + public function toMail($notifiable) + { + $user = $this->user; + $password = $this->password; + $url = route('auth.show'); + + return (new MailMessage) + ->subject("You have been added to a company on " . config('app.name')) + ->greeting("Hello {$user->full_name}!") + ->line('A new account has been created for you on ' . config('app.name')) + ->line('You account details are: ') + ->line("Username: {$user->username}") + ->line("Password: {$password}") + ->action('Sign In', $url) + ->line('Thank you for using our application!'); + } + + /** + * Get the array representation of the notification. + * + * @param mixed $notifiable + * @return array + */ + public function toArray($notifiable) + { + return [ + // + ]; + } +} diff --git a/app/Notifications/RequestCompanyAccessNotification.php b/app/Notifications/RequestCompanyAccessNotification.php new file mode 100755 index 00000000..34c2d591 --- /dev/null +++ b/app/Notifications/RequestCompanyAccessNotification.php @@ -0,0 +1,66 @@ +full_name = $full_name; + $this->email = $email; + $this->phone = $phone; + } + + /** + * Get the notification's delivery channels. + * + * @param mixed $notifiable + * @return array + */ + public function via($notifiable) + { + return ['mail']; + } + + /** + * Get the mail representation of the notification. + * + * @param mixed $notifiable + * @return \Illuminate\Notifications\Messages\MailMessage + */ + public function toMail($notifiable) + { + $url = route('auth.show'); + + return (new MailMessage) + ->subject("{$this->full_name} has requested to be added to your company on " . config('app.name')) + ->line('Please login to ' . config('app.name') . ' to approve/reject the user') + ->action('Sign In', $url) + ->line('Thank you for using our application!'); + } + + /** + * Get the array representation of the notification. + * + * @param mixed $notifiable + * @return array + */ + public function toArray($notifiable) + { + return [ + // + ]; + } +} diff --git a/app/Policies/CompanyPolicy.php b/app/Policies/CompanyPolicy.php index e3bbd3f5..8b8b6ddd 100755 --- a/app/Policies/CompanyPolicy.php +++ b/app/Policies/CompanyPolicy.php @@ -5,6 +5,8 @@ use App\Models\User; use App\Models\Company; use Illuminate\Auth\Access\HandlesAuthorization; +use Illuminate\Support\Facades\Route; +use Log; class CompanyPolicy { @@ -67,4 +69,24 @@ public function delete(User $user, Company $company) { return $company->isOwner($user); } + + /** + * Determine whether the user owns the company. + * + * @param \App\Models\User $user + * @return mixed + */ + public function owner(User $user) + { + $company = $user->company; + if ($company) + { + return $company->isOwner($user); + } + else + { + //Check if the current route name matches company.edit or company.update and return true if it is + return (Route::currentRouteName() === 'company.edit' || Route::currentRouteName() === 'company.update'); + } + } } diff --git a/app/Policies/CompanyUserRequestPolicy.php b/app/Policies/CompanyUserRequestPolicy.php new file mode 100755 index 00000000..6ce2a221 --- /dev/null +++ b/app/Policies/CompanyUserRequestPolicy.php @@ -0,0 +1,76 @@ +isSuperAdmin()) { + return true; + } + } + + /** + * Determine whether the user can view the companyUserRequest. + * + * @param \App\Models\User $user + * @param \App\Models\CompanyUserRequest $companyUserRequest + * @return mixed + */ + public function view(User $user, CompanyUserRequest $companyUserRequest) + { + return $user->isOfCompanyUserRequest($companyUserRequest->id); + } + + /** + * Determine whether the user can create companies. + * + * @param \App\Models\User $user + * @return mixed + */ + public function create(User $user) + { + // + } + + /** + * Determine whether the user can update the companyUserRequest. + * + * @param \App\Models\User $user + * @param \App\Models\CompanyUserRequest $companyUserRequest + * @return mixed + */ + public function update(User $user, CompanyUserRequest $companyUserRequest) + { + return $companyUserRequest->isOwner($user); + } + + /** + * Determine whether the user can delete the companyUserRequest. + * + * @param \App\Models\User $user + * @param \App\Models\CompanyUserRequest $companyUserRequest + * @return mixed + */ + public function delete(User $user, CompanyUserRequest $companyUserRequest) + { + return $companyUserRequest->isOwner($user); + } +} diff --git a/app/Providers/RouteServiceProvider.php b/app/Providers/RouteServiceProvider.php index 9b3e8566..6cda2d40 100755 --- a/app/Providers/RouteServiceProvider.php +++ b/app/Providers/RouteServiceProvider.php @@ -25,6 +25,7 @@ public function boot() { Route::model('client', 'App\Models\Client'); Route::model('company', 'App\Models\Company'); + Route::model('companyuserrequest', 'App\Models\CompanyUserRequest'); Route::model('invoice', 'App\Models\Invoice'); Route::model('invoiceitem', 'App\Models\InvoiceItem'); Route::model('oldinvoice', 'App\Models\OldInvoice'); @@ -41,6 +42,7 @@ public function boot() Route::pattern('token', '([A-Za-z0-9]+)'); Route::pattern('client', '([A-Za-z0-9]+)'); Route::pattern('company', '([A-Za-z0-9]+)'); + Route::pattern('companyuserrequest', '([A-Za-z0-9]+)'); Route::pattern('invoice', '([A-Za-z0-9]+)'); Route::pattern('invoiceitem', '([A-Za-z0-9]+)'); Route::pattern('oldinvoice', '([A-Za-z0-9]+)'); diff --git a/database/factories/ClientFactory.php b/database/factories/ClientFactory.php new file mode 100755 index 00000000..98caa0db --- /dev/null +++ b/database/factories/ClientFactory.php @@ -0,0 +1,28 @@ +define(\App\Models\Client::class, function (Faker $faker) { + + return [ + 'companyname' => $faker->company, + 'phone' => '+65' . $faker->randomNumber(8), + 'block' => $faker->buildingNumber, + 'street' => $faker->streetName, + 'unitnumber' => $faker->buildingNumber, + 'postalcode' => $faker->postcode, + 'country' => $faker->country, + 'nickname' => $faker->name, + 'crn' => $faker->ean8, + 'website' => $faker->url, + 'contactsalutation' => $faker->title, + 'contactfirstname' => $faker->firstName, + 'contactlastname' => $faker->lastName, + 'contactgender' => 'male', + 'contactemail' => $faker->unique()->companyEmail, + 'contactphone' => '+65' . $faker->randomNumber(8), + 'company_id' => function () { + return factory(\App\Models\Company::class)->create()->id; + } + ]; +}); diff --git a/database/factories/CompanyAddressFactory.php b/database/factories/CompanyAddressFactory.php new file mode 100755 index 00000000..5e0655a1 --- /dev/null +++ b/database/factories/CompanyAddressFactory.php @@ -0,0 +1,16 @@ +define(\App\Models\CompanyAddress::class, function (Faker $faker) { + return [ + 'block' => $faker->buildingNumber, + 'street' => $faker->streetName, + 'unitnumber' => $faker->buildingNumber, + 'postalcode' => $faker->postcode, + 'buildingtype' => $faker->numberBetween($min = 1, $max = 2), + 'company_id' => function () { + return factory(\App\Models\Company::class)->create()->id; + } + ]; +}); diff --git a/database/factories/CompanyFactory.php b/database/factories/CompanyFactory.php new file mode 100755 index 00000000..8f714cf1 --- /dev/null +++ b/database/factories/CompanyFactory.php @@ -0,0 +1,18 @@ +define(\App\Models\Company::class, function (Faker $faker) { + return [ + 'name' => $faker->company, + 'invoice_index' => $faker->randomDigit, + 'quote_index' => $faker->randomDigit, + 'slug' => $faker->slug, + 'crn' => $faker->ean8, + 'phone' => '+65' . $faker->randomNumber(8), + 'email' => $faker->unique()->companyEmail, + 'user_id' => function() { + return factory(\App\Models\User::class)->create()->id; + } + ]; +}); diff --git a/database/factories/CompanySettingsFactory.php b/database/factories/CompanySettingsFactory.php new file mode 100755 index 00000000..2c8fff49 --- /dev/null +++ b/database/factories/CompanySettingsFactory.php @@ -0,0 +1,16 @@ +define(\App\Models\CompanySettings::class, function (Faker $faker) { + return [ + 'invoice_prefix' => $faker->domainWord, + 'quote_prefix' => $faker->domainWord, + 'invoice_conditions' => $faker->realText($maxNbChars = 200, $indexSize = 2), + 'quote_conditions' => $faker->realText($maxNbChars = 200, $indexSize = 2), + 'tax' => $faker->numberBetween($min = 1, $max = 100), + 'company_id' => function () { + return factory(\App\Models\Company::class)->create()->id; + } + ]; +}); diff --git a/database/factories/InvoiceFactory.php b/database/factories/InvoiceFactory.php new file mode 100755 index 00000000..7ee04cae --- /dev/null +++ b/database/factories/InvoiceFactory.php @@ -0,0 +1,22 @@ +define(\App\Models\Invoice::class, function (Faker $faker) { + return [ + 'nice_invoice_id' => $faker->slug, + 'date' => $faker->dateTime, + 'duedate' => $faker->dateTime, + 'netdays' => $faker->numberBetween($min = 1, $max = 60), + 'total' => $faker->randomFloat($nbMaxDecimals = NULL, $min = 0, $max = NULL), + 'share_token' => $faker->uuid, + 'status' => $faker->numberBetween($min = 1, $max = 7), + 'archived' => $faker->boolean, + 'client_id' => function () { + return factory(\App\Models\Client::class)->create()->id; + }, + 'company_id' => function () { + return factory(\App\Models\Company::class)->create()->id; + } + ]; +}); \ No newline at end of file diff --git a/database/factories/InvoiceItemFactory.php b/database/factories/InvoiceItemFactory.php new file mode 100755 index 00000000..9c8d22db --- /dev/null +++ b/database/factories/InvoiceItemFactory.php @@ -0,0 +1,15 @@ +define(\App\Models\InvoiceItem::class, function (Faker $faker) { + return [ + 'name' => $faker->realText($maxNbChars = 20, $indexSize = 1), + 'quantity' => $faker->numberBetween($min = 1, $max = 1000), + 'price' => $faker->randomFloat($nbMaxDecimals = NULL, $min = 0, $max = NULL), + 'description' => $faker->randomHtml(2,3), + 'invoice_id' => function () { + return factory(\App\Models\Invoice::class)->create()->id; + } + ]; +}); diff --git a/database/factories/ItemTemplateFactory.php b/database/factories/ItemTemplateFactory.php new file mode 100755 index 00000000..e59338db --- /dev/null +++ b/database/factories/ItemTemplateFactory.php @@ -0,0 +1,15 @@ +define(\App\Models\ItemTemplate::class, function (Faker $faker) { + return [ + 'name' => $faker->realText($maxNbChars = 20, $indexSize = 1), + 'quantity' => $faker->numberBetween($min = 1, $max = 1000), + 'price' => $faker->randomFloat($nbMaxDecimals = NULL, $min = 0, $max = NULL), + 'description' => $faker->randomHtml(2,3), + 'company_id' => function () { + return factory(\App\Models\Company::class)->create()->id; + } + ]; +}); diff --git a/database/factories/QuoteFactory.php b/database/factories/QuoteFactory.php new file mode 100755 index 00000000..d70b0192 --- /dev/null +++ b/database/factories/QuoteFactory.php @@ -0,0 +1,22 @@ +define(\App\Models\Quote::class, function (Faker $faker) { + return [ + 'nice_quote_id' => $faker->slug, + 'date' => $faker->dateTime, + 'duedate' => $faker->dateTime, + 'netdays' => $faker->numberBetween($min = 1, $max = 60), + 'total' => $faker->randomFloat($nbMaxDecimals = NULL, $min = 0, $max = NULL), + 'share_token' => $faker->uuid, + 'status' => $faker->numberBetween($min = 1, $max = 7), + 'archived' => $faker->boolean, + 'client_id' => function () { + return factory(\App\Models\Client::class)->create()->id; + }, + 'company_id' => function () { + return factory(\App\Models\Company::class)->create()->id; + } + ]; +}); diff --git a/database/factories/QuoteItemFactory.php b/database/factories/QuoteItemFactory.php new file mode 100755 index 00000000..215e08c6 --- /dev/null +++ b/database/factories/QuoteItemFactory.php @@ -0,0 +1,15 @@ +define(\App\Models\QuoteItem::class, function (Faker $faker) { + return [ + 'name' => $faker->realText($maxNbChars = 20, $indexSize = 1), + 'quantity' => $faker->numberBetween($min = 1, $max = 1000), + 'price' => $faker->randomFloat($nbMaxDecimals = NULL, $min = 0, $max = NULL), + 'description' => $faker->randomHtml(2,3), + 'quote_id' => function () { + return factory(\App\Models\Quote::class)->create()->id; + } + ]; +}); diff --git a/database/factories/UserFactory.php b/database/factories/UserFactory.php index 1177a12a..6dc02dd7 100755 --- a/database/factories/UserFactory.php +++ b/database/factories/UserFactory.php @@ -13,7 +13,7 @@ | */ -$factory->define(App\Models\User::class, function (Faker $faker) { +$factory->define(\App\Models\User::class, function (Faker $faker) { static $password; return [ diff --git a/database/migrations/2018_10_30_221048_add_status_to_users_table.php b/database/migrations/2018_10_30_221048_add_status_to_users_table.php new file mode 100755 index 00000000..57b076e3 --- /dev/null +++ b/database/migrations/2018_10_30_221048_add_status_to_users_table.php @@ -0,0 +1,32 @@ +integer('status')->after('gender'); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('users', function (Blueprint $table) { + $table->dropColumn('status'); + }); + } +} diff --git a/database/migrations/2018_10_31_014426_add_domain_to_companies_table.php b/database/migrations/2018_10_31_014426_add_domain_to_companies_table.php new file mode 100755 index 00000000..4565ef4a --- /dev/null +++ b/database/migrations/2018_10_31_014426_add_domain_to_companies_table.php @@ -0,0 +1,32 @@ +string('domain_name')->after('slug'); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('companies', function (Blueprint $table) { + $table->string('domain_name')->after('slug'); + }); + } +} diff --git a/database/migrations/2018_10_31_015426_update_crn_not_nullable_to_companies_table.php b/database/migrations/2018_10_31_015426_update_crn_not_nullable_to_companies_table.php new file mode 100755 index 00000000..619339c9 --- /dev/null +++ b/database/migrations/2018_10_31_015426_update_crn_not_nullable_to_companies_table.php @@ -0,0 +1,32 @@ +string('crn')->nullable(false)->change(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('companies', function (Blueprint $table) { + $table->string('crn')->nullable()->change(); + }); + } +} diff --git a/database/migrations/2018_10_31_170650_change_domain_name_nullable_to_companies_table.php b/database/migrations/2018_10_31_170650_change_domain_name_nullable_to_companies_table.php new file mode 100644 index 00000000..d984cc74 --- /dev/null +++ b/database/migrations/2018_10_31_170650_change_domain_name_nullable_to_companies_table.php @@ -0,0 +1,32 @@ +string('domain_name')->nullable()->change(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('companies', function (Blueprint $table) { + $table->string('domain_name')->nullable(false)->change(); + }); + } +} diff --git a/database/migrations/2018_10_31_221557_create_company_user_requests_table.php b/database/migrations/2018_10_31_221557_create_company_user_requests_table.php new file mode 100755 index 00000000..b7fc4f48 --- /dev/null +++ b/database/migrations/2018_10_31_221557_create_company_user_requests_table.php @@ -0,0 +1,41 @@ +increments('id'); + $table->string('full_name'); + $table->string('email')->unique(); + $table->string('phone'); + $table->string('token'); + $table->integer('status'); + $table->integer('company_id')->unsigned(); + $table->foreign('company_id') + ->references('id')->on('companies') + ->onDelete('cascade'); + $table->timestamps(); + $table->softDeletes(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('company_user_requests'); + } +} diff --git a/database/migrations/2018_10_31_221953_change_domain_name_unique_to_companies_table.php b/database/migrations/2018_10_31_221953_change_domain_name_unique_to_companies_table.php new file mode 100755 index 00000000..8b82b08d --- /dev/null +++ b/database/migrations/2018_10_31_221953_change_domain_name_unique_to_companies_table.php @@ -0,0 +1,32 @@ +string('domain_name')->unique()->change(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('companies', function (Blueprint $table) { + $table->dropUnique('domain_name'); + }); + } +} diff --git a/public/assets/css/style.css b/public/assets/css/style.css index 42d3d42c..7184582c 100755 --- a/public/assets/css/style.css +++ b/public/assets/css/style.css @@ -112,6 +112,10 @@ mark { font-weight: normal; } +.text-bold { + font-weight: bold; +} + .mbth5 { margin-top: 5px; margin-bottom: 5px; @@ -350,6 +354,10 @@ mark { height: 22px; } +.alt-badge.mini-padding { + padding: 2px 4px; +} + :root:root .card-panel .card-input { border: 0; margin: 0; diff --git a/public/mix-manifest.json b/public/mix-manifest.json index 61b19d5e..4e3c9265 100755 --- a/public/mix-manifest.json +++ b/public/mix-manifest.json @@ -2,7 +2,7 @@ "/assets/js/app.js": "/assets/js/app.js?id=627a0c22daaa3692a223", "/assets/css/selectize.css": "/assets/css/selectize.css?id=567e90bc0f0fb17a6074", "/assets/css/core.css": "/assets/css/core.css?id=2d6ffdc9e1192a5830ca", - "/assets/css/style.css": "/assets/css/style.css?id=3baee358d034148be7b1", + "/assets/css/style.css": "/assets/css/style.css?id=5b8029adbc3cd2e9ce49", "/assets/css/materialize.css": "/assets/css/materialize.css?id=8e7ce7662a503970babd", "/assets/css/materialdesignicons.css": "/assets/css/materialdesignicons.css?id=a1a2666c60552debfaa8", "/assets/css/trumbowyg.css": "/assets/css/trumbowyg.css?id=19e35aa42e06b569ab56", diff --git a/resources/assets/sass/style.scss b/resources/assets/sass/style.scss index 7493a922..84dcfc74 100755 --- a/resources/assets/sass/style.scss +++ b/resources/assets/sass/style.scss @@ -114,6 +114,10 @@ mark { font-weight: normal; } +.text-bold { + font-weight: bold; +} + .mbth5 { margin-top: 5px; margin-bottom: 5px; @@ -324,6 +328,10 @@ mark { height: 22px; } +.alt-badge.mini-padding { + padding: 2px 4px; +} + :root:root .card-panel .card-input { border: 0; margin: 0; diff --git a/resources/views/pages/company/address/edit.blade.php b/resources/views/pages/company/address/edit.blade.php index e01fead1..575b56d4 100755 --- a/resources/views/pages/company/address/edit.blade.php +++ b/resources/views/pages/company/address/edit.blade.php @@ -15,7 +15,7 @@
- @include("partials/sidenav") + @include("partials/sidenav-company")
@@ -90,7 +90,6 @@ M.toast({ html: "You need to fill in your company information first", displayLength: "poowf", classes: "error"}); @endif - $('#edit-address').parsley({ successClass: 'valid', errorClass: 'invalid', diff --git a/resources/views/pages/company/check.blade.php b/resources/views/pages/company/check.blade.php new file mode 100755 index 00000000..1f3006d3 --- /dev/null +++ b/resources/views/pages/company/check.blade.php @@ -0,0 +1,86 @@ +@extends("layouts/default") + +@section("head") + {{ config('app.name') }} + + + +@stop + +@section("content") +
+
+
+

Check for your company

+ +
+

Key in your work email:

+
+
+ + + +
+
+
+
+
+ {{ csrf_field() }} + +
+
+ +
+
+
+@stop + +@section("scripts") + + + +@stop \ No newline at end of file diff --git a/resources/views/pages/company/create.blade.php b/resources/views/pages/company/create.blade.php index 1fe81965..eddd0307 100755 --- a/resources/views/pages/company/create.blade.php +++ b/resources/views/pages/company/create.blade.php @@ -32,6 +32,13 @@
+
+
+ + + +
+
diff --git a/resources/views/pages/company/edit.blade.php b/resources/views/pages/company/edit.blade.php index 7007636d..7ae4a88e 100755 --- a/resources/views/pages/company/edit.blade.php +++ b/resources/views/pages/company/edit.blade.php @@ -66,12 +66,12 @@
-

Company

+

Details

- @include("partials/sidenav") + @include("partials/sidenav-company")
@@ -110,6 +110,13 @@
+
+
+ + + +
+
diff --git a/resources/views/pages/company/owner/edit.blade.php b/resources/views/pages/company/owner/edit.blade.php new file mode 100755 index 00000000..26428104 --- /dev/null +++ b/resources/views/pages/company/owner/edit.blade.php @@ -0,0 +1,176 @@ +@extends("layouts/default") + +@section("head") + {{ config('app.name') }} + +@stop + +@section("content") +
+
+
+

Owner

+
+
+
+
+ @include("partials/sidenav-company") +
+
+ @if($users->isNotEmpty()) +
+

Current Owner

+
+
Username
+
{{ $owner->username }}
+
Email
+
{{ $owner->email ?? '-' }}
+
Full Name
+
{{ $owner->full_name ?? '-' }}
+
Phone
+
{{ $owner->phone ?? '-' }}
+
+
+ @can('update', $owner->company) + +
+
+ + + +
+
+
+
+

New Company Owner

+
+
Username
+
{{ $owner->username }} to
+
Email
+
{{ $owner->email ?? '-' }} to
+
Full Name
+
{{ $owner->full_name ?? '-' }} to
+
Phone
+
{{ $owner->phone ?? '-' }} to
+
+
+
+
+
+ {{ method_field('PATCH') }} + {{ csrf_field() }} + +
+
+ + @endcan + @else +
+ sentiment_dissatisfied +

There's nothing here

+
+ @endif +
+
+
+@stop + +@section("scripts") + @if($users->isNotEmpty()) + @can('update', $owner->company) + + @endcan + @endif +@stop \ No newline at end of file diff --git a/resources/views/pages/company/requests/create.blade.php b/resources/views/pages/company/requests/create.blade.php new file mode 100755 index 00000000..2aebfdd5 --- /dev/null +++ b/resources/views/pages/company/requests/create.blade.php @@ -0,0 +1,134 @@ +@extends("layouts.default") + +@section("head") + {{ config('app.name') }} + + + +@stop + +@section("content") +
+
+
+

Request for an account

+
+
+
+
+
+
+
+
+ + + +
+
+
+
+ + + +
+
+
+
+ + + +
+
+
+
+
+ {{ csrf_field() }} + +
+
+
+
+
+
+@stop + +@section("scripts") + + + +@stop \ No newline at end of file diff --git a/resources/views/pages/company/requests/index.blade.php b/resources/views/pages/company/requests/index.blade.php new file mode 100755 index 00000000..a8f61ec9 --- /dev/null +++ b/resources/views/pages/company/requests/index.blade.php @@ -0,0 +1,90 @@ +@extends("layouts/default") + +@section("head") + {{ config('app.name') }} + +@stop + +@section("content") +
+
+
+

Requests

+
+
+
+
+
+
+ @include("partials/sidenav-company") +
+
+
+ @if($requests->isNotEmpty()) +
+ + + + + + + + @can('owner', \App\Models\Company::class) + + @endcan + + + + + @foreach($requests as $key => $request) + + + + + + @can('owner', \App\Models\Company::class) + + @endcan + + + @endforeach + +
Full NameEmailPhoneStatusAction
{{ $request->full_name }}{{ $request->email }}{{ $request->phone }}{{ $request->statusText() }} +
+ {{ csrf_field() }} + +
+
+ {{ csrf_field() }} + +
+
+
+
+ {!! $requests->appends(Request::except("page"))->links('partials.pagination') !!} +
+
+
+ @else +
+ sentiment_dissatisfied +

There's nothing here

+
+ @endif +
+
+
+
+@stop + +@section("scripts") + +@stop \ No newline at end of file diff --git a/resources/views/pages/company/settings/edit.blade.php b/resources/views/pages/company/settings/edit.blade.php index db06b0ea..1c621983 100755 --- a/resources/views/pages/company/settings/edit.blade.php +++ b/resources/views/pages/company/settings/edit.blade.php @@ -15,42 +15,42 @@
- @include("partials/sidenav") + @include("partials/sidenav-company")
- +
- +
- +
- +
- +
@@ -60,7 +60,7 @@
{{ method_field('PATCH') }} {{ csrf_field() }} - +
@@ -73,6 +73,11 @@ +@stop \ No newline at end of file diff --git a/resources/views/pages/company/users/create.blade.php b/resources/views/pages/company/users/create.blade.php new file mode 100755 index 00000000..582930e3 --- /dev/null +++ b/resources/views/pages/company/users/create.blade.php @@ -0,0 +1,164 @@ +@extends("layouts/default") + +@section("head") + {{ config('app.name') }} + + +@stop + +@section("content") +
+
+
+

Add User

+
+
+
+
+ @include("partials/sidenav-company") +
+
+
+
+
+

Company: {{ $company->name }}

+
+
+
+ + + +
+
+
+
+ + + +
+
+
+
+ + + +
+
+
+
+ + + +
+
+
+
+ +

+ +

+

+ +

+ +
+
+
+
+
+ {{ csrf_field() }} + +
+
+
+
+
+
+@stop + +@section("scripts") + + + +@stop \ No newline at end of file diff --git a/resources/views/pages/company/users/edit.blade.php b/resources/views/pages/company/users/edit.blade.php new file mode 100755 index 00000000..35b67efc --- /dev/null +++ b/resources/views/pages/company/users/edit.blade.php @@ -0,0 +1,176 @@ +@extends("layouts/default") + +@section("head") + {{ config('app.name') }} + + +@stop + +@section("content") +
+
+
+

Edit User

+
+
+
+
+ @include("partials/sidenav-company") +
+
+
+
+
+
+ + + +
+
+
+
+ + + +
+
+
+
+ + + +
+
+
+
+ + + +
+
+
+
+ + + +
+
+
+
+ + + +
+
+
+
+ +

+ +

+

+ +

+ +
+
+
+
+
+ {{ method_field('PATCH') }} + {{ csrf_field() }} + +
+
+
+
+
+
+@stop + +@section("scripts") + + + +@stop \ No newline at end of file diff --git a/resources/views/pages/company/users/index.blade.php b/resources/views/pages/company/users/index.blade.php new file mode 100755 index 00000000..342f9354 --- /dev/null +++ b/resources/views/pages/company/users/index.blade.php @@ -0,0 +1,115 @@ +@extends("layouts/default") + +@section("head") + {{ config('app.name') }} + +@stop + +@section("content") +
+
+
+

Users

+
+
+ @if($users->isNotEmpty()) + @can('owner', \App\Models\Company::class) + Add User + @endcan + @endif +
+
+
+
+ @include("partials/sidenav-company") +
+
+
+ @if($users->isNotEmpty()) +
+ + + + + + + + + @can('owner', \App\Models\Company::class) + + @endcan + + + + + @foreach($users as $key => $user) + + + + + + + @can('owner', \App\Models\Company::class) + + @endcan + + + @endforeach + +
UsernameEmailFull NamePhoneStatusAction
{{ $user->username }} @if($user->owns($company))Owner + @endif{{ $user->email }}{{ $user->full_name }}{{ $user->phone }}{{ $user->statusText() }} + mode_edit + @if($user->id != auth()->user()->id) + remove_circle + @endif +
+
+
+ {!! $users->appends(Request::except("page"))->links('partials.pagination') !!} +
+
+
+ @else +
+ sentiment_dissatisfied +

There's nothing here

+
+ @endif +
+
+
+
+ +@stop + +@section("scripts") + +@stop \ No newline at end of file diff --git a/resources/views/pages/payment/noinvoices.blade.php b/resources/views/pages/payment/noinvoices.blade.php index 3dd2ffad..025c3b49 100755 --- a/resources/views/pages/payment/noinvoices.blade.php +++ b/resources/views/pages/payment/noinvoices.blade.php @@ -14,7 +14,7 @@

You have no invoices created

You need at least one invoice to create a payment
Maybe you should create a invoice first?
- +
diff --git a/resources/views/pages/start.blade.php b/resources/views/pages/start.blade.php new file mode 100755 index 00000000..239b8e9f --- /dev/null +++ b/resources/views/pages/start.blade.php @@ -0,0 +1,59 @@ +@extends("layouts.default") + +@section("head") + {{ config('app.name') }} + + + +@stop + +@section("content") +
+
+
+

Start Here

+
+
+ +
+@stop + +@section("scripts") + + + +@stop \ No newline at end of file diff --git a/resources/views/pages/user/create.blade.php b/resources/views/pages/user/create.blade.php index 6d111c5f..709cb477 100755 --- a/resources/views/pages/user/create.blade.php +++ b/resources/views/pages/user/create.blade.php @@ -83,7 +83,7 @@
{{ csrf_field() }} - +
diff --git a/resources/views/pages/user/edit.blade.php b/resources/views/pages/user/edit.blade.php index f00fc6a2..8f011cc6 100755 --- a/resources/views/pages/user/edit.blade.php +++ b/resources/views/pages/user/edit.blade.php @@ -11,12 +11,12 @@
-

Profile

+

User

- @include("partials/sidenav") + @include("partials/sidenav-user")
diff --git a/resources/views/partials/header.blade.php b/resources/views/partials/header.blade.php index 51cca325..f46c5a63 100755 --- a/resources/views/partials/header.blade.php +++ b/resources/views/partials/header.blade.php @@ -20,9 +20,13 @@
  • Payments
  • My Accountarrow_drop_down
  • @else
  • Sign In
  • -
  • Sign Up
  • +
  • Start Here
  • @endif
    diff --git a/resources/views/partials/sidenav-company.blade.php b/resources/views/partials/sidenav-company.blade.php new file mode 100755 index 00000000..e90bd105 --- /dev/null +++ b/resources/views/partials/sidenav-company.blade.php @@ -0,0 +1,18 @@ +@section('sidenav-company') +
    + @if(auth()->user()->company) + Company + @can('owner', \App\Models\Company::class) + Details + Settings + Address + Owner + Users + Requests + @endcan + @else + Details + @endif + {{--Data Migration--}} +
    +@show \ No newline at end of file diff --git a/resources/views/partials/sidenav-user.blade.php b/resources/views/partials/sidenav-user.blade.php new file mode 100755 index 00000000..f47f993b --- /dev/null +++ b/resources/views/partials/sidenav-user.blade.php @@ -0,0 +1,6 @@ +@section('sidenav-user') +
    + User + {{--Data Migration--}} +
    +@show \ No newline at end of file diff --git a/resources/views/partials/sidenav.blade.php b/resources/views/partials/sidenav.blade.php deleted file mode 100755 index 1a6f493e..00000000 --- a/resources/views/partials/sidenav.blade.php +++ /dev/null @@ -1,9 +0,0 @@ -@section('sidenav') - -@show \ No newline at end of file diff --git a/routes/web.php b/routes/web.php index 334aff55..6960df61 100755 --- a/routes/web.php +++ b/routes/web.php @@ -24,6 +24,8 @@ Route::get('/reset/{token}', 'ResetPasswordController@show')->name('reset'); Route::post('/reset/{token}', 'ResetPasswordController@process')->name('reset'); + Route::get('/start', 'MainController@start')->name('start'); + /* User */ Route::get('/user/create', 'UserController@create')->name('user.create'); Route::post('/user/create', 'UserController@store')->name('user.store'); @@ -31,30 +33,53 @@ /* Company */ Route::get('/company/create', 'CompanyController@create')->name('company.create'); Route::post('/company/create', 'CompanyController@store')->name('company.store'); + Route::get('/company/check', 'CompanyController@show_check')->name('company.show_check'); + Route::post('/company/check', 'CompanyController@check')->name('company.check'); + + Route::get('/company/requests/create', 'CompanyUserRequestController@create')->name('company.requests.create'); + Route::post('/company/requests/create', 'CompanyUserRequestController@store')->name('company.requests.store'); + }); Route::group(['middleware' => ['auth']], function() { Route::post('/signout', 'AuthController@destroy')->name('auth.destroy'); - Route::get('/errors/nocompany', 'MainController@nocompany')->name('nocompany'); - Route::get('/dashboard', 'MainController@dashboard')->name('dashboard'); /* User */ Route::get('/user/edit', 'UserController@edit')->name('user.edit'); Route::patch('/user/edit', 'UserController@update')->name('user.update'); /* Company */ - Route::get('/company/edit', 'CompanyController@edit')->name('company.edit'); - Route::patch('/company/edit', 'CompanyController@update')->name('company.update'); - - /* CompanyAddress */ - Route::get('/company/address/edit', 'CompanyAddressController@edit')->name('company.address.edit'); - Route::patch('/company/address/edit', 'CompanyAddressController@update')->name('company.address.update'); - - Route::get('/company/settings/edit', 'CompanySettingsController@edit')->name('company.settings.edit'); - Route::patch('/company/settings/edit', 'CompanySettingsController@update')->name('company.settings.update'); + Route::get('/company/show', 'CompanyController@show')->name('company.show'); + Route::get('/company/edit', 'CompanyController@edit')->name('company.edit')->middleware('can:owner,App\Models\Company'); + Route::patch('/company/edit', 'CompanyController@update')->name('company.update')->middleware('can:owner,App\Models\Company'); Route::group(['middleware' => ['hascompany']], function() { + Route::get('/dashboard', 'MainController@dashboard')->name('dashboard'); + + //TODO:Middleware check to ensure that the user logged in is an owner and that the user retrieved is a member of the company + Route::get('/user/{user}/retrieve', 'UserController@retrieve')->name('user.retrieve'); + /* Company */ + Route::get('/company/owner/edit', 'CompanyController@edit_owner')->name('company.owner.edit')->middleware('can:owner,App\Models\Company'); + Route::patch('/company/owner/edit', 'CompanyController@update_owner')->name('company.owner.update')->middleware('can:owner,App\Models\Company'); + Route::get('/company/users', 'CompanyController@index_users')->name('company.users.index')->middleware('can:owner,App\Models\Company'); + Route::get('/company/users/create', 'CompanyController@create_users')->name('company.users.create')->middleware('can:owner,App\Models\Company'); + Route::post('/company/users/create', 'CompanyController@store_users')->name('company.users.store')->middleware('can:owner,App\Models\Company'); + Route::get('/company/users/{user}/edit', 'CompanyController@edit_users')->name('company.users.edit')->middleware('can:owner,App\Models\Company'); + Route::patch('/company/users/{user}/edit', 'CompanyController@update_users')->name('company.users.update')->middleware('can:owner,App\Models\Company'); + Route::delete('/company/users/{user}/destroy', 'CompanyController@destroy_users')->name('company.users.destroy')->middleware('can:owner,App\Models\Company'); + + /* CompanyAddress */ + Route::get('/company/address/edit', 'CompanyAddressController@edit')->name('company.address.edit')->middleware('can:owner,App\Models\Company'); + Route::patch('/company/address/edit', 'CompanyAddressController@update')->name('company.address.update')->middleware('can:owner,App\Models\Company'); + + /* CompanySettings */ + Route::get('/company/settings/edit', 'CompanySettingsController@edit')->name('company.settings.edit')->middleware('can:owner,App\Models\Company'); + Route::patch('/company/settings/edit', 'CompanySettingsController@update')->name('company.settings.update')->middleware('can:owner,App\Models\Company'); + + Route::get('/company/requests', 'CompanyUserRequestController@index')->name('company.requests.index'); + Route::post('/company/requests/{companyuserrequest}/approve', 'CompanyUserRequestController@approve')->name('company.requests.approve'); + Route::post('/company/requests/{companyuserrequest}/reject', 'CompanyUserRequestController@reject')->name('company.requests.reject'); /* Migration */ Route::get('/migration/', 'DataMigrationController@create')->name('migration.create'); diff --git a/tests/Feature/ClientTest.php b/tests/Feature/ClientTest.php new file mode 100755 index 00000000..11fd97c0 --- /dev/null +++ b/tests/Feature/ClientTest.php @@ -0,0 +1,52 @@ +create(); + + Client::unguard(); + + $client = Client::create([ + 'companyname' => 'Poowf Labs', + 'phone' => '+6581234567', + 'block' => '123', + 'street' => '123 Street Name', + 'unitnumber' => '00-00', + 'postalcode' => '123456', + 'country' => 'Singapore', + 'nickname' => 'Poowf the Bunny', + 'crn' => '201810000A', + 'website' => 'http://poowf.com', + 'contactsalutation' => 'Ms.', + 'contactfirstname' => 'Poowf', + 'contactlastname' => 'Bunny', + 'contactgender' => 'female', + 'contactemail' => 'bunny@poowf.com', + 'contactphone' => '+6579328669', + 'company_id' => $company->id + ]); + + Client::unguard(); + + $this->assertEquals($client->company->name, $company->name); + $this->assertEquals('Poowf Labs', $client->companyname); + } + +} diff --git a/tests/Feature/CompanyAddressTest.php b/tests/Feature/CompanyAddressTest.php new file mode 100755 index 00000000..402c0810 --- /dev/null +++ b/tests/Feature/CompanyAddressTest.php @@ -0,0 +1,39 @@ +create(); + + CompanyAddress::unguard(); + + $companyaddress = CompanyAddress::create([ + 'block' => '123', + 'street' => '123 Street Name', + 'unitnumber' => '00-00', + 'postalcode' => '123456', + 'buildingtype' => '1', + 'company_id' => $company->id + ]); + + CompanyAddress::reguard(); + + $this->assertEquals($companyaddress->company->name, $company->name); + $this->assertEquals('123 Street Name', $companyaddress->street); + } +} diff --git a/tests/Feature/CompanySettingsTest.php b/tests/Feature/CompanySettingsTest.php new file mode 100755 index 00000000..7f3bdf46 --- /dev/null +++ b/tests/Feature/CompanySettingsTest.php @@ -0,0 +1,39 @@ +create(); + + CompanySettings::unguard(); + + $companysettings = CompanySettings::create([ + 'invoice_prefix' => 'PWF', + 'quote_prefix' => 'PWFQ', + 'invoice_conditions' => 'asdfasfdasfasfasdf asdfasdfasdf asfdassafas

    asdfasdfasdfas

    ', + 'quote_conditions' => 'asdfasfdasfasfasdf asdfasdfasdf asfdassafas

    asdfasdfasdfas

    ', + 'tax' => '20', + 'company_id' => $company->id + ]); + + CompanySettings::reguard(); + + $this->assertEquals($companysettings->company->name, $company->name); + $this->assertEquals('asdfasfdasfasfasdf asdfasdfasdf asfdassafas

    asdfasdfasdfas

    ', $companysettings->invoice_conditions); + } +} diff --git a/tests/Feature/CompanyTest.php b/tests/Feature/CompanyTest.php new file mode 100755 index 00000000..2ee6511d --- /dev/null +++ b/tests/Feature/CompanyTest.php @@ -0,0 +1,40 @@ +create(); + + Company::unguard(); + + $company = Company::create([ + 'name' => 'Poowf Labs', + 'invoice_index' => '2342', + 'quote_index' => '12313', + 'crn' => '201810000A', + 'phone' => '+6579328669', + 'email' => 'bunny@poowf.com', + 'user_id' => $user->id + ]); + + Company::reguard(); + + $this->assertEquals($company->owner->name, $user->name); + $this->assertEquals('poowf-labs', $company->slug); + } +} diff --git a/tests/Feature/ExampleTest.php b/tests/Feature/ExampleTest.php index f31e495c..ce9db80a 100755 --- a/tests/Feature/ExampleTest.php +++ b/tests/Feature/ExampleTest.php @@ -16,6 +16,6 @@ public function testBasicTest() { $response = $this->get('/'); - $response->assertStatus(200); + $response->assertStatus(302); } } diff --git a/tests/Feature/InvoiceItemTest.php b/tests/Feature/InvoiceItemTest.php new file mode 100755 index 00000000..e858de7d --- /dev/null +++ b/tests/Feature/InvoiceItemTest.php @@ -0,0 +1,38 @@ +create(); + + InvoiceItem::unguard(); + + $invoiceitem = InvoiceItem::create([ + 'name' => 'This is an Invoice Item la', + 'quantity' => '250', + 'price' => '5.00', + 'description' => 'asfdasfasfasfsf

    asasdfasdfasfas

    ', + 'invoice_id' => $invoice->id + ]); + + InvoiceItem::reguard(); + + $this->assertEquals($invoiceitem->invoice->id, $invoice->id); + $this->assertEquals('asfdasfasfasfsf

    asasdfasdfasfas

    ', $invoiceitem->description); + } +} diff --git a/tests/Feature/InvoiceTest.php b/tests/Feature/InvoiceTest.php new file mode 100755 index 00000000..7b6331d7 --- /dev/null +++ b/tests/Feature/InvoiceTest.php @@ -0,0 +1,45 @@ +create(); + + Invoice::unguard(); + + $invoice = Invoice::create([ + 'nice_invoice_id' => 'PWF-000001', + 'date' => '2018-01-01 12:01:00', + 'duedate' => '2018-01-01 12:01:00', + 'netdays' => '20', + 'total' => '650.80', + 'share_token' => '7e57d004-2b97-0e7a-b45f-5387367791cd', + 'status' => '2', + 'archived' => '0', + 'client_id' => $client->id, + 'company_id' => $client->company->id + ]); + + Invoice::reguard(); + + $this->assertEquals($invoice->client->name, $client->name); + $this->assertEquals($invoice->client->company->name, $client->company->name); + $this->assertEquals('7e57d004-2b97-0e7a-b45f-5387367791cd', $invoice->share_token); + } + +} diff --git a/tests/Feature/ItemTemplateTest.php b/tests/Feature/ItemTemplateTest.php new file mode 100755 index 00000000..8ccd6d34 --- /dev/null +++ b/tests/Feature/ItemTemplateTest.php @@ -0,0 +1,38 @@ +create(); + + ItemTemplate::unguard(); + + $itemtemplate = ItemTemplate::create([ + 'name' => 'This is an Item Template la', + 'quantity' => '250', + 'price' => '5.00', + 'description' => 'asfdasfasfasfsf

    asasdfasdfasfas

    ', + 'company_id' => $company->id + ]); + + ItemTemplate::reguard(); + + $this->assertEquals($itemtemplate->company->id, $company->id); + $this->assertEquals('asfdasfasfasfsf

    asasdfasdfasfas

    ', $itemtemplate->description); + } +} diff --git a/tests/Feature/QuoteItemTest.php b/tests/Feature/QuoteItemTest.php new file mode 100755 index 00000000..dd11134e --- /dev/null +++ b/tests/Feature/QuoteItemTest.php @@ -0,0 +1,38 @@ +create(); + + QuoteItem::unguard(); + + $quoteitem = QuoteItem::create([ + 'name' => 'This is a Quote Item la', + 'quantity' => '250', + 'price' => '5.00', + 'description' => 'asfdasfasfasfsf

    asasdfasdfasfas

    ', + 'quote_id' => $quote->id + ]); + + QuoteItem::reguard(); + + $this->assertEquals($quoteitem->quote->id, $quote->id); + $this->assertEquals('asfdasfasfasfsf

    asasdfasdfasfas

    ', $quoteitem->description); + } +} diff --git a/tests/Feature/QuoteTest.php b/tests/Feature/QuoteTest.php new file mode 100755 index 00000000..69ae5bfd --- /dev/null +++ b/tests/Feature/QuoteTest.php @@ -0,0 +1,44 @@ +create(); + + Quote::unguard(); + + $quote = Quote::create([ + 'nice_quote_id' => 'PWFQ-000001', + 'date' => '2018-01-01 12:01:00', + 'duedate' => '2018-01-01 12:01:00', + 'netdays' => '20', + 'total' => '650.50', + 'share_token' => '7e57d004-2b97-0e7a-b45f-5387367791cd', + 'status' => '2', + 'archived' => '0', + 'client_id' => $client->id, + 'company_id' => $client->company->id + ]); + + Quote::reguard(); + + $this->assertEquals($quote->client->name, $client->name); + $this->assertEquals($quote->client->company->name, $client->company->name); + $this->assertEquals('7e57d004-2b97-0e7a-b45f-5387367791cd', $quote->share_token); + } +} diff --git a/tests/Feature/UserSignupTest.php b/tests/Feature/UserSignupTest.php deleted file mode 100755 index a80370bd..00000000 --- a/tests/Feature/UserSignupTest.php +++ /dev/null @@ -1,28 +0,0 @@ -visit('auth/register') - ->type('bob', 'name') - ->type('hello1@in.com', 'email') - ->type('hello1', 'password') - ->type('hello1', 'password_confirmation') - ->press('Register') - ->seePageIs('/'); - } -} diff --git a/tests/Feature/UserTest.php b/tests/Feature/UserTest.php new file mode 100755 index 00000000..93a1ee3a --- /dev/null +++ b/tests/Feature/UserTest.php @@ -0,0 +1,43 @@ +create(); + + User::unguard(); + + $user = User::create([ + 'full_name' => 'Poowf Bunny', + 'username' => 'poowf', + 'password' => 'secret', + 'email' => 'bunny@poowf.com', + 'phone' => '+6579328669', + 'gender' => 'female', + 'remember_token' => 'sadfaxsfie', + 'company_id' => $company->id + ]); + + User::reguard(); + + $this->assertEquals($user->company->name, $company->name); + $this->assertEquals('bunny@poowf.com', $user->email); + } + +}