Skip to content

Commit 562f645

Browse files
committed
Merge branch '2.1' of github.com:krayin/laravel-crm into issue#2256
2 parents 7150019 + 1d2e602 commit 562f645

File tree

45 files changed

+1362
-448
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

45 files changed

+1362
-448
lines changed

README.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,12 @@ php artisan serve
110110
email:admin@example.com
111111
password:admin123
112112
```
113+
### Krayin CRM Multi Tenant SaaS
114+
115+
[Krayin CRM Multi Tenant SaaS](https://krayincrm.com/extensions/krayin-crm-multi-tenant-saas-extension/) Krayin Multitenant SaaS is a Laravel-based CRM solution that allows multiple businesses (tenants) to use a single application instance while keeping their data isolated and secure.
116+
117+
![enter image description here](https://raw.githubusercontent.com/krayin/temp-media/master/krayin-saas.png)
118+
113119
### WhatsApp CRM Integration
114120

115121
[Krayin CRM WhatsApp](https://krayincrm.com/extensions/krayin-crm-whatsapp-extension/) Extension enables the store administrator to generate leads via their WhatsApp number.
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
<?php
2+
3+
use Illuminate\Database\Migrations\Migration;
4+
use Illuminate\Database\Schema\Blueprint;
5+
use Illuminate\Support\Facades\Schema;
6+
7+
return new class extends Migration
8+
{
9+
/**
10+
* Run the migrations.
11+
*/
12+
public function up(): void
13+
{
14+
Schema::table('lead_pipelines', function (Blueprint $table) {
15+
$table->string('name')->unique()->change();
16+
});
17+
}
18+
19+
/**
20+
* Reverse the migrations.
21+
*/
22+
public function down(): void
23+
{
24+
Schema::table('lead_pipelines', function (Blueprint $table) {
25+
$table->dropUnique(['name']);
26+
27+
$table->string('name')->change();
28+
});
29+
}
30+
};

packages/Webkul/Admin/src/Http/Controllers/Lead/LeadController.php

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -153,24 +153,28 @@ public function create(): View
153153
/**
154154
* Store a newly created resource in storage.
155155
*/
156-
public function store(LeadForm $request): RedirectResponse
156+
public function store(LeadForm $request): RedirectResponse|JsonResponse
157157
{
158158
Event::dispatch('lead.create.before');
159159

160-
$data = $request->all();
160+
$data = request()->all();
161161

162162
$data['status'] = 1;
163163

164-
if (isset($data['lead_pipeline_stage_id'])) {
164+
if (! empty($data['lead_pipeline_stage_id'])) {
165165
$stage = $this->stageRepository->findOrFail($data['lead_pipeline_stage_id']);
166166

167167
$data['lead_pipeline_id'] = $stage->lead_pipeline_id;
168168
} else {
169-
$pipeline = $this->pipelineRepository->getDefaultPipeline();
169+
if (empty($data['lead_pipeline_id'])) {
170+
$pipeline = $this->pipelineRepository->getDefaultPipeline();
170171

171-
$stage = $pipeline->stages()->first();
172+
$data['lead_pipeline_id'] = $pipeline->id;
173+
} else {
174+
$pipeline = $this->pipelineRepository->findOrFail($data['lead_pipeline_id']);
175+
}
172176

173-
$data['lead_pipeline_id'] = $pipeline->id;
177+
$stage = $pipeline->stages()->first();
174178

175179
$data['lead_pipeline_stage_id'] = $stage->id;
176180
}
@@ -181,11 +185,22 @@ public function store(LeadForm $request): RedirectResponse
181185

182186
$lead = $this->leadRepository->create($data);
183187

188+
if (request()->ajax()) {
189+
return response()->json([
190+
'message' => trans('admin::app.leads.create-success'),
191+
'data' => new LeadResource($lead),
192+
]);
193+
}
194+
184195
Event::dispatch('lead.create.after', $lead);
185196

186197
session()->flash('success', trans('admin::app.leads.create-success'));
187198

188-
return redirect()->route('admin.leads.index', $data['lead_pipeline_id']);
199+
if (! empty($data['lead_pipeline_id'])) {
200+
$params['pipeline_id'] = $data['lead_pipeline_id'];
201+
}
202+
203+
return redirect()->route('admin.leads.index', $params ?? []);
189204
}
190205

191206
/**

packages/Webkul/Admin/src/Http/Controllers/Products/ProductController.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,9 @@ public function search(): JsonResource
153153
{
154154
$products = $this->productRepository
155155
->pushCriteria(app(RequestCriteria::class))
156-
->all();
156+
->orderBy('created_at', 'desc')
157+
->take(5)
158+
->get();
157159

158160
return ProductResource::collection($products);
159161
}

packages/Webkul/Admin/src/Http/Controllers/Settings/PipelineController.php

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -79,9 +79,24 @@ public function update(PipelineForm $request, int $id): RedirectResponse
7979
{
8080
$request->validated();
8181

82-
$request->merge([
83-
'is_default' => request()->has('is_default') ? 1 : 0,
84-
]);
82+
$isDefault = request()->has('is_default') ? 1 : 0;
83+
84+
if (! $isDefault) {
85+
$defaultCount = $this->pipelineRepository->findWhere(['is_default' => 1])->count();
86+
87+
$pipeline = $this->pipelineRepository->find($id);
88+
89+
if (
90+
$defaultCount === 1
91+
&& $pipeline->is_default
92+
) {
93+
session()->flash('error', trans('admin::app.settings.pipelines.index.default-required'));
94+
95+
return redirect()->back();
96+
}
97+
}
98+
99+
$request->merge(['is_default' => $isDefault]);
85100

86101
Event::dispatch('settings.pipeline.update.before', $id);
87102

packages/Webkul/Admin/src/Http/Controllers/Settings/UserController.php

Lines changed: 20 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
use Illuminate\Http\JsonResponse;
66
use Illuminate\Http\Resources\Json\JsonResource;
7+
use Illuminate\Support\Arr;
78
use Illuminate\Support\Facades\Event;
89
use Illuminate\Support\Facades\Mail;
910
use Illuminate\View\View;
@@ -58,25 +59,24 @@ public function store(): View|JsonResponse
5859
'password' => 'nullable',
5960
'confirm_password' => 'nullable|required_with:password|same:password',
6061
'role_id' => 'required',
62+
'status' => 'boolean|in:0,1',
63+
'view_permission' => 'string|in:global,group,individual',
6164
]);
6265

6366
$data = request()->all();
6467

65-
if (isset($data['password']) && $data['password']) {
68+
if (
69+
isset($data['password'])
70+
&& $data['password']
71+
) {
6672
$data['password'] = bcrypt($data['password']);
6773
}
6874

69-
$data['status'] = $data['status'] ? 1 : 0;
70-
7175
Event::dispatch('settings.user.create.before');
7276

7377
$admin = $this->userRepository->create($data);
7478

75-
$admin->view_permission = $data['view_permission'];
76-
77-
$admin->save();
78-
79-
$admin->groups()->sync(request('groups') ?? []);
79+
$admin->groups()->sync($data['groups'] ?? []);
8080

8181
try {
8282
Mail::queue(new UserCreatedNotification($admin));
@@ -111,33 +111,33 @@ public function update(int $id): JsonResponse
111111
{
112112
$this->validate(request(), [
113113
'email' => 'required|email|unique:users,email,'.$id,
114-
'name' => 'required',
115-
'password' => 'nullable',
114+
'name' => 'required|string',
115+
'password' => 'nullable|string|min:6',
116116
'confirm_password' => 'nullable|required_with:password|same:password',
117-
'role_id' => 'required',
117+
'role_id' => 'required|integer|exists:roles,id',
118+
'status' => 'nullable|boolean|in:0,1',
119+
'view_permission' => 'required|string|in:global,group,individual',
118120
]);
119121

120122
$data = request()->all();
121123

122-
if (! $data['password']) {
123-
unset($data['password'], $data['confirm_password']);
124+
if (empty($data['password'])) {
125+
$data = Arr::except($data, ['password', 'confirm_password']);
124126
} else {
125127
$data['password'] = bcrypt($data['password']);
126128
}
127129

128-
if (auth()->guard('user')->user()->id != $id) {
129-
$data['status'] = $data['status'] ? 1 : 0;
130+
$authUser = auth()->guard('user')->user();
131+
132+
if ($authUser->id == $id) {
133+
$data['status'] = true;
130134
}
131135

132136
Event::dispatch('settings.user.update.before', $id);
133137

134138
$admin = $this->userRepository->update($data, $id);
135139

136-
$admin->view_permission = $data['view_permission'];
137-
138-
$admin->save();
139-
140-
$admin->groups()->sync(request()->input('groups') ?? []);
140+
$admin->groups()->sync($data['groups'] ?? []);
141141

142142
Event::dispatch('settings.user.update.after', $admin);
143143

packages/Webkul/Admin/src/Http/Controllers/User/SessionController.php

Lines changed: 53 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -2,38 +2,38 @@
22

33
namespace Webkul\Admin\Http\Controllers\User;
44

5+
use Illuminate\Http\RedirectResponse;
6+
use Illuminate\Support\Collection;
7+
use Illuminate\View\View;
58
use Webkul\Admin\Http\Controllers\Controller;
9+
use Webkul\Core\Menu\MenuItem;
610

711
class SessionController extends Controller
812
{
913
/**
1014
* Show the form for creating a new resource.
11-
*
12-
* @return \Illuminate\View\View
1315
*/
14-
public function create()
16+
public function create(): RedirectResponse|View
1517
{
1618
if (auth()->guard('user')->check()) {
1719
return redirect()->route('admin.dashboard.index');
18-
} else {
19-
if (strpos(url()->previous(), 'admin') !== false) {
20-
$intendedUrl = url()->previous();
21-
} else {
22-
$intendedUrl = route('admin.dashboard.index');
23-
}
20+
}
2421

25-
session()->put('url.intended', $intendedUrl);
22+
$previousUrl = url()->previous();
2623

27-
return view('admin::sessions.login');
28-
}
24+
$intendedUrl = str_contains($previousUrl, 'admin')
25+
? $previousUrl
26+
: route('admin.dashboard.index');
27+
28+
session()->put('url.intended', $intendedUrl);
29+
30+
return view('admin::sessions.login');
2931
}
3032

3133
/**
3234
* Store a newly created resource in storage.
33-
*
34-
* @return \Illuminate\Http\Response
3535
*/
36-
public function store()
36+
public function store(): RedirectResponse
3737
{
3838
$this->validate(request(), [
3939
'email' => 'required|email',
@@ -54,9 +54,11 @@ public function store()
5454
return redirect()->route('admin.session.create');
5555
}
5656

57-
if (! bouncer()->hasPermission('dashboard')) {
58-
$availableNextMenu = menu()->getItems('admin')?->first();
57+
$menus = menu()->getItems('admin');
5958

59+
$availableNextMenu = $menus?->first();
60+
61+
if (! bouncer()->hasPermission('dashboard')) {
6062
if (is_null($availableNextMenu)) {
6163
session()->flash('error', trans('admin::app.users.not-permission'));
6264

@@ -68,18 +70,48 @@ public function store()
6870
return redirect()->to($availableNextMenu->getUrl());
6971
}
7072

71-
return redirect()->intended(route('admin.dashboard.index'));
73+
$hasAccessToIntendedUrl = $this->canAccessIntendedUrl($menus, redirect()->getIntendedUrl());
74+
75+
if ($hasAccessToIntendedUrl) {
76+
return redirect()->intended(route('admin.dashboard.index'));
77+
}
78+
79+
return redirect()->to($availableNextMenu->getUrl());
7280
}
7381

7482
/**
7583
* Remove the specified resource from storage.
76-
*
77-
* @return \Illuminate\Http\Response
7884
*/
79-
public function destroy()
85+
public function destroy(): RedirectResponse
8086
{
8187
auth()->guard('user')->logout();
8288

8389
return redirect()->route('admin.session.create');
8490
}
91+
92+
/**
93+
* Find menu item by URL.
94+
*/
95+
protected function canAccessIntendedUrl(Collection $menus, ?string $url): ?MenuItem
96+
{
97+
if (is_null($url)) {
98+
return null;
99+
}
100+
101+
foreach ($menus as $menu) {
102+
if ($menu->getUrl() === $url) {
103+
return $menu;
104+
}
105+
106+
if ($menu->haveChildren()) {
107+
$found = $this->canAccessIntendedUrl($menu->getChildren(), $url);
108+
109+
if ($found) {
110+
return $found;
111+
}
112+
}
113+
}
114+
115+
return null;
116+
}
85117
}

packages/Webkul/Admin/src/Http/Requests/PipelineForm.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,14 +36,14 @@ public function rules()
3636
{
3737
if (request('id')) {
3838
return [
39-
'name' => 'required',
39+
'name' => 'required|unique:lead_pipelines,name,'.request('id'),
4040
'stages.*.name' => 'unique_key',
4141
'stages.*.code' => 'unique_key',
4242
];
4343
}
4444

4545
return [
46-
'name' => 'required',
46+
'name' => 'required|unique:lead_pipelines,name',
4747
'rotten_days' => 'required',
4848
'stages.*.name' => 'unique_key',
4949
'stages.*.code' => 'unique_key',

0 commit comments

Comments
 (0)