mirror of
https://github.com/InvoiceShelf/InvoiceShelf.git
synced 2026-04-15 09:14:08 +00:00
Rename controller namespaces: drop V1 prefix, clarify roles
V1/Admin -> Company (company-scoped controllers) V1/SuperAdmin -> Admin (platform-wide admin controllers) V1/Customer -> CustomerPortal (customer-facing portal) V1/Installation -> Setup (installation wizard) V1/PDF -> Pdf (consistent casing) V1/Modules -> Modules (drop V1 prefix) V1/Webhook -> Webhook (drop V1 prefix) The V1 prefix served no purpose - API versioning is in the route prefix (/api/v1/), not the controller namespace. "Admin" was misleading for company-scoped controllers. "SuperAdmin" is now simply "Admin" for platform administration.
This commit is contained in:
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Company\Auth;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Providers\AppServiceProvider;
|
||||
use Illuminate\Foundation\Auth\ConfirmsPasswords;
|
||||
|
||||
class ConfirmPasswordController extends Controller
|
||||
{
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Confirm Password Controller
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This controller is responsible for handling password confirmations and
|
||||
| uses a simple trait to include the behavior. You're free to explore
|
||||
| this trait and override any functions that require customization.
|
||||
|
|
||||
*/
|
||||
|
||||
use ConfirmsPasswords;
|
||||
|
||||
/**
|
||||
* Where to redirect users when the intended url fails.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $redirectTo = AppServiceProvider::HOME;
|
||||
|
||||
/**
|
||||
* Create a new controller instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->middleware('auth');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Company\Auth;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Foundation\Auth\SendsPasswordResetEmails;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class ForgotPasswordController extends Controller
|
||||
{
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Password Reset Controller
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This controller is responsible for handling password reset emails and
|
||||
| includes a trait which assists in sending these notifications from
|
||||
| your application to your users. Feel free to explore this trait.
|
||||
|
|
||||
*/
|
||||
|
||||
use SendsPasswordResetEmails;
|
||||
|
||||
/**
|
||||
* Get the response for a successful password reset link.
|
||||
*
|
||||
* @param string $response
|
||||
* @return RedirectResponse|JsonResponse
|
||||
*/
|
||||
protected function sendResetLinkResponse(Request $request, $response)
|
||||
{
|
||||
return response()->json([
|
||||
'message' => 'Password reset email sent.',
|
||||
'data' => $response,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the response for a failed password reset link.
|
||||
*
|
||||
* @param string $response
|
||||
* @return RedirectResponse|JsonResponse
|
||||
*/
|
||||
protected function sendResetLinkFailedResponse(Request $request, $response)
|
||||
{
|
||||
return response()->json([
|
||||
'error' => 'Email could not be sent to this email address.',
|
||||
], 403);
|
||||
}
|
||||
}
|
||||
40
app/Http/Controllers/Company/Auth/LoginController.php
Normal file
40
app/Http/Controllers/Company/Auth/LoginController.php
Normal file
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Company\Auth;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Providers\AppServiceProvider;
|
||||
use Illuminate\Foundation\Auth\AuthenticatesUsers;
|
||||
|
||||
class LoginController extends Controller
|
||||
{
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Login Controller
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This controller handles authenticating users for the application and
|
||||
| redirecting them to your home screen. The controller uses a trait
|
||||
| to conveniently provide its functionality to your applications.
|
||||
|
|
||||
*/
|
||||
|
||||
use AuthenticatesUsers;
|
||||
|
||||
/**
|
||||
* Where to redirect users after login.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $redirectTo = AppServiceProvider::HOME;
|
||||
|
||||
/**
|
||||
* Create a new controller instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->middleware('guest')->except('logout');
|
||||
}
|
||||
}
|
||||
70
app/Http/Controllers/Company/Auth/RegisterController.php
Normal file
70
app/Http/Controllers/Company/Auth/RegisterController.php
Normal file
@@ -0,0 +1,70 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Company\Auth;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\User;
|
||||
use App\Providers\AppServiceProvider;
|
||||
use Illuminate\Foundation\Auth\RegistersUsers;
|
||||
use Illuminate\Support\Facades\Validator;
|
||||
|
||||
class RegisterController extends Controller
|
||||
{
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Register Controller
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This controller handles the registration of new users as well as their
|
||||
| validation and creation. By default this controller uses a trait to
|
||||
| provide this functionality without requiring any additional code.
|
||||
|
|
||||
*/
|
||||
|
||||
use RegistersUsers;
|
||||
|
||||
/**
|
||||
* Where to redirect users after registration.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $redirectTo = AppServiceProvider::HOME;
|
||||
|
||||
/**
|
||||
* Create a new controller instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->middleware('guest');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a validator for an incoming registration request.
|
||||
*
|
||||
* @return \Illuminate\Contracts\Validation\Validator
|
||||
*/
|
||||
protected function validator(array $data)
|
||||
{
|
||||
return Validator::make($data, [
|
||||
'name' => ['required', 'string', 'max:255'],
|
||||
'email' => ['required', 'string', 'email', 'max:255', 'unique:users'],
|
||||
'password' => ['required', 'string', 'min:8', 'confirmed'],
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new user instance after a valid registration.
|
||||
*
|
||||
* @return \App\User
|
||||
*/
|
||||
protected function create(array $data)
|
||||
{
|
||||
return User::create([
|
||||
'name' => $data['name'],
|
||||
'email' => $data['email'],
|
||||
'password' => $data['password'],
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Company\Auth;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Providers\AppServiceProvider;
|
||||
use Illuminate\Auth\Events\PasswordReset;
|
||||
use Illuminate\Contracts\Auth\CanResetPassword;
|
||||
use Illuminate\Foundation\Auth\ResetsPasswords;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
class ResetPasswordController extends Controller
|
||||
{
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Password Reset Controller
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This controller is responsible for handling password reset requests
|
||||
| and uses a simple trait to include this behavior. You're free to
|
||||
| explore this trait and override any methods you wish to tweak.
|
||||
|
|
||||
*/
|
||||
|
||||
use ResetsPasswords;
|
||||
|
||||
/**
|
||||
* Where to redirect users after resetting their password.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $redirectTo = AppServiceProvider::HOME;
|
||||
|
||||
/**
|
||||
* Get the response for a successful password reset.
|
||||
*
|
||||
* @param string $response
|
||||
* @return RedirectResponse|JsonResponse
|
||||
*/
|
||||
protected function sendResetResponse(Request $request, $response)
|
||||
{
|
||||
return response()->json([
|
||||
'message' => 'Password reset successfully.',
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the given user's password.
|
||||
*
|
||||
* @param CanResetPassword $user
|
||||
* @param string $password
|
||||
* @return void
|
||||
*/
|
||||
protected function resetPassword($user, $password)
|
||||
{
|
||||
$user->password = $password;
|
||||
|
||||
$user->setRememberToken(Str::random(60));
|
||||
|
||||
$user->save();
|
||||
|
||||
event(new PasswordReset($user));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the response for a failed password reset.
|
||||
*
|
||||
* @param string $response
|
||||
* @return RedirectResponse|JsonResponse
|
||||
*/
|
||||
protected function sendResetFailedResponse(Request $request, $response)
|
||||
{
|
||||
return response('Failed, Invalid Token.', 403);
|
||||
}
|
||||
}
|
||||
42
app/Http/Controllers/Company/Auth/VerificationController.php
Normal file
42
app/Http/Controllers/Company/Auth/VerificationController.php
Normal file
@@ -0,0 +1,42 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Company\Auth;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Providers\AppServiceProvider;
|
||||
use Illuminate\Foundation\Auth\VerifiesEmails;
|
||||
|
||||
class VerificationController extends Controller
|
||||
{
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Email Verification Controller
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This controller is responsible for handling email verification for any
|
||||
| user that recently registered with the application. Emails may also
|
||||
| be re-sent if the user didn't receive the original email message.
|
||||
|
|
||||
*/
|
||||
|
||||
use VerifiesEmails;
|
||||
|
||||
/**
|
||||
* Where to redirect users after verification.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $redirectTo = AppServiceProvider::HOME;
|
||||
|
||||
/**
|
||||
* Create a new controller instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->middleware('auth');
|
||||
$this->middleware('signed')->only('verify');
|
||||
$this->middleware('throttle:6,1')->only('verify', 'resend');
|
||||
}
|
||||
}
|
||||
97
app/Http/Controllers/Company/Company/CompaniesController.php
Normal file
97
app/Http/Controllers/Company/Company/CompaniesController.php
Normal file
@@ -0,0 +1,97 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Company\Company;
|
||||
|
||||
use App\Facades\Hashids;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\CompaniesRequest;
|
||||
use App\Http\Resources\CompanyResource;
|
||||
use App\Models\Company;
|
||||
use App\Models\User;
|
||||
use App\Services\CompanyService;
|
||||
use Illuminate\Http\Request;
|
||||
use Silber\Bouncer\BouncerFacade;
|
||||
|
||||
class CompaniesController extends Controller
|
||||
{
|
||||
public function __construct(
|
||||
private readonly CompanyService $companyService,
|
||||
) {}
|
||||
|
||||
public function show(Request $request)
|
||||
{
|
||||
$company = Company::find($request->header('company'));
|
||||
|
||||
return new CompanyResource($company);
|
||||
}
|
||||
|
||||
public function store(CompaniesRequest $request)
|
||||
{
|
||||
$this->authorize('create company');
|
||||
|
||||
$user = $request->user();
|
||||
|
||||
$company = Company::create($request->getCompanyPayload());
|
||||
$company->unique_hash = Hashids::connection(Company::class)->encode($company->id);
|
||||
$company->save();
|
||||
$this->companyService->setupDefaults($company);
|
||||
$user->companies()->attach($company->id);
|
||||
$user->assign('super admin');
|
||||
|
||||
if ($request->address) {
|
||||
$company->address()->create($request->address);
|
||||
}
|
||||
|
||||
return new CompanyResource($company);
|
||||
}
|
||||
|
||||
public function destroy(Request $request)
|
||||
{
|
||||
$company = Company::find($request->header('company'));
|
||||
|
||||
$this->authorize('delete company', $company);
|
||||
|
||||
$user = $request->user();
|
||||
|
||||
if ($request->name !== $company->name) {
|
||||
return respondJson('company_name_must_match_with_given_name', 'Company name must match with given name');
|
||||
}
|
||||
|
||||
if ($user->loadCount('companies')->companies_count <= 1) {
|
||||
return respondJson('You_cannot_delete_all_companies', 'You cannot delete all companies');
|
||||
}
|
||||
|
||||
$this->companyService->delete($company, $user);
|
||||
|
||||
return response()->json([
|
||||
'success' => true,
|
||||
]);
|
||||
}
|
||||
|
||||
public function transferOwnership(Request $request, User $user)
|
||||
{
|
||||
$company = Company::find($request->header('company'));
|
||||
$this->authorize('transfer company ownership', $company);
|
||||
|
||||
if (! $user->hasCompany($company->id)) {
|
||||
return response()->json([
|
||||
'success' => false,
|
||||
'message' => 'User does not belong to this company.',
|
||||
]);
|
||||
}
|
||||
|
||||
$company->update(['owner_id' => $user->id]);
|
||||
BouncerFacade::sync($user)->roles(['super admin']);
|
||||
|
||||
return response()->json([
|
||||
'success' => true,
|
||||
]);
|
||||
}
|
||||
|
||||
public function getUserCompanies(Request $request)
|
||||
{
|
||||
$companies = $request->user()->companies;
|
||||
|
||||
return CompanyResource::collection($companies);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Company\Config;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\Response;
|
||||
|
||||
class FiscalYearsController extends Controller
|
||||
{
|
||||
/**
|
||||
* Handle the incoming request.
|
||||
*
|
||||
* @return Response
|
||||
*/
|
||||
public function __invoke(Request $request)
|
||||
{
|
||||
return response()->json([
|
||||
'fiscal_years' => config('invoiceshelf.fiscal_years'),
|
||||
]);
|
||||
}
|
||||
}
|
||||
22
app/Http/Controllers/Company/Config/LanguagesController.php
Normal file
22
app/Http/Controllers/Company/Config/LanguagesController.php
Normal file
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Company\Config;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\Response;
|
||||
|
||||
class LanguagesController extends Controller
|
||||
{
|
||||
/**
|
||||
* Handle the incoming request.
|
||||
*
|
||||
* @return Response
|
||||
*/
|
||||
public function __invoke(Request $request)
|
||||
{
|
||||
return response()->json([
|
||||
'languages' => config('invoiceshelf.languages'),
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Company\Config;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\Response;
|
||||
|
||||
class RetrospectiveEditsController extends Controller
|
||||
{
|
||||
/**
|
||||
* Handle the incoming request.
|
||||
*
|
||||
* @return Response
|
||||
*/
|
||||
public function __invoke(Request $request)
|
||||
{
|
||||
return response()->json([
|
||||
'retrospective_edits' => config('invoiceshelf.retrospective_edits'),
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Company\CustomField;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\CustomFieldRequest;
|
||||
use App\Http\Resources\CustomFieldResource;
|
||||
use App\Models\CustomField;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\Response;
|
||||
|
||||
class CustomFieldsController extends Controller
|
||||
{
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*
|
||||
* @return Response
|
||||
*/
|
||||
public function index(Request $request)
|
||||
{
|
||||
$this->authorize('viewAny', CustomField::class);
|
||||
|
||||
$limit = $request->has('limit') ? $request->limit : 5;
|
||||
|
||||
$customFields = CustomField::applyFilters($request->all())
|
||||
->whereCompany()
|
||||
->latest()
|
||||
->paginateData($limit);
|
||||
|
||||
return CustomFieldResource::collection($customFields);
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*
|
||||
* @param \Illuminate\Http\CustomFieldRequest $request
|
||||
* @return Response
|
||||
*/
|
||||
public function store(CustomFieldRequest $request)
|
||||
{
|
||||
$this->authorize('create', CustomField::class);
|
||||
|
||||
$customField = CustomField::createCustomField($request);
|
||||
|
||||
return new CustomFieldResource($customField);
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the specified resource.
|
||||
*
|
||||
* @param int $id
|
||||
* @return Response
|
||||
*/
|
||||
public function show(CustomField $customField)
|
||||
{
|
||||
$this->authorize('view', $customField);
|
||||
|
||||
return new CustomFieldResource($customField);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the specified resource in storage.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param int $id
|
||||
* @return Response
|
||||
*/
|
||||
public function update(CustomFieldRequest $request, CustomField $customField)
|
||||
{
|
||||
$this->authorize('update', $customField);
|
||||
|
||||
$customField->updateCustomField($request);
|
||||
|
||||
return new CustomFieldResource($customField);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified resource from storage.
|
||||
*
|
||||
* @param int $id
|
||||
* @return Response
|
||||
*/
|
||||
public function destroy(CustomField $customField)
|
||||
{
|
||||
$this->authorize('delete', $customField);
|
||||
|
||||
if ($customField->customFieldValues()->exists()) {
|
||||
$customField->customFieldValues()->delete();
|
||||
}
|
||||
|
||||
$customField->forceDelete();
|
||||
|
||||
return response()->json([
|
||||
'success' => true,
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Company\Customer;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Resources\CustomerResource;
|
||||
use App\Models\Customer;
|
||||
use App\Services\CustomerService;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class CustomerStatsController extends Controller
|
||||
{
|
||||
public function __construct(
|
||||
private readonly CustomerService $customerService,
|
||||
) {}
|
||||
|
||||
public function __invoke(Request $request, Customer $customer)
|
||||
{
|
||||
$this->authorize('view', $customer);
|
||||
|
||||
$chartData = $this->customerService->getStats(
|
||||
$customer,
|
||||
$request->header('company'),
|
||||
$request->has('previous_year')
|
||||
);
|
||||
|
||||
$customer = Customer::find($customer->id);
|
||||
|
||||
return (new CustomerResource($customer))
|
||||
->additional(['meta' => [
|
||||
'chartData' => $chartData,
|
||||
]]);
|
||||
}
|
||||
}
|
||||
106
app/Http/Controllers/Company/Customer/CustomersController.php
Normal file
106
app/Http/Controllers/Company/Customer/CustomersController.php
Normal file
@@ -0,0 +1,106 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Company\Customer;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests;
|
||||
use App\Http\Requests\DeleteCustomersRequest;
|
||||
use App\Http\Resources\CustomerResource;
|
||||
use App\Models\Customer;
|
||||
use App\Services\CustomerService;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class CustomersController extends Controller
|
||||
{
|
||||
public function __construct(
|
||||
private readonly CustomerService $customerService,
|
||||
) {}
|
||||
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*
|
||||
* @return JsonResponse
|
||||
*/
|
||||
public function index(Request $request)
|
||||
{
|
||||
$this->authorize('viewAny', Customer::class);
|
||||
|
||||
$limit = $request->has('limit') ? $request->limit : 10;
|
||||
|
||||
$customers = Customer::with('creator')
|
||||
->whereCompany()
|
||||
->applyFilters($request->all())
|
||||
->withSum('invoices as base_due_amount', 'base_due_amount')
|
||||
->withSum('invoices as due_amount', 'due_amount')
|
||||
->paginateData($limit);
|
||||
|
||||
return CustomerResource::collection($customers)
|
||||
->additional(['meta' => [
|
||||
'customer_total_count' => Customer::whereCompany()->count(),
|
||||
]]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*
|
||||
* @param Request $request
|
||||
* @return JsonResponse
|
||||
*/
|
||||
public function store(Requests\CustomerRequest $request)
|
||||
{
|
||||
$this->authorize('create', Customer::class);
|
||||
|
||||
$customer = $this->customerService->create($request);
|
||||
|
||||
return new CustomerResource($customer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the specified resource.
|
||||
*
|
||||
* @return JsonResponse
|
||||
*/
|
||||
public function show(Customer $customer)
|
||||
{
|
||||
$this->authorize('view', $customer);
|
||||
|
||||
return new CustomerResource($customer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the specified resource in storage.
|
||||
*
|
||||
* @param Request $request
|
||||
* @return JsonResponse
|
||||
*/
|
||||
public function update(Requests\CustomerRequest $request, Customer $customer)
|
||||
{
|
||||
$this->authorize('update', $customer);
|
||||
|
||||
$customer = $this->customerService->update($request, $customer);
|
||||
|
||||
return new CustomerResource($customer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a list of Customers along side all their resources (ie. Estimates, Invoices, Payments and Addresses)
|
||||
*
|
||||
* @param Request $request
|
||||
* @return JsonResponse
|
||||
*/
|
||||
public function delete(DeleteCustomersRequest $request)
|
||||
{
|
||||
$this->authorize('delete multiple customers');
|
||||
|
||||
$ids = Customer::whereCompany()
|
||||
->whereIn('id', $request->ids)
|
||||
->pluck('id');
|
||||
|
||||
$this->customerService->delete($ids);
|
||||
|
||||
return response()->json([
|
||||
'success' => true,
|
||||
]);
|
||||
}
|
||||
}
|
||||
167
app/Http/Controllers/Company/Dashboard/DashboardController.php
Normal file
167
app/Http/Controllers/Company/Dashboard/DashboardController.php
Normal file
@@ -0,0 +1,167 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Company\Dashboard;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Company;
|
||||
use App\Models\CompanySetting;
|
||||
use App\Models\Customer;
|
||||
use App\Models\Estimate;
|
||||
use App\Models\Expense;
|
||||
use App\Models\Invoice;
|
||||
use App\Models\Payment;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Silber\Bouncer\BouncerFacade;
|
||||
|
||||
class DashboardController extends Controller
|
||||
{
|
||||
/**
|
||||
* Handle the incoming request.
|
||||
*
|
||||
* @return JsonResponse
|
||||
*/
|
||||
public function __invoke(Request $request)
|
||||
{
|
||||
$company = Company::find($request->header('company'));
|
||||
|
||||
$this->authorize('view dashboard', $company);
|
||||
|
||||
$invoice_totals = [];
|
||||
$expense_totals = [];
|
||||
$receipt_totals = [];
|
||||
$net_income_totals = [];
|
||||
|
||||
$i = 0;
|
||||
$months = [];
|
||||
$monthCounter = 0;
|
||||
$fiscalYear = CompanySetting::getSetting('fiscal_year', $request->header('company'));
|
||||
$startDate = Carbon::now();
|
||||
$start = Carbon::now();
|
||||
$end = Carbon::now();
|
||||
$terms = explode('-', $fiscalYear);
|
||||
$companyStartMonth = intval($terms[0]);
|
||||
|
||||
if ($companyStartMonth <= $start->month) {
|
||||
$startDate->month($companyStartMonth)->startOfMonth();
|
||||
$start->month($companyStartMonth)->startOfMonth();
|
||||
$end->month($companyStartMonth)->endOfMonth();
|
||||
} else {
|
||||
$startDate->subYear()->month($companyStartMonth)->startOfMonth();
|
||||
$start->subYear()->month($companyStartMonth)->startOfMonth();
|
||||
$end->subYear()->month($companyStartMonth)->endOfMonth();
|
||||
}
|
||||
|
||||
if ($request->has('previous_year')) {
|
||||
$startDate->subYear()->startOfMonth();
|
||||
$start->subYear()->startOfMonth();
|
||||
$end->subYear()->endOfMonth();
|
||||
}
|
||||
|
||||
while ($monthCounter < 12) {
|
||||
array_push(
|
||||
$invoice_totals,
|
||||
Invoice::whereBetween(
|
||||
'invoice_date',
|
||||
[$start->format('Y-m-d'), $end->format('Y-m-d')]
|
||||
)
|
||||
->whereCompany()
|
||||
->sum('base_total')
|
||||
);
|
||||
array_push(
|
||||
$expense_totals,
|
||||
Expense::whereBetween(
|
||||
'expense_date',
|
||||
[$start->format('Y-m-d'), $end->format('Y-m-d')]
|
||||
)
|
||||
->whereCompany()
|
||||
->sum('base_amount')
|
||||
);
|
||||
array_push(
|
||||
$receipt_totals,
|
||||
Payment::whereBetween(
|
||||
'payment_date',
|
||||
[$start->format('Y-m-d'), $end->format('Y-m-d')]
|
||||
)
|
||||
->whereCompany()
|
||||
->sum('base_amount')
|
||||
);
|
||||
array_push(
|
||||
$net_income_totals,
|
||||
($receipt_totals[$i] - $expense_totals[$i])
|
||||
);
|
||||
$i++;
|
||||
array_push($months, $start->translatedFormat('M'));
|
||||
$monthCounter++;
|
||||
$end->startOfMonth();
|
||||
$start->addMonth()->startOfMonth();
|
||||
$end->addMonth()->endOfMonth();
|
||||
}
|
||||
|
||||
$start->subMonth()->endOfMonth();
|
||||
|
||||
$total_sales = Invoice::whereBetween(
|
||||
'invoice_date',
|
||||
[$startDate->format('Y-m-d'), $start->format('Y-m-d')]
|
||||
)
|
||||
->whereCompany()
|
||||
->sum('base_total');
|
||||
|
||||
$total_receipts = Payment::whereBetween(
|
||||
'payment_date',
|
||||
[$startDate->format('Y-m-d'), $start->format('Y-m-d')]
|
||||
)
|
||||
->whereCompany()
|
||||
->sum('base_amount');
|
||||
|
||||
$total_expenses = Expense::whereBetween(
|
||||
'expense_date',
|
||||
[$startDate->format('Y-m-d'), $start->format('Y-m-d')]
|
||||
)
|
||||
->whereCompany()
|
||||
->sum('base_amount');
|
||||
|
||||
$total_net_income = (int) $total_receipts - (int) $total_expenses;
|
||||
|
||||
$chart_data = [
|
||||
'months' => $months,
|
||||
'invoice_totals' => $invoice_totals,
|
||||
'expense_totals' => $expense_totals,
|
||||
'receipt_totals' => $receipt_totals,
|
||||
'net_income_totals' => $net_income_totals,
|
||||
];
|
||||
|
||||
$total_customer_count = Customer::whereCompany()->count();
|
||||
$total_invoice_count = Invoice::whereCompany()
|
||||
->count();
|
||||
$total_estimate_count = Estimate::whereCompany()->count();
|
||||
$total_amount_due = Invoice::whereCompany()
|
||||
->sum('base_due_amount');
|
||||
|
||||
$recent_due_invoices = Invoice::with('customer')
|
||||
->whereCompany()
|
||||
->where('base_due_amount', '>', 0)
|
||||
->take(5)
|
||||
->latest()
|
||||
->get();
|
||||
$recent_estimates = Estimate::with('customer')->whereCompany()->take(5)->latest()->get();
|
||||
|
||||
return response()->json([
|
||||
'total_amount_due' => $total_amount_due,
|
||||
'total_customer_count' => $total_customer_count,
|
||||
'total_invoice_count' => $total_invoice_count,
|
||||
'total_estimate_count' => $total_estimate_count,
|
||||
|
||||
'recent_due_invoices' => BouncerFacade::can('view-invoice', Invoice::class) ? $recent_due_invoices : [],
|
||||
'recent_estimates' => BouncerFacade::can('view-estimate', Estimate::class) ? $recent_estimates : [],
|
||||
|
||||
'chart_data' => $chart_data,
|
||||
|
||||
'total_sales' => $total_sales,
|
||||
'total_receipts' => $total_receipts,
|
||||
'total_expenses' => $total_expenses,
|
||||
'total_net_income' => $total_net_income,
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Company\Estimate;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Estimate;
|
||||
use App\Services\Pdf\PdfTemplateUtils;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class EstimateTemplatesController extends Controller
|
||||
{
|
||||
/**
|
||||
* Handle the incoming request.
|
||||
*
|
||||
* @return JsonResponse
|
||||
*/
|
||||
public function __invoke(Request $request)
|
||||
{
|
||||
$this->authorize('viewAny', Estimate::class);
|
||||
|
||||
$estimateTemplates = PdfTemplateUtils::getFormattedTemplates('estimate');
|
||||
|
||||
return response()->json([
|
||||
'estimateTemplates' => $estimateTemplates,
|
||||
]);
|
||||
}
|
||||
}
|
||||
141
app/Http/Controllers/Company/Estimate/EstimatesController.php
Normal file
141
app/Http/Controllers/Company/Estimate/EstimatesController.php
Normal file
@@ -0,0 +1,141 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Company\Estimate;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\DeleteEstimatesRequest;
|
||||
use App\Http\Requests\EstimatesRequest;
|
||||
use App\Http\Requests\SendEstimatesRequest;
|
||||
use App\Http\Resources\EstimateResource;
|
||||
use App\Http\Resources\InvoiceResource;
|
||||
use App\Jobs\GenerateEstimatePdfJob;
|
||||
use App\Models\Estimate;
|
||||
use App\Models\Invoice;
|
||||
use App\Services\EstimateService;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Mail\Markdown;
|
||||
|
||||
class EstimatesController extends Controller
|
||||
{
|
||||
public function __construct(
|
||||
private readonly EstimateService $estimateService,
|
||||
) {}
|
||||
|
||||
public function index(Request $request)
|
||||
{
|
||||
$this->authorize('viewAny', Estimate::class);
|
||||
|
||||
$limit = $request->has('limit') ? $request->limit : 10;
|
||||
|
||||
$estimates = Estimate::whereCompany()
|
||||
->join('customers', 'customers.id', '=', 'estimates.customer_id')
|
||||
->applyFilters($request->all())
|
||||
->select('estimates.*', 'customers.name')
|
||||
->latest()
|
||||
->paginateData($limit);
|
||||
|
||||
return EstimateResource::collection($estimates)
|
||||
->additional(['meta' => [
|
||||
'estimate_total_count' => Estimate::whereCompany()->count(),
|
||||
]]);
|
||||
}
|
||||
|
||||
public function store(EstimatesRequest $request)
|
||||
{
|
||||
$this->authorize('create', Estimate::class);
|
||||
|
||||
$estimate = $this->estimateService->create($request);
|
||||
|
||||
if ($request->has('estimateSend')) {
|
||||
$this->estimateService->send($estimate, $request->only(['title', 'body']));
|
||||
}
|
||||
|
||||
GenerateEstimatePdfJob::dispatch($estimate);
|
||||
|
||||
return new EstimateResource($estimate);
|
||||
}
|
||||
|
||||
public function show(Request $request, Estimate $estimate)
|
||||
{
|
||||
$this->authorize('view', $estimate);
|
||||
|
||||
return new EstimateResource($estimate);
|
||||
}
|
||||
|
||||
public function update(EstimatesRequest $request, Estimate $estimate)
|
||||
{
|
||||
$this->authorize('update', $estimate);
|
||||
|
||||
$estimate = $this->estimateService->update($estimate, $request);
|
||||
|
||||
GenerateEstimatePdfJob::dispatch($estimate, true);
|
||||
|
||||
return new EstimateResource($estimate);
|
||||
}
|
||||
|
||||
public function delete(DeleteEstimatesRequest $request)
|
||||
{
|
||||
$this->authorize('delete multiple estimates');
|
||||
|
||||
$ids = Estimate::whereCompany()
|
||||
->whereIn('id', $request->ids)
|
||||
->pluck('id');
|
||||
|
||||
Estimate::destroy($ids);
|
||||
|
||||
return response()->json([
|
||||
'success' => true,
|
||||
]);
|
||||
}
|
||||
|
||||
public function send(SendEstimatesRequest $request, Estimate $estimate)
|
||||
{
|
||||
$this->authorize('send estimate', $estimate);
|
||||
|
||||
$response = $this->estimateService->send($estimate, $request->all());
|
||||
|
||||
return response()->json($response);
|
||||
}
|
||||
|
||||
public function sendPreview(SendEstimatesRequest $request, Estimate $estimate)
|
||||
{
|
||||
$this->authorize('send estimate', $estimate);
|
||||
|
||||
$markdown = new Markdown(view(), config('mail.markdown'));
|
||||
|
||||
$data = $this->estimateService->sendEstimateData($estimate, $request->all());
|
||||
$data['url'] = $estimate->estimatePdfUrl;
|
||||
|
||||
return $markdown->render('emails.send.estimate', ['data' => $data]);
|
||||
}
|
||||
|
||||
public function clone(Request $request, Estimate $estimate)
|
||||
{
|
||||
$this->authorize('view', $estimate);
|
||||
$this->authorize('create', Estimate::class);
|
||||
|
||||
$newEstimate = $this->estimateService->clone($estimate);
|
||||
|
||||
return new EstimateResource($newEstimate);
|
||||
}
|
||||
|
||||
public function convertToInvoice(Request $request, Estimate $estimate)
|
||||
{
|
||||
$this->authorize('create', Invoice::class);
|
||||
|
||||
$invoice = $this->estimateService->convertToInvoice($estimate);
|
||||
|
||||
return new InvoiceResource($invoice);
|
||||
}
|
||||
|
||||
public function changeStatus(Request $request, Estimate $estimate)
|
||||
{
|
||||
$this->authorize('send estimate', $estimate);
|
||||
|
||||
$this->estimateService->changeStatus($estimate, $request->status);
|
||||
|
||||
return response()->json([
|
||||
'success' => true,
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,347 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Company\ExchangeRate;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\BulkExchangeRateRequest;
|
||||
use App\Http\Requests\ExchangeRateProviderRequest;
|
||||
use App\Http\Resources\ExchangeRateProviderResource;
|
||||
use App\Models\CompanySetting;
|
||||
use App\Models\Currency;
|
||||
use App\Models\Estimate;
|
||||
use App\Models\ExchangeRateLog;
|
||||
use App\Models\ExchangeRateProvider;
|
||||
use App\Models\Invoice;
|
||||
use App\Models\Payment;
|
||||
use App\Models\Tax;
|
||||
use App\Traits\ExchangeRateProvidersTrait;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\Response;
|
||||
use Illuminate\Support\Arr;
|
||||
|
||||
class ExchangeRateProviderController extends Controller
|
||||
{
|
||||
use ExchangeRateProvidersTrait;
|
||||
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*
|
||||
* @return Response
|
||||
*/
|
||||
public function index(Request $request)
|
||||
{
|
||||
$this->authorize('viewAny', ExchangeRateProvider::class);
|
||||
|
||||
$limit = $request->has('limit') ? $request->limit : 5;
|
||||
|
||||
$exchangeRateProviders = ExchangeRateProvider::whereCompany()->paginate($limit);
|
||||
|
||||
return ExchangeRateProviderResource::collection($exchangeRateProviders);
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*
|
||||
* @param Request $request
|
||||
* @return Response
|
||||
*/
|
||||
public function store(ExchangeRateProviderRequest $request)
|
||||
{
|
||||
$this->authorize('create', ExchangeRateProvider::class);
|
||||
|
||||
$query = ExchangeRateProvider::checkActiveCurrencies($request);
|
||||
|
||||
if (count($query) !== 0) {
|
||||
return respondJson('currency_used', 'Currency used.');
|
||||
}
|
||||
|
||||
$checkConverterApi = ExchangeRateProvider::checkExchangeRateProviderStatus($request);
|
||||
|
||||
if ($checkConverterApi->status() == 200) {
|
||||
$exchangeRateProvider = ExchangeRateProvider::createFromRequest($request);
|
||||
|
||||
return new ExchangeRateProviderResource($exchangeRateProvider);
|
||||
}
|
||||
|
||||
return $checkConverterApi;
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the specified resource.
|
||||
*
|
||||
* @return Response
|
||||
*/
|
||||
public function show(ExchangeRateProvider $exchangeRateProvider)
|
||||
{
|
||||
$this->authorize('view', $exchangeRateProvider);
|
||||
|
||||
return new ExchangeRateProviderResource($exchangeRateProvider);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the specified resource in storage.
|
||||
*
|
||||
* @param Request $request
|
||||
* @return Response
|
||||
*/
|
||||
public function update(ExchangeRateProviderRequest $request, ExchangeRateProvider $exchangeRateProvider)
|
||||
{
|
||||
$this->authorize('update', $exchangeRateProvider);
|
||||
|
||||
$query = $exchangeRateProvider->checkUpdateActiveCurrencies($request);
|
||||
|
||||
if (count($query) !== 0) {
|
||||
return respondJson('currency_used', 'Currency used.');
|
||||
}
|
||||
|
||||
$checkConverterApi = ExchangeRateProvider::checkExchangeRateProviderStatus($request);
|
||||
|
||||
if ($checkConverterApi->status() == 200) {
|
||||
$exchangeRateProvider->updateFromRequest($request);
|
||||
|
||||
return new ExchangeRateProviderResource($exchangeRateProvider);
|
||||
}
|
||||
|
||||
return $checkConverterApi;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified resource from storage.
|
||||
*
|
||||
* @return Response
|
||||
*/
|
||||
public function destroy(ExchangeRateProvider $exchangeRateProvider)
|
||||
{
|
||||
$this->authorize('delete', $exchangeRateProvider);
|
||||
|
||||
if ($exchangeRateProvider->active == true) {
|
||||
return respondJson('provider_active', 'Provider Active.');
|
||||
}
|
||||
|
||||
$exchangeRateProvider->delete();
|
||||
|
||||
return response()->json([
|
||||
'success' => true,
|
||||
]);
|
||||
}
|
||||
|
||||
public function activeProvider(Request $request, Currency $currency)
|
||||
{
|
||||
$query = ExchangeRateProvider::whereCompany()->whereJsonContains('currencies', $currency->code)
|
||||
->where('active', true)
|
||||
->get();
|
||||
|
||||
if (count($query) !== 0) {
|
||||
return response()->json([
|
||||
'success' => true,
|
||||
'message' => 'provider_active',
|
||||
], 200);
|
||||
}
|
||||
|
||||
return response()->json([
|
||||
'error' => 'no_active_provider',
|
||||
], 200);
|
||||
}
|
||||
|
||||
public function getRate(Request $request, Currency $currency)
|
||||
{
|
||||
$settings = CompanySetting::getSettings(['currency'], $request->header('company'));
|
||||
$baseCurrency = Currency::findOrFail($settings['currency']);
|
||||
|
||||
$query = ExchangeRateProvider::whereJsonContains('currencies', $currency->code)
|
||||
->where('active', true)
|
||||
->get()
|
||||
->toArray();
|
||||
|
||||
$exchange_rate = ExchangeRateLog::where('base_currency_id', $currency->id)
|
||||
->where('currency_id', $baseCurrency->id)
|
||||
->orderBy('created_at', 'desc')
|
||||
->value('exchange_rate');
|
||||
|
||||
if ($query) {
|
||||
$filter = Arr::only($query[0], ['key', 'driver', 'driver_config']);
|
||||
$exchange_rate_value = $this->getExchangeRate($filter, $currency->code, $baseCurrency->code);
|
||||
|
||||
if ($exchange_rate_value->status() == 200) {
|
||||
return $exchange_rate_value;
|
||||
}
|
||||
}
|
||||
if ($exchange_rate) {
|
||||
return response()->json([
|
||||
'exchangeRate' => [$exchange_rate],
|
||||
], 200);
|
||||
}
|
||||
|
||||
return response()->json([
|
||||
'error' => 'no_exchange_rate_available',
|
||||
], 200);
|
||||
}
|
||||
|
||||
public function supportedCurrencies(Request $request)
|
||||
{
|
||||
$this->authorize('viewAny', ExchangeRateProvider::class);
|
||||
|
||||
return $this->getSupportedCurrencies($request);
|
||||
}
|
||||
|
||||
public function usedCurrencies(Request $request)
|
||||
{
|
||||
$this->authorize('viewAny', ExchangeRateProvider::class);
|
||||
|
||||
$providerId = $request->provider_id;
|
||||
|
||||
$activeExchangeRateProviders = ExchangeRateProvider::where('active', true)
|
||||
->whereCompany()
|
||||
->when($providerId, function ($query) use ($providerId) {
|
||||
return $query->where('id', '<>', $providerId);
|
||||
})
|
||||
->pluck('currencies');
|
||||
$activeExchangeRateProvider = [];
|
||||
|
||||
foreach ($activeExchangeRateProviders as $data) {
|
||||
if (is_array($data)) {
|
||||
for ($limit = 0; $limit < count($data); $limit++) {
|
||||
$activeExchangeRateProvider[] = $data[$limit];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$allExchangeRateProviders = ExchangeRateProvider::whereCompany()->pluck('currencies');
|
||||
$allExchangeRateProvider = [];
|
||||
|
||||
foreach ($allExchangeRateProviders as $data) {
|
||||
if (is_array($data)) {
|
||||
for ($limit = 0; $limit < count($data); $limit++) {
|
||||
$allExchangeRateProvider[] = $data[$limit];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return response()->json([
|
||||
'allUsedCurrencies' => $allExchangeRateProvider ? $allExchangeRateProvider : [],
|
||||
'activeUsedCurrencies' => $activeExchangeRateProvider ? $activeExchangeRateProvider : [],
|
||||
]);
|
||||
}
|
||||
|
||||
public function usedCurrenciesWithoutRate(Request $request)
|
||||
{
|
||||
$invoices = Invoice::where('exchange_rate', null)->pluck('currency_id')->toArray();
|
||||
$taxes = Tax::where('exchange_rate', null)->pluck('currency_id')->toArray();
|
||||
$estimates = Estimate::where('exchange_rate', null)->pluck('currency_id')->toArray();
|
||||
$payments = Payment::where('exchange_rate', null)->pluck('currency_id')->toArray();
|
||||
|
||||
$currencies = array_merge($invoices, $taxes, $estimates, $payments);
|
||||
|
||||
return response()->json([
|
||||
'currencies' => Currency::whereIn('id', $currencies)->get(),
|
||||
]);
|
||||
}
|
||||
|
||||
public function bulkUpdate(BulkExchangeRateRequest $request)
|
||||
{
|
||||
$bulkExchangeRate = CompanySetting::getSetting('bulk_exchange_rate_configured', $request->header('company'));
|
||||
|
||||
if ($bulkExchangeRate == 'NO') {
|
||||
if ($request->currencies) {
|
||||
foreach ($request->currencies as $currency) {
|
||||
$currency['exchange_rate'] = $currency['exchange_rate'] ?? 1;
|
||||
|
||||
$invoices = Invoice::where('currency_id', $currency['id'])->get();
|
||||
|
||||
if ($invoices) {
|
||||
foreach ($invoices as $invoice) {
|
||||
$invoice->update([
|
||||
'exchange_rate' => $currency['exchange_rate'],
|
||||
'base_discount_val' => $invoice->sub_total * $currency['exchange_rate'],
|
||||
'base_sub_total' => $invoice->sub_total * $currency['exchange_rate'],
|
||||
'base_total' => $invoice->total * $currency['exchange_rate'],
|
||||
'base_tax' => $invoice->tax * $currency['exchange_rate'],
|
||||
'base_due_amount' => $invoice->due_amount * $currency['exchange_rate'],
|
||||
]);
|
||||
|
||||
$this->updateItemsExchangeRate($invoice);
|
||||
}
|
||||
}
|
||||
|
||||
$estimates = Estimate::where('currency_id', $currency['id'])->get();
|
||||
|
||||
if ($estimates) {
|
||||
foreach ($estimates as $estimate) {
|
||||
$estimate->update([
|
||||
'exchange_rate' => $currency['exchange_rate'],
|
||||
'base_discount_val' => $estimate->sub_total * $currency['exchange_rate'],
|
||||
'base_sub_total' => $estimate->sub_total * $currency['exchange_rate'],
|
||||
'base_total' => $estimate->total * $currency['exchange_rate'],
|
||||
'base_tax' => $estimate->tax * $currency['exchange_rate'],
|
||||
]);
|
||||
|
||||
$this->updateItemsExchangeRate($estimate);
|
||||
}
|
||||
}
|
||||
|
||||
$taxes = Tax::where('currency_id', $currency['id'])->get();
|
||||
|
||||
if ($taxes) {
|
||||
foreach ($taxes as $tax) {
|
||||
$tax->base_amount = $tax->base_amount * $currency['exchange_rate'];
|
||||
$tax->save();
|
||||
}
|
||||
}
|
||||
|
||||
$payments = Payment::where('currency_id', $currency['id'])->get();
|
||||
|
||||
if ($payments) {
|
||||
foreach ($payments as $payment) {
|
||||
$payment->exchange_rate = $currency['exchange_rate'];
|
||||
$payment->base_amount = $payment->amount * $currency['exchange_rate'];
|
||||
$payment->save();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$settings = [
|
||||
'bulk_exchange_rate_configured' => 'YES',
|
||||
];
|
||||
|
||||
CompanySetting::setSettings($settings, $request->header('company'));
|
||||
|
||||
return response()->json([
|
||||
'success' => true,
|
||||
]);
|
||||
}
|
||||
|
||||
return response()->json([
|
||||
'error' => false,
|
||||
]);
|
||||
}
|
||||
|
||||
private function updateItemsExchangeRate($model): void
|
||||
{
|
||||
foreach ($model->items as $item) {
|
||||
$item->update([
|
||||
'exchange_rate' => $model->exchange_rate,
|
||||
'base_discount_val' => $item->discount_val * $model->exchange_rate,
|
||||
'base_price' => $item->price * $model->exchange_rate,
|
||||
'base_tax' => $item->tax * $model->exchange_rate,
|
||||
'base_total' => $item->total * $model->exchange_rate,
|
||||
]);
|
||||
|
||||
$this->updateTaxesExchangeRate($item);
|
||||
}
|
||||
|
||||
$this->updateTaxesExchangeRate($model);
|
||||
}
|
||||
|
||||
private function updateTaxesExchangeRate($model): void
|
||||
{
|
||||
if ($model->taxes()->exists()) {
|
||||
$model->taxes->map(function ($tax) use ($model) {
|
||||
$tax->update([
|
||||
'exchange_rate' => $model->exchange_rate,
|
||||
'base_amount' => $tax->amount * $model->exchange_rate,
|
||||
]);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Company\Expense;
|
||||
|
||||
use App\ExpensesCategory;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\ExpenseCategoryRequest;
|
||||
use App\Http\Resources\ExpenseCategoryResource;
|
||||
use App\Models\ExpenseCategory;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\Response;
|
||||
|
||||
class ExpenseCategoriesController extends Controller
|
||||
{
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*
|
||||
* @return Response
|
||||
*/
|
||||
public function index(Request $request)
|
||||
{
|
||||
$this->authorize('viewAny', ExpenseCategory::class);
|
||||
|
||||
$limit = $request->has('limit') ? $request->limit : 5;
|
||||
|
||||
$categories = ExpenseCategory::applyFilters($request->all())
|
||||
->whereCompany()
|
||||
->latest()
|
||||
->paginateData($limit);
|
||||
|
||||
return ExpenseCategoryResource::collection($categories);
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*
|
||||
* @param Request $request
|
||||
* @return Response
|
||||
*/
|
||||
public function store(ExpenseCategoryRequest $request)
|
||||
{
|
||||
$this->authorize('create', ExpenseCategory::class);
|
||||
|
||||
$category = ExpenseCategory::create($request->getExpenseCategoryPayload());
|
||||
|
||||
return new ExpenseCategoryResource($category);
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the specified resource.
|
||||
*
|
||||
* @return Response
|
||||
*/
|
||||
public function show(ExpenseCategory $category)
|
||||
{
|
||||
$this->authorize('view', $category);
|
||||
|
||||
return new ExpenseCategoryResource($category);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the specified resource in storage.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param ExpenseCategory $ExpenseCategory
|
||||
* @return Response
|
||||
*/
|
||||
public function update(ExpenseCategoryRequest $request, ExpenseCategory $category)
|
||||
{
|
||||
$this->authorize('update', $category);
|
||||
|
||||
$category->update($request->getExpenseCategoryPayload());
|
||||
|
||||
return new ExpenseCategoryResource($category);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified resource from storage.
|
||||
*
|
||||
* @param ExpensesCategory $category
|
||||
* @return Response
|
||||
*/
|
||||
public function destroy(ExpenseCategory $category)
|
||||
{
|
||||
$this->authorize('delete', $category);
|
||||
|
||||
if ($category->expenses() && $category->expenses()->count() > 0) {
|
||||
return respondJson('expense_attached', 'Expense Attached');
|
||||
}
|
||||
|
||||
$category->delete();
|
||||
|
||||
return response()->json([
|
||||
'success' => true,
|
||||
]);
|
||||
}
|
||||
}
|
||||
136
app/Http/Controllers/Company/Expense/ExpensesController.php
Normal file
136
app/Http/Controllers/Company/Expense/ExpensesController.php
Normal file
@@ -0,0 +1,136 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Company\Expense;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\DeleteExpensesRequest;
|
||||
use App\Http\Requests\ExpenseRequest;
|
||||
use App\Http\Requests\UploadExpenseReceiptRequest;
|
||||
use App\Http\Resources\ExpenseResource;
|
||||
use App\Models\Expense;
|
||||
use App\Services\ExpenseService;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class ExpensesController extends Controller
|
||||
{
|
||||
public function __construct(
|
||||
private readonly ExpenseService $expenseService,
|
||||
) {}
|
||||
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*
|
||||
* @return JsonResponse
|
||||
*/
|
||||
public function index(Request $request)
|
||||
{
|
||||
$this->authorize('viewAny', Expense::class);
|
||||
|
||||
$limit = $request->has('limit') ? $request->limit : 10;
|
||||
|
||||
$expenses = Expense::with('category', 'creator', 'fields')
|
||||
->whereCompany()
|
||||
->leftJoin('customers', 'customers.id', '=', 'expenses.customer_id')
|
||||
->join('expense_categories', 'expense_categories.id', '=', 'expenses.expense_category_id')
|
||||
->applyFilters($request->all())
|
||||
->select('expenses.*', 'expense_categories.name', 'customers.name as user_name')
|
||||
->paginateData($limit);
|
||||
|
||||
return ExpenseResource::collection($expenses)
|
||||
->additional(['meta' => [
|
||||
'expense_total_count' => Expense::whereCompany()->count(),
|
||||
]]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*
|
||||
* @return JsonResponse
|
||||
*/
|
||||
public function store(ExpenseRequest $request)
|
||||
{
|
||||
$this->authorize('create', Expense::class);
|
||||
|
||||
$expense = $this->expenseService->create($request);
|
||||
|
||||
return new ExpenseResource($expense);
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the specified resource.
|
||||
*
|
||||
* @return JsonResponse
|
||||
*/
|
||||
public function show(Expense $expense)
|
||||
{
|
||||
$this->authorize('view', $expense);
|
||||
|
||||
return new ExpenseResource($expense);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the specified resource in storage.
|
||||
*
|
||||
* @return JsonResponse
|
||||
*/
|
||||
public function update(ExpenseRequest $request, Expense $expense)
|
||||
{
|
||||
$this->authorize('update', $expense);
|
||||
|
||||
$this->expenseService->update($expense, $request);
|
||||
|
||||
return new ExpenseResource($expense);
|
||||
}
|
||||
|
||||
public function delete(DeleteExpensesRequest $request)
|
||||
{
|
||||
$this->authorize('delete multiple expenses');
|
||||
|
||||
$ids = Expense::whereCompany()
|
||||
->whereIn('id', $request->ids)
|
||||
->pluck('id');
|
||||
|
||||
Expense::destroy($ids);
|
||||
|
||||
return response()->json([
|
||||
'success' => true,
|
||||
]);
|
||||
}
|
||||
|
||||
public function showReceipt(Expense $expense)
|
||||
{
|
||||
$this->authorize('view', $expense);
|
||||
|
||||
if ($expense) {
|
||||
$media = $expense->getFirstMedia('receipts');
|
||||
|
||||
if ($media) {
|
||||
return response()->file($media->getPath());
|
||||
}
|
||||
|
||||
return respondJson('receipt_does_not_exist', 'Receipt does not exist.');
|
||||
}
|
||||
}
|
||||
|
||||
public function uploadReceipt(UploadExpenseReceiptRequest $request, Expense $expense)
|
||||
{
|
||||
$this->authorize('update', $expense);
|
||||
|
||||
$data = json_decode($request->attachment_receipt);
|
||||
|
||||
if ($data) {
|
||||
if ($request->type === 'edit') {
|
||||
$expense->clearMediaCollection('receipts');
|
||||
}
|
||||
|
||||
$expense->addMediaFromBase64($data->data)
|
||||
->usingFileName($data->name)
|
||||
->toMediaCollection('receipts');
|
||||
}
|
||||
|
||||
return response()->json([
|
||||
'success' => 'Expense receipts uploaded successfully',
|
||||
], 200);
|
||||
}
|
||||
}
|
||||
79
app/Http/Controllers/Company/General/BootstrapController.php
Normal file
79
app/Http/Controllers/Company/General/BootstrapController.php
Normal file
@@ -0,0 +1,79 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Company\General;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Resources\CompanyResource;
|
||||
use App\Http\Resources\UserResource;
|
||||
use App\Models\Company;
|
||||
use App\Models\CompanySetting;
|
||||
use App\Models\Currency;
|
||||
use App\Models\Module;
|
||||
use App\Models\Setting;
|
||||
use App\Traits\GeneratesMenuTrait;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Silber\Bouncer\BouncerFacade;
|
||||
|
||||
class BootstrapController extends Controller
|
||||
{
|
||||
use GeneratesMenuTrait;
|
||||
|
||||
/**
|
||||
* Handle the incoming request.
|
||||
*
|
||||
* @return JsonResponse
|
||||
*/
|
||||
public function __invoke(Request $request)
|
||||
{
|
||||
$current_user = $request->user();
|
||||
$current_user_settings = $current_user->getAllSettings();
|
||||
|
||||
$main_menu = $this->generateMenu('main_menu', $current_user);
|
||||
|
||||
$setting_menu = $this->generateMenu('setting_menu', $current_user);
|
||||
|
||||
$companies = $current_user->companies;
|
||||
|
||||
$current_company = Company::find($request->header('company'));
|
||||
|
||||
if ((! $current_company) || ($current_company && ! $current_user->hasCompany($current_company->id))) {
|
||||
$current_company = $current_user->companies()->first();
|
||||
}
|
||||
|
||||
$current_company_settings = CompanySetting::getAllSettings($current_company->id);
|
||||
|
||||
$current_company_currency = $current_company_settings->has('currency')
|
||||
? Currency::find($current_company_settings->get('currency'))
|
||||
: Currency::first();
|
||||
|
||||
BouncerFacade::refreshFor($current_user);
|
||||
|
||||
$global_settings = Setting::getSettings([
|
||||
'api_token',
|
||||
'admin_portal_theme',
|
||||
'admin_portal_logo',
|
||||
'login_page_logo',
|
||||
'login_page_heading',
|
||||
'login_page_description',
|
||||
'admin_page_title',
|
||||
'copyright_text',
|
||||
'save_pdf_to_disk',
|
||||
]);
|
||||
|
||||
return response()->json([
|
||||
'current_user' => new UserResource($current_user),
|
||||
'current_user_settings' => $current_user_settings,
|
||||
'current_user_abilities' => $current_user->getAbilities(),
|
||||
'companies' => CompanyResource::collection($companies),
|
||||
'current_company' => new CompanyResource($current_company),
|
||||
'current_company_settings' => $current_company_settings,
|
||||
'current_company_currency' => $current_company_currency,
|
||||
'config' => config('invoiceshelf'),
|
||||
'global_settings' => $global_settings,
|
||||
'main_menu' => $main_menu,
|
||||
'setting_menu' => $setting_menu,
|
||||
'modules' => Module::where('enabled', true)->pluck('name'),
|
||||
]);
|
||||
}
|
||||
}
|
||||
22
app/Http/Controllers/Company/General/ConfigController.php
Normal file
22
app/Http/Controllers/Company/General/ConfigController.php
Normal file
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Company\General;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\Response;
|
||||
|
||||
class ConfigController extends Controller
|
||||
{
|
||||
/**
|
||||
* Handle the incoming request.
|
||||
*
|
||||
* @return Response
|
||||
*/
|
||||
public function __invoke(Request $request)
|
||||
{
|
||||
return response()->json([
|
||||
$request->key => config('invoiceshelf.'.$request->key),
|
||||
]);
|
||||
}
|
||||
}
|
||||
33
app/Http/Controllers/Company/General/FormatsController.php
Normal file
33
app/Http/Controllers/Company/General/FormatsController.php
Normal file
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Company\General;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Support\Formatters\DateFormatter;
|
||||
use App\Support\Formatters\TimeFormatter;
|
||||
use App\Support\Formatters\TimeZones;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
|
||||
class FormatsController extends Controller
|
||||
{
|
||||
public function dateFormats(): JsonResponse
|
||||
{
|
||||
return response()->json([
|
||||
'date_formats' => DateFormatter::get_list(),
|
||||
]);
|
||||
}
|
||||
|
||||
public function timeFormats(): JsonResponse
|
||||
{
|
||||
return response()->json([
|
||||
'time_formats' => TimeFormatter::get_list(),
|
||||
]);
|
||||
}
|
||||
|
||||
public function timezones(): JsonResponse
|
||||
{
|
||||
return response()->json([
|
||||
'time_zones' => TimeZones::get_list(),
|
||||
]);
|
||||
}
|
||||
}
|
||||
108
app/Http/Controllers/Company/General/NotesController.php
Normal file
108
app/Http/Controllers/Company/General/NotesController.php
Normal file
@@ -0,0 +1,108 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Company\General;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\NotesRequest;
|
||||
use App\Http\Resources\NoteResource;
|
||||
use App\Models\Note;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\Response;
|
||||
|
||||
class NotesController extends Controller
|
||||
{
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*
|
||||
* @return Response
|
||||
*/
|
||||
public function index(Request $request)
|
||||
{
|
||||
$this->authorize('view notes');
|
||||
|
||||
$limit = $request->limit ?? 10;
|
||||
|
||||
$notes = Note::latest()
|
||||
->whereCompany()
|
||||
->applyFilters($request->all())
|
||||
->paginate($limit);
|
||||
|
||||
return NoteResource::collection($notes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*
|
||||
* @param Request $request
|
||||
* @return Response
|
||||
*/
|
||||
public function store(NotesRequest $request)
|
||||
{
|
||||
$this->authorize('manage notes');
|
||||
|
||||
$note = Note::create($request->getNotesPayload());
|
||||
|
||||
if ($note->is_default) {
|
||||
Note::where('id', '!=', $note->id)
|
||||
->where('type', $note->type)
|
||||
->where('is_default', true)
|
||||
->update([
|
||||
'is_default' => false,
|
||||
]);
|
||||
}
|
||||
|
||||
return new NoteResource($note);
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the specified resource.
|
||||
*
|
||||
* @return Response
|
||||
*/
|
||||
public function show(Note $note)
|
||||
{
|
||||
$this->authorize('view notes');
|
||||
|
||||
return new NoteResource($note);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the specified resource in storage.
|
||||
*
|
||||
* @param Request $request
|
||||
* @return Response
|
||||
*/
|
||||
public function update(NotesRequest $request, Note $note)
|
||||
{
|
||||
$this->authorize('manage notes');
|
||||
|
||||
$note->update($request->getNotesPayload());
|
||||
|
||||
if ($note->is_default) {
|
||||
Note::where('id', '!=', $note->id)
|
||||
->where('type', $note->type)
|
||||
->where('is_default', true)
|
||||
->update([
|
||||
'is_default' => false,
|
||||
]);
|
||||
}
|
||||
|
||||
return new NoteResource($note);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified resource from storage.
|
||||
*
|
||||
* @return Response
|
||||
*/
|
||||
public function destroy(Note $note)
|
||||
{
|
||||
$this->authorize('manage notes');
|
||||
|
||||
$note->delete();
|
||||
|
||||
return response()->json([
|
||||
'success' => true,
|
||||
]);
|
||||
}
|
||||
}
|
||||
50
app/Http/Controllers/Company/General/SearchController.php
Normal file
50
app/Http/Controllers/Company/General/SearchController.php
Normal file
@@ -0,0 +1,50 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Company\General;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Customer;
|
||||
use App\Models\User;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\Response;
|
||||
|
||||
class SearchController extends Controller
|
||||
{
|
||||
/**
|
||||
* Handle the incoming request.
|
||||
*
|
||||
* @return Response
|
||||
*/
|
||||
public function __invoke(Request $request)
|
||||
{
|
||||
$user = $request->user();
|
||||
|
||||
$customers = Customer::applyFilters($request->only(['search']))
|
||||
->whereCompany()
|
||||
->latest()
|
||||
->paginate(10);
|
||||
|
||||
if ($user->isOwner()) {
|
||||
$users = User::whereCompany()
|
||||
->applyFilters($request->only(['search']))
|
||||
->latest()
|
||||
->paginate(10);
|
||||
}
|
||||
|
||||
return response()->json([
|
||||
'customers' => $customers,
|
||||
'users' => $users ?? [],
|
||||
]);
|
||||
}
|
||||
|
||||
public function users(Request $request)
|
||||
{
|
||||
$this->authorize('create', User::class);
|
||||
|
||||
$users = User::whereEmail($request->email)
|
||||
->latest()
|
||||
->paginate(10);
|
||||
|
||||
return response()->json(['users' => $users]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Company\General;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Estimate;
|
||||
use App\Models\Invoice;
|
||||
use App\Models\Payment;
|
||||
use App\Services\SerialNumberService;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class SerialNumberController extends Controller
|
||||
{
|
||||
public function nextNumber(Request $request, Invoice $invoice, Estimate $estimate, Payment $payment): JsonResponse
|
||||
{
|
||||
$key = $request->key;
|
||||
$nextNumber = null;
|
||||
$serial = (new SerialNumberService)
|
||||
->setCompany($request->header('company'))
|
||||
->setCustomer($request->userId);
|
||||
|
||||
try {
|
||||
switch ($key) {
|
||||
case 'invoice':
|
||||
$nextNumber = $serial->setModel($invoice)
|
||||
->setModelObject($request->model_id)
|
||||
->getNextNumber();
|
||||
|
||||
break;
|
||||
|
||||
case 'estimate':
|
||||
$nextNumber = $serial->setModel($estimate)
|
||||
->setModelObject($request->model_id)
|
||||
->getNextNumber();
|
||||
|
||||
break;
|
||||
|
||||
case 'payment':
|
||||
$nextNumber = $serial->setModel($payment)
|
||||
->setModelObject($request->model_id)
|
||||
->getNextNumber();
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
return response()->json([
|
||||
'success' => false,
|
||||
]);
|
||||
}
|
||||
} catch (\Exception $exception) {
|
||||
return response()->json([
|
||||
'success' => false,
|
||||
'message' => $exception->getMessage(),
|
||||
]);
|
||||
}
|
||||
|
||||
return response()->json([
|
||||
'success' => true,
|
||||
'nextNumber' => $nextNumber,
|
||||
]);
|
||||
}
|
||||
|
||||
public function placeholders(Request $request): JsonResponse
|
||||
{
|
||||
if ($request->format) {
|
||||
$placeholders = SerialNumberService::getPlaceholders($request->format);
|
||||
} else {
|
||||
$placeholders = [];
|
||||
}
|
||||
|
||||
return response()->json([
|
||||
'success' => true,
|
||||
'placeholders' => $placeholders,
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Company\Invoice;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Invoice;
|
||||
use App\Services\Pdf\PdfTemplateUtils;
|
||||
use Illuminate\Auth\Access\AuthorizationException;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class InvoiceTemplatesController extends Controller
|
||||
{
|
||||
/**
|
||||
* Handle the incoming request.
|
||||
*
|
||||
*
|
||||
* @return JsonResponse
|
||||
*
|
||||
* @throws AuthorizationException
|
||||
*/
|
||||
public function __invoke(Request $request)
|
||||
{
|
||||
$this->authorize('viewAny', Invoice::class);
|
||||
|
||||
$invoiceTemplates = PdfTemplateUtils::getFormattedTemplates('invoice');
|
||||
|
||||
return response()->json([
|
||||
'invoiceTemplates' => $invoiceTemplates,
|
||||
]);
|
||||
}
|
||||
}
|
||||
160
app/Http/Controllers/Company/Invoice/InvoicesController.php
Normal file
160
app/Http/Controllers/Company/Invoice/InvoicesController.php
Normal file
@@ -0,0 +1,160 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Company\Invoice;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests;
|
||||
use App\Http\Requests\DeleteInvoiceRequest;
|
||||
use App\Http\Requests\SendInvoiceRequest;
|
||||
use App\Http\Resources\InvoiceResource;
|
||||
use App\Jobs\GenerateInvoicePdfJob;
|
||||
use App\Models\Invoice;
|
||||
use App\Services\InvoiceService;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Mail\Markdown;
|
||||
|
||||
class InvoicesController extends Controller
|
||||
{
|
||||
public function __construct(
|
||||
private readonly InvoiceService $invoiceService,
|
||||
) {}
|
||||
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*
|
||||
* @return JsonResponse
|
||||
*/
|
||||
public function index(Request $request)
|
||||
{
|
||||
$this->authorize('viewAny', Invoice::class);
|
||||
|
||||
$limit = $request->input('limit', 10);
|
||||
|
||||
$invoices = Invoice::whereCompany()
|
||||
->applyFilters($request->all())
|
||||
->with('customer')
|
||||
->latest()
|
||||
->paginateData($limit);
|
||||
|
||||
return InvoiceResource::collection($invoices)
|
||||
->additional(['meta' => [
|
||||
'invoice_total_count' => Invoice::whereCompany()->count(),
|
||||
]]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*
|
||||
* @param Request $request
|
||||
* @return JsonResponse
|
||||
*/
|
||||
public function store(Requests\InvoicesRequest $request)
|
||||
{
|
||||
$this->authorize('create', Invoice::class);
|
||||
|
||||
$invoice = $this->invoiceService->create($request);
|
||||
|
||||
if ($request->has('invoiceSend')) {
|
||||
$this->invoiceService->send($invoice, $request->only(['subject', 'body']));
|
||||
}
|
||||
|
||||
GenerateInvoicePdfJob::dispatch($invoice);
|
||||
|
||||
return new InvoiceResource($invoice);
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the specified resource.
|
||||
*
|
||||
* @return JsonResponse
|
||||
*/
|
||||
public function show(Request $request, Invoice $invoice)
|
||||
{
|
||||
$this->authorize('view', $invoice);
|
||||
|
||||
return new InvoiceResource($invoice);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the specified resource in storage.
|
||||
*
|
||||
* @param Request $request
|
||||
* @return JsonResponse
|
||||
*/
|
||||
public function update(Requests\InvoicesRequest $request, Invoice $invoice)
|
||||
{
|
||||
$this->authorize('update', $invoice);
|
||||
|
||||
$invoice = $this->invoiceService->update($invoice, $request);
|
||||
|
||||
GenerateInvoicePdfJob::dispatch($invoice, true);
|
||||
|
||||
return new InvoiceResource($invoice);
|
||||
}
|
||||
|
||||
/**
|
||||
* delete the specified resources in storage.
|
||||
*
|
||||
* @param Request $request
|
||||
* @return JsonResponse
|
||||
*/
|
||||
public function delete(DeleteInvoiceRequest $request)
|
||||
{
|
||||
$this->authorize('delete multiple invoices');
|
||||
|
||||
$ids = Invoice::whereCompany()
|
||||
->whereIn('id', $request->ids)
|
||||
->pluck('id');
|
||||
|
||||
$this->invoiceService->delete($ids);
|
||||
|
||||
return response()->json([
|
||||
'success' => true,
|
||||
]);
|
||||
}
|
||||
|
||||
public function send(SendInvoiceRequest $request, Invoice $invoice)
|
||||
{
|
||||
$this->authorize('send invoice', $invoice);
|
||||
|
||||
$this->invoiceService->send($invoice, $request->all());
|
||||
|
||||
return response()->json([
|
||||
'success' => true,
|
||||
]);
|
||||
}
|
||||
|
||||
public function sendPreview(SendInvoiceRequest $request, Invoice $invoice)
|
||||
{
|
||||
$this->authorize('send invoice', $invoice);
|
||||
|
||||
$markdown = new Markdown(view(), config('mail.markdown'));
|
||||
|
||||
$data = $this->invoiceService->sendInvoiceData($invoice, $request->all());
|
||||
$data['url'] = $invoice->invoicePdfUrl;
|
||||
|
||||
return $markdown->render('emails.send.invoice', ['data' => $data]);
|
||||
}
|
||||
|
||||
public function clone(Request $request, Invoice $invoice)
|
||||
{
|
||||
$this->authorize('view', $invoice);
|
||||
$this->authorize('create', Invoice::class);
|
||||
|
||||
$newInvoice = $this->invoiceService->clone($invoice);
|
||||
|
||||
return new InvoiceResource($newInvoice);
|
||||
}
|
||||
|
||||
public function changeStatus(Request $request, Invoice $invoice)
|
||||
{
|
||||
$this->authorize('send invoice', $invoice);
|
||||
|
||||
$this->invoiceService->changeStatus($invoice, $request->status);
|
||||
|
||||
return response()->json([
|
||||
'success' => true,
|
||||
]);
|
||||
}
|
||||
}
|
||||
103
app/Http/Controllers/Company/Item/ItemsController.php
Normal file
103
app/Http/Controllers/Company/Item/ItemsController.php
Normal file
@@ -0,0 +1,103 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Company\Item;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests;
|
||||
use App\Http\Requests\DeleteItemsRequest;
|
||||
use App\Http\Resources\ItemResource;
|
||||
use App\Models\Item;
|
||||
use App\Models\TaxType;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class ItemsController extends Controller
|
||||
{
|
||||
/**
|
||||
* Retrieve a list of existing Items.
|
||||
*
|
||||
* @return JsonResponse
|
||||
*/
|
||||
public function index(Request $request)
|
||||
{
|
||||
$this->authorize('viewAny', Item::class);
|
||||
|
||||
$limit = $request->has('limit') ? $request->limit : 10;
|
||||
|
||||
$items = Item::whereCompany()
|
||||
->leftJoin('units', 'units.id', '=', 'items.unit_id')
|
||||
->applyFilters($request->all())
|
||||
->select('items.*', 'units.name as unit_name')
|
||||
->latest()
|
||||
->paginateData($limit);
|
||||
|
||||
return ItemResource::collection($items)
|
||||
->additional(['meta' => [
|
||||
'tax_types' => TaxType::whereCompany()->latest()->get(),
|
||||
'item_total_count' => Item::whereCompany()->count(),
|
||||
]]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create Item.
|
||||
*
|
||||
* @param App\Http\Requests\ItemsRequest $request
|
||||
* @return JsonResponse
|
||||
*/
|
||||
public function store(Requests\ItemsRequest $request)
|
||||
{
|
||||
$this->authorize('create', Item::class);
|
||||
|
||||
$item = Item::createItem($request);
|
||||
|
||||
return new ItemResource($item);
|
||||
}
|
||||
|
||||
/**
|
||||
* get an existing Item.
|
||||
*
|
||||
* @return JsonResponse
|
||||
*/
|
||||
public function show(Item $item)
|
||||
{
|
||||
$this->authorize('view', $item);
|
||||
|
||||
return new ItemResource($item);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update an existing Item.
|
||||
*
|
||||
* @param App\Http\Requests\ItemsRequest $request
|
||||
* @return JsonResponse
|
||||
*/
|
||||
public function update(Requests\ItemsRequest $request, Item $item)
|
||||
{
|
||||
$this->authorize('update', $item);
|
||||
|
||||
$item = $item->updateItem($request);
|
||||
|
||||
return new ItemResource($item);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a list of existing Items.
|
||||
*
|
||||
* @param Request $request
|
||||
* @return JsonResponse
|
||||
*/
|
||||
public function delete(DeleteItemsRequest $request)
|
||||
{
|
||||
$this->authorize('delete multiple items');
|
||||
|
||||
$ids = Item::whereCompany()
|
||||
->whereIn('id', $request->ids)
|
||||
->pluck('id');
|
||||
|
||||
Item::destroy($ids);
|
||||
|
||||
return response()->json([
|
||||
'success' => true,
|
||||
]);
|
||||
}
|
||||
}
|
||||
94
app/Http/Controllers/Company/Item/UnitsController.php
Normal file
94
app/Http/Controllers/Company/Item/UnitsController.php
Normal file
@@ -0,0 +1,94 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Company\Item;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\UnitRequest;
|
||||
use App\Http\Resources\UnitResource;
|
||||
use App\Models\Unit;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\Response;
|
||||
|
||||
class UnitsController extends Controller
|
||||
{
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*
|
||||
* @return Response
|
||||
*/
|
||||
public function index(Request $request)
|
||||
{
|
||||
$this->authorize('viewAny', Unit::class);
|
||||
|
||||
$limit = $request->has('limit') ? $request->limit : 5;
|
||||
|
||||
$units = Unit::applyFilters($request->all())
|
||||
->whereCompany()
|
||||
->latest()
|
||||
->paginateData($limit);
|
||||
|
||||
return UnitResource::collection($units);
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*
|
||||
* @param Request $request
|
||||
* @return Response
|
||||
*/
|
||||
public function store(UnitRequest $request)
|
||||
{
|
||||
$this->authorize('create', Unit::class);
|
||||
|
||||
$unit = Unit::create($request->getUnitPayload());
|
||||
|
||||
return new UnitResource($unit);
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the specified resource.
|
||||
*
|
||||
* @return Response
|
||||
*/
|
||||
public function show(Unit $unit)
|
||||
{
|
||||
$this->authorize('view', $unit);
|
||||
|
||||
return new UnitResource($unit);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the specified resource in storage.
|
||||
*
|
||||
* @param Request $request
|
||||
* @return Response
|
||||
*/
|
||||
public function update(UnitRequest $request, Unit $unit)
|
||||
{
|
||||
$this->authorize('update', $unit);
|
||||
|
||||
$unit->update($request->getUnitPayload());
|
||||
|
||||
return new UnitResource($unit);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified resource from storage.
|
||||
*
|
||||
* @return Response
|
||||
*/
|
||||
public function destroy(Unit $unit)
|
||||
{
|
||||
$this->authorize('delete', $unit);
|
||||
|
||||
if ($unit->items()->exists()) {
|
||||
return respondJson('items_attached', 'Items Attached');
|
||||
}
|
||||
|
||||
$unit->delete();
|
||||
|
||||
return response()->json([
|
||||
'success' => 'Unit deleted successfully',
|
||||
]);
|
||||
}
|
||||
}
|
||||
44
app/Http/Controllers/Company/Mobile/AuthController.php
Normal file
44
app/Http/Controllers/Company/Mobile/AuthController.php
Normal file
@@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Company\Mobile;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\LoginRequest;
|
||||
use App\Models\User;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
|
||||
class AuthController extends Controller
|
||||
{
|
||||
public function login(LoginRequest $request)
|
||||
{
|
||||
$user = User::where('email', $request->username)->first();
|
||||
|
||||
if (! $user || ! Hash::check($request->password, $user->password)) {
|
||||
throw ValidationException::withMessages([
|
||||
'email' => ['The provided credentials are incorrect.'],
|
||||
]);
|
||||
}
|
||||
|
||||
return response()->json([
|
||||
'type' => 'Bearer',
|
||||
'token' => $user->createToken($request->device_name)->plainTextToken,
|
||||
]);
|
||||
}
|
||||
|
||||
public function logout(Request $request)
|
||||
{
|
||||
$request->user()->currentAccessToken()->delete();
|
||||
|
||||
return response()->json([
|
||||
'success' => true,
|
||||
]);
|
||||
}
|
||||
|
||||
public function check()
|
||||
{
|
||||
return Auth::check();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Company\Payment;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\PaymentMethodRequest;
|
||||
use App\Http\Resources\PaymentMethodResource;
|
||||
use App\Models\PaymentMethod;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\Response;
|
||||
|
||||
class PaymentMethodsController extends Controller
|
||||
{
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*
|
||||
* @return Response
|
||||
*/
|
||||
public function index(Request $request)
|
||||
{
|
||||
$this->authorize('viewAny', PaymentMethod::class);
|
||||
|
||||
$limit = $request->has('limit') ? $request->limit : 5;
|
||||
|
||||
$paymentMethods = PaymentMethod::applyFilters($request->all())
|
||||
->where('type', PaymentMethod::TYPE_GENERAL)
|
||||
->whereCompany()
|
||||
->latest()
|
||||
->paginateData($limit);
|
||||
|
||||
return PaymentMethodResource::collection($paymentMethods);
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*
|
||||
* @param Request $request
|
||||
* @return Response
|
||||
*/
|
||||
public function store(PaymentMethodRequest $request)
|
||||
{
|
||||
$this->authorize('create', PaymentMethod::class);
|
||||
|
||||
$paymentMethod = PaymentMethod::createPaymentMethod($request);
|
||||
|
||||
return new PaymentMethodResource($paymentMethod);
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the specified resource.
|
||||
*
|
||||
* @return Response
|
||||
*/
|
||||
public function show(PaymentMethod $paymentMethod)
|
||||
{
|
||||
$this->authorize('view', $paymentMethod);
|
||||
|
||||
return new PaymentMethodResource($paymentMethod);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the specified resource in storage.
|
||||
*
|
||||
* @param Request $request
|
||||
* @return Response
|
||||
*/
|
||||
public function update(PaymentMethodRequest $request, PaymentMethod $paymentMethod)
|
||||
{
|
||||
$this->authorize('update', $paymentMethod);
|
||||
|
||||
$paymentMethod->update($request->getPaymentMethodPayload());
|
||||
|
||||
return new PaymentMethodResource($paymentMethod);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified resource from storage.
|
||||
*
|
||||
* @return Response
|
||||
*/
|
||||
public function destroy(PaymentMethod $paymentMethod)
|
||||
{
|
||||
$this->authorize('delete', $paymentMethod);
|
||||
|
||||
if ($paymentMethod->payments()->exists()) {
|
||||
return respondJson('payments_attached', 'Payments Attached.');
|
||||
}
|
||||
|
||||
if ($paymentMethod->expenses()->exists()) {
|
||||
return respondJson('expenses_attached', 'Expenses Attached.');
|
||||
}
|
||||
|
||||
$paymentMethod->delete();
|
||||
|
||||
return response()->json([
|
||||
'success' => 'Payment method deleted successfully',
|
||||
]);
|
||||
}
|
||||
}
|
||||
114
app/Http/Controllers/Company/Payment/PaymentsController.php
Normal file
114
app/Http/Controllers/Company/Payment/PaymentsController.php
Normal file
@@ -0,0 +1,114 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Company\Payment;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\DeletePaymentsRequest;
|
||||
use App\Http\Requests\PaymentRequest;
|
||||
use App\Http\Requests\SendPaymentRequest;
|
||||
use App\Http\Resources\PaymentResource;
|
||||
use App\Models\Payment;
|
||||
use App\Services\PaymentService;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\Response;
|
||||
use Illuminate\Mail\Markdown;
|
||||
|
||||
class PaymentsController extends Controller
|
||||
{
|
||||
public function __construct(
|
||||
private readonly PaymentService $paymentService,
|
||||
) {}
|
||||
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*
|
||||
* @return Response
|
||||
*/
|
||||
public function index(Request $request)
|
||||
{
|
||||
$this->authorize('viewAny', Payment::class);
|
||||
|
||||
$limit = $request->has('limit') ? $request->limit : 10;
|
||||
|
||||
$payments = Payment::whereCompany()
|
||||
->join('customers', 'customers.id', '=', 'payments.customer_id')
|
||||
->leftJoin('invoices', 'invoices.id', '=', 'payments.invoice_id')
|
||||
->leftJoin('payment_methods', 'payment_methods.id', '=', 'payments.payment_method_id')
|
||||
->applyFilters($request->all())
|
||||
->select('payments.*', 'customers.name', 'invoices.invoice_number', 'payment_methods.name as payment_mode')
|
||||
->latest()
|
||||
->paginateData($limit);
|
||||
|
||||
return PaymentResource::collection($payments)
|
||||
->additional(['meta' => [
|
||||
'payment_total_count' => Payment::whereCompany()->count(),
|
||||
]]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*
|
||||
* @param Request $request
|
||||
* @return Response
|
||||
*/
|
||||
public function store(PaymentRequest $request)
|
||||
{
|
||||
$this->authorize('create', Payment::class);
|
||||
|
||||
$payment = $this->paymentService->create($request);
|
||||
|
||||
return new PaymentResource($payment);
|
||||
}
|
||||
|
||||
public function show(Request $request, Payment $payment)
|
||||
{
|
||||
$this->authorize('view', $payment);
|
||||
|
||||
return new PaymentResource($payment);
|
||||
}
|
||||
|
||||
public function update(PaymentRequest $request, Payment $payment)
|
||||
{
|
||||
$this->authorize('update', $payment);
|
||||
|
||||
$payment = $this->paymentService->update($payment, $request);
|
||||
|
||||
return new PaymentResource($payment);
|
||||
}
|
||||
|
||||
public function delete(DeletePaymentsRequest $request)
|
||||
{
|
||||
$this->authorize('delete multiple payments');
|
||||
|
||||
$ids = Payment::whereCompany()
|
||||
->whereIn('id', $request->ids)
|
||||
->pluck('id');
|
||||
|
||||
$this->paymentService->delete($ids);
|
||||
|
||||
return response()->json([
|
||||
'success' => true,
|
||||
]);
|
||||
}
|
||||
|
||||
public function send(SendPaymentRequest $request, Payment $payment)
|
||||
{
|
||||
$this->authorize('send payment', $payment);
|
||||
|
||||
$response = $this->paymentService->send($payment, $request->all());
|
||||
|
||||
return response()->json($response);
|
||||
}
|
||||
|
||||
public function sendPreview(Request $request, Payment $payment)
|
||||
{
|
||||
$this->authorize('send payment', $payment);
|
||||
|
||||
$markdown = new Markdown(view(), config('mail.markdown'));
|
||||
|
||||
$data = $this->paymentService->sendPaymentData($payment, $request->all());
|
||||
$data['url'] = $payment->paymentPdfUrl;
|
||||
|
||||
return $markdown->render('emails.send.payment', ['data' => $data]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Company\RecurringInvoice;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\RecurringInvoiceRequest;
|
||||
use App\Http\Resources\RecurringInvoiceResource;
|
||||
use App\Models\RecurringInvoice;
|
||||
use App\Services\RecurringInvoiceService;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\Response;
|
||||
|
||||
class RecurringInvoiceController extends Controller
|
||||
{
|
||||
public function __construct(
|
||||
private readonly RecurringInvoiceService $recurringInvoiceService,
|
||||
) {}
|
||||
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*
|
||||
* @return Response
|
||||
*/
|
||||
public function index(Request $request)
|
||||
{
|
||||
$this->authorize('viewAny', RecurringInvoice::class);
|
||||
|
||||
$limit = $request->has('limit') ? $request->limit : 10;
|
||||
|
||||
$recurringInvoices = RecurringInvoice::whereCompany()
|
||||
->applyFilters($request->all())
|
||||
->paginateData($limit);
|
||||
|
||||
return RecurringInvoiceResource::collection($recurringInvoices)
|
||||
->additional(['meta' => [
|
||||
'recurring_invoice_total_count' => RecurringInvoice::whereCompany()->count(),
|
||||
]]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*
|
||||
* @param Request $request
|
||||
* @return Response
|
||||
*/
|
||||
public function store(RecurringInvoiceRequest $request)
|
||||
{
|
||||
$this->authorize('create', RecurringInvoice::class);
|
||||
|
||||
$recurringInvoice = $this->recurringInvoiceService->create($request);
|
||||
|
||||
return new RecurringInvoiceResource($recurringInvoice);
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the specified resource.
|
||||
*
|
||||
* @return Response
|
||||
*/
|
||||
public function show(RecurringInvoice $recurringInvoice)
|
||||
{
|
||||
$this->authorize('view', $recurringInvoice);
|
||||
|
||||
return new RecurringInvoiceResource($recurringInvoice);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the specified resource in storage.
|
||||
*
|
||||
* @param Request $request
|
||||
* @return Response
|
||||
*/
|
||||
public function update(RecurringInvoiceRequest $request, RecurringInvoice $recurringInvoice)
|
||||
{
|
||||
$this->authorize('update', $recurringInvoice);
|
||||
|
||||
$this->recurringInvoiceService->update($recurringInvoice, $request);
|
||||
|
||||
return new RecurringInvoiceResource($recurringInvoice);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified resource from storage.
|
||||
*
|
||||
* @param RecurringInvoice $recurringInvoice
|
||||
* @return Response
|
||||
*/
|
||||
public function delete(Request $request)
|
||||
{
|
||||
$this->authorize('delete multiple recurring invoices');
|
||||
|
||||
$ids = RecurringInvoice::whereCompany()
|
||||
->whereIn('id', $request->ids)
|
||||
->pluck('id');
|
||||
|
||||
$this->recurringInvoiceService->delete($ids);
|
||||
|
||||
return response()->json([
|
||||
'success' => true,
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Company\RecurringInvoice;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\RecurringInvoice;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class RecurringInvoiceFrequencyController extends Controller
|
||||
{
|
||||
public function __invoke(Request $request)
|
||||
{
|
||||
$nextInvoiceAt = RecurringInvoice::getNextInvoiceDate($request->frequency, $request->starts_at);
|
||||
|
||||
return response()->json([
|
||||
'success' => true,
|
||||
'next_invoice_at' => $nextInvoiceAt,
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Company\Report;
|
||||
|
||||
use App\Facades\Pdf;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Company;
|
||||
use App\Models\CompanySetting;
|
||||
use App\Models\Currency;
|
||||
use App\Models\Customer;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\App;
|
||||
|
||||
class CustomerSalesReportController extends Controller
|
||||
{
|
||||
/**
|
||||
* Handle the incoming request.
|
||||
*
|
||||
* @param string $hash
|
||||
* @return JsonResponse
|
||||
*/
|
||||
public function __invoke(Request $request, $hash)
|
||||
{
|
||||
$company = Company::where('unique_hash', $hash)->first();
|
||||
|
||||
$this->authorize('view report', $company);
|
||||
|
||||
$locale = CompanySetting::getSetting('language', $company->id);
|
||||
|
||||
App::setLocale($locale);
|
||||
|
||||
$start = Carbon::createFromFormat('Y-m-d', $request->from_date);
|
||||
$end = Carbon::createFromFormat('Y-m-d', $request->to_date);
|
||||
|
||||
$customers = Customer::with(['invoices' => function ($query) use ($start, $end) {
|
||||
$query->whereBetween(
|
||||
'invoice_date',
|
||||
[$start->format('Y-m-d'), $end->format('Y-m-d')]
|
||||
);
|
||||
}])
|
||||
->where('company_id', $company->id)
|
||||
->applyInvoiceFilters($request->only(['from_date', 'to_date']))
|
||||
->get();
|
||||
|
||||
$totalAmount = 0;
|
||||
foreach ($customers as $customer) {
|
||||
$customerTotalAmount = 0;
|
||||
foreach ($customer->invoices as $invoice) {
|
||||
$customerTotalAmount += $invoice->base_total;
|
||||
}
|
||||
$customer->totalAmount = $customerTotalAmount;
|
||||
$totalAmount += $customerTotalAmount;
|
||||
}
|
||||
|
||||
$dateFormat = CompanySetting::getSetting('carbon_date_format', $company->id);
|
||||
$from_date = Carbon::createFromFormat('Y-m-d', $request->from_date)->translatedFormat($dateFormat);
|
||||
$to_date = Carbon::createFromFormat('Y-m-d', $request->to_date)->translatedFormat($dateFormat);
|
||||
$currency = Currency::findOrFail(CompanySetting::getSetting('currency', $company->id));
|
||||
|
||||
$colors = [
|
||||
'primary_text_color',
|
||||
'heading_text_color',
|
||||
'section_heading_text_color',
|
||||
'border_color',
|
||||
'body_text_color',
|
||||
'footer_text_color',
|
||||
'footer_total_color',
|
||||
'footer_bg_color',
|
||||
'date_text_color',
|
||||
];
|
||||
|
||||
$colorSettings = CompanySetting::whereIn('option', $colors)
|
||||
->whereCompany($company->id)
|
||||
->get();
|
||||
|
||||
view()->share([
|
||||
'customers' => $customers,
|
||||
'totalAmount' => $totalAmount,
|
||||
'colorSettings' => $colorSettings,
|
||||
'company' => $company,
|
||||
'from_date' => $from_date,
|
||||
'to_date' => $to_date,
|
||||
'currency' => $currency,
|
||||
]);
|
||||
|
||||
$pdf = Pdf::loadView('app.pdf.reports.sales-customers');
|
||||
|
||||
if ($request->has('preview')) {
|
||||
return view('app.pdf.reports.sales-customers');
|
||||
}
|
||||
|
||||
if ($request->has('download')) {
|
||||
return $pdf->download();
|
||||
}
|
||||
|
||||
return $pdf->stream();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Company\Report;
|
||||
|
||||
use App\Facades\Pdf;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Company;
|
||||
use App\Models\CompanySetting;
|
||||
use App\Models\Currency;
|
||||
use App\Models\Expense;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\App;
|
||||
|
||||
class ExpensesReportController extends Controller
|
||||
{
|
||||
/**
|
||||
* Handle the incoming request.
|
||||
*
|
||||
* @param string $hash
|
||||
* @return JsonResponse
|
||||
*/
|
||||
public function __invoke(Request $request, $hash)
|
||||
{
|
||||
$company = Company::where('unique_hash', $hash)->first();
|
||||
|
||||
$this->authorize('view report', $company);
|
||||
|
||||
$locale = CompanySetting::getSetting('language', $company->id);
|
||||
|
||||
App::setLocale($locale);
|
||||
|
||||
$expenseCategories = Expense::with('category')
|
||||
->whereCompanyId($company->id)
|
||||
->applyFilters($request->only(['from_date', 'to_date']))
|
||||
->expensesAttributes()
|
||||
->get();
|
||||
$totalAmount = 0;
|
||||
foreach ($expenseCategories as $category) {
|
||||
$totalAmount += $category->total_amount;
|
||||
}
|
||||
|
||||
$dateFormat = CompanySetting::getSetting('carbon_date_format', $company->id);
|
||||
$from_date = Carbon::createFromFormat('Y-m-d', $request->from_date)->translatedFormat($dateFormat);
|
||||
$to_date = Carbon::createFromFormat('Y-m-d', $request->to_date)->translatedFormat($dateFormat);
|
||||
$currency = Currency::findOrFail(CompanySetting::getSetting('currency', $company->id));
|
||||
|
||||
$colors = [
|
||||
'primary_text_color',
|
||||
'heading_text_color',
|
||||
'section_heading_text_color',
|
||||
'border_color',
|
||||
'body_text_color',
|
||||
'footer_text_color',
|
||||
'footer_total_color',
|
||||
'footer_bg_color',
|
||||
'date_text_color',
|
||||
];
|
||||
$colorSettings = CompanySetting::whereIn('option', $colors)
|
||||
->whereCompany($company->id)
|
||||
->get();
|
||||
|
||||
view()->share([
|
||||
'expenseCategories' => $expenseCategories,
|
||||
'colorSettings' => $colorSettings,
|
||||
'totalExpense' => $totalAmount,
|
||||
'company' => $company,
|
||||
'from_date' => $from_date,
|
||||
'to_date' => $to_date,
|
||||
'currency' => $currency,
|
||||
]);
|
||||
$pdf = Pdf::loadView('app.pdf.reports.expenses');
|
||||
|
||||
if ($request->has('preview')) {
|
||||
return view('app.pdf.reports.expenses');
|
||||
}
|
||||
|
||||
if ($request->has('download')) {
|
||||
return $pdf->download();
|
||||
}
|
||||
|
||||
return $pdf->stream();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Company\Report;
|
||||
|
||||
use App\Facades\Pdf;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Company;
|
||||
use App\Models\CompanySetting;
|
||||
use App\Models\Currency;
|
||||
use App\Models\InvoiceItem;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\App;
|
||||
|
||||
class ItemSalesReportController extends Controller
|
||||
{
|
||||
/**
|
||||
* Handle the incoming request.
|
||||
*
|
||||
* @param string $hash
|
||||
* @return JsonResponse
|
||||
*/
|
||||
public function __invoke(Request $request, $hash)
|
||||
{
|
||||
$company = Company::where('unique_hash', $hash)->first();
|
||||
|
||||
$this->authorize('view report', $company);
|
||||
|
||||
$locale = CompanySetting::getSetting('language', $company->id);
|
||||
|
||||
App::setLocale($locale);
|
||||
|
||||
$items = InvoiceItem::whereCompany($company->id)
|
||||
->applyInvoiceFilters($request->only(['from_date', 'to_date']))
|
||||
->itemAttributes()
|
||||
->get();
|
||||
|
||||
$totalAmount = 0;
|
||||
foreach ($items as $item) {
|
||||
$totalAmount += $item->total_amount;
|
||||
}
|
||||
|
||||
$dateFormat = CompanySetting::getSetting('carbon_date_format', $company->id);
|
||||
$from_date = Carbon::createFromFormat('Y-m-d', $request->from_date)->translatedFormat($dateFormat);
|
||||
$to_date = Carbon::createFromFormat('Y-m-d', $request->to_date)->translatedFormat($dateFormat);
|
||||
$currency = Currency::findOrFail(CompanySetting::getSetting('currency', $company->id));
|
||||
|
||||
$colors = [
|
||||
'primary_text_color',
|
||||
'heading_text_color',
|
||||
'section_heading_text_color',
|
||||
'border_color',
|
||||
'body_text_color',
|
||||
'footer_text_color',
|
||||
'footer_total_color',
|
||||
'footer_bg_color',
|
||||
'date_text_color',
|
||||
];
|
||||
$colorSettings = CompanySetting::whereIn('option', $colors)
|
||||
->whereCompany($company->id)
|
||||
->get();
|
||||
|
||||
view()->share([
|
||||
'items' => $items,
|
||||
'colorSettings' => $colorSettings,
|
||||
'totalAmount' => $totalAmount,
|
||||
'company' => $company,
|
||||
'from_date' => $from_date,
|
||||
'to_date' => $to_date,
|
||||
'currency' => $currency,
|
||||
]);
|
||||
$pdf = Pdf::loadView('app.pdf.reports.sales-items');
|
||||
|
||||
if ($request->has('preview')) {
|
||||
return view('app.pdf.reports.sales-items');
|
||||
}
|
||||
|
||||
if ($request->has('download')) {
|
||||
return $pdf->download();
|
||||
}
|
||||
|
||||
return $pdf->stream();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Company\Report;
|
||||
|
||||
use App\Facades\Pdf;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Company;
|
||||
use App\Models\CompanySetting;
|
||||
use App\Models\Currency;
|
||||
use App\Models\Expense;
|
||||
use App\Models\Payment;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\App;
|
||||
|
||||
class ProfitLossReportController extends Controller
|
||||
{
|
||||
/**
|
||||
* Handle the incoming request.
|
||||
*
|
||||
* @param string $hash
|
||||
* @return JsonResponse
|
||||
*/
|
||||
public function __invoke(Request $request, $hash)
|
||||
{
|
||||
$company = Company::where('unique_hash', $hash)->first();
|
||||
|
||||
$this->authorize('view report', $company);
|
||||
|
||||
$locale = CompanySetting::getSetting('language', $company->id);
|
||||
|
||||
App::setLocale($locale);
|
||||
|
||||
$paymentsAmount = Payment::whereCompanyId($company->id)
|
||||
->applyFilters($request->only(['from_date', 'to_date']))
|
||||
->sum('base_amount');
|
||||
|
||||
$expenseCategories = Expense::with('category')
|
||||
->whereCompanyId($company->id)
|
||||
->applyFilters($request->only(['from_date', 'to_date']))
|
||||
->expensesAttributes()
|
||||
->get();
|
||||
|
||||
$totalAmount = 0;
|
||||
foreach ($expenseCategories as $category) {
|
||||
$totalAmount += $category->total_amount;
|
||||
}
|
||||
|
||||
$dateFormat = CompanySetting::getSetting('carbon_date_format', $company->id);
|
||||
$from_date = Carbon::createFromFormat('Y-m-d', $request->from_date)->translatedFormat($dateFormat);
|
||||
$to_date = Carbon::createFromFormat('Y-m-d', $request->to_date)->translatedFormat($dateFormat);
|
||||
$currency = Currency::findOrFail(CompanySetting::getSetting('currency', $company->id));
|
||||
|
||||
$colors = [
|
||||
'primary_text_color',
|
||||
'heading_text_color',
|
||||
'section_heading_text_color',
|
||||
'border_color',
|
||||
'body_text_color',
|
||||
'footer_text_color',
|
||||
'footer_total_color',
|
||||
'footer_bg_color',
|
||||
'date_text_color',
|
||||
];
|
||||
$colorSettings = CompanySetting::whereIn('option', $colors)
|
||||
->whereCompany($company->id)
|
||||
->get();
|
||||
|
||||
view()->share([
|
||||
'company' => $company,
|
||||
'income' => $paymentsAmount,
|
||||
'expenseCategories' => $expenseCategories,
|
||||
'totalExpense' => $totalAmount,
|
||||
'colorSettings' => $colorSettings,
|
||||
'company' => $company,
|
||||
'from_date' => $from_date,
|
||||
'to_date' => $to_date,
|
||||
'currency' => $currency,
|
||||
]);
|
||||
$pdf = Pdf::loadView('app.pdf.reports.profit-loss');
|
||||
|
||||
if ($request->has('preview')) {
|
||||
return view('app.pdf.reports.profit-loss');
|
||||
}
|
||||
|
||||
if ($request->has('download')) {
|
||||
return $pdf->download();
|
||||
}
|
||||
|
||||
return $pdf->stream();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Company\Report;
|
||||
|
||||
use App\Facades\Pdf;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Company;
|
||||
use App\Models\CompanySetting;
|
||||
use App\Models\Currency;
|
||||
use App\Models\Tax;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\App;
|
||||
|
||||
class TaxSummaryReportController extends Controller
|
||||
{
|
||||
/**
|
||||
* Handle the incoming request.
|
||||
*
|
||||
* @param string $hash
|
||||
* @return JsonResponse
|
||||
*/
|
||||
public function __invoke(Request $request, $hash)
|
||||
{
|
||||
$company = Company::where('unique_hash', $hash)->first();
|
||||
|
||||
$this->authorize('view report', $company);
|
||||
|
||||
$locale = CompanySetting::getSetting('language', $company->id);
|
||||
|
||||
App::setLocale($locale);
|
||||
|
||||
$taxTypes = Tax::with('taxType', 'invoice', 'invoiceItem')
|
||||
->whereCompany($company->id)
|
||||
->whereInvoicesFilters($request->only(['from_date', 'to_date']))
|
||||
->taxAttributes()
|
||||
->get();
|
||||
|
||||
$totalAmount = 0;
|
||||
foreach ($taxTypes as $taxType) {
|
||||
$totalAmount += $taxType->total_tax_amount;
|
||||
}
|
||||
|
||||
$dateFormat = CompanySetting::getSetting('carbon_date_format', $company->id);
|
||||
$from_date = Carbon::createFromFormat('Y-m-d', $request->from_date)->translatedFormat($dateFormat);
|
||||
$to_date = Carbon::createFromFormat('Y-m-d', $request->to_date)->translatedFormat($dateFormat);
|
||||
$currency = Currency::findOrFail(CompanySetting::getSetting('currency', $company->id));
|
||||
|
||||
$colors = [
|
||||
'primary_text_color',
|
||||
'heading_text_color',
|
||||
'section_heading_text_color',
|
||||
'border_color',
|
||||
'body_text_color',
|
||||
'footer_text_color',
|
||||
'footer_total_color',
|
||||
'footer_bg_color',
|
||||
'date_text_color',
|
||||
];
|
||||
|
||||
$colorSettings = CompanySetting::whereIn('option', $colors)
|
||||
->whereCompany($company->id)
|
||||
->get();
|
||||
|
||||
view()->share([
|
||||
'taxTypes' => $taxTypes,
|
||||
'totalTaxAmount' => $totalAmount,
|
||||
'colorSettings' => $colorSettings,
|
||||
'company' => $company,
|
||||
'from_date' => $from_date,
|
||||
'to_date' => $to_date,
|
||||
'currency' => $currency,
|
||||
]);
|
||||
|
||||
$pdf = Pdf::loadView('app.pdf.reports.tax-summary');
|
||||
|
||||
if ($request->has('preview')) {
|
||||
return view('app.pdf.reports.tax-summary');
|
||||
}
|
||||
|
||||
if ($request->has('download')) {
|
||||
return $pdf->download();
|
||||
}
|
||||
|
||||
return $pdf->stream();
|
||||
}
|
||||
}
|
||||
20
app/Http/Controllers/Company/Role/AbilitiesController.php
Normal file
20
app/Http/Controllers/Company/Role/AbilitiesController.php
Normal file
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Company\Role;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\Response;
|
||||
|
||||
class AbilitiesController extends Controller
|
||||
{
|
||||
/**
|
||||
* Handle the incoming request.
|
||||
*
|
||||
* @return Response
|
||||
*/
|
||||
public function __invoke(Request $request)
|
||||
{
|
||||
return response()->json(['abilities' => config('abilities.abilities')]);
|
||||
}
|
||||
}
|
||||
120
app/Http/Controllers/Company/Role/RolesController.php
Normal file
120
app/Http/Controllers/Company/Role/RolesController.php
Normal file
@@ -0,0 +1,120 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Company\Role;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\RoleRequest;
|
||||
use App\Http\Resources\RoleResource;
|
||||
use App\Models\User;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\Response;
|
||||
use Silber\Bouncer\BouncerFacade;
|
||||
use Silber\Bouncer\Database\Role;
|
||||
|
||||
class RolesController extends Controller
|
||||
{
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*
|
||||
* @return Response
|
||||
*/
|
||||
public function index(Request $request)
|
||||
{
|
||||
$this->authorize('viewAny', Role::class);
|
||||
|
||||
$roles = Role::when($request->has('orderByField'), function ($query) use ($request) {
|
||||
return $query->orderBy($request['orderByField'], $request['orderBy']);
|
||||
})
|
||||
->when($request->company_id, function ($query) use ($request) {
|
||||
return $query->where('scope', $request->company_id);
|
||||
})
|
||||
->get();
|
||||
|
||||
return RoleResource::collection($roles);
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*
|
||||
* @param Request $request
|
||||
* @return Response
|
||||
*/
|
||||
public function store(RoleRequest $request)
|
||||
{
|
||||
$this->authorize('create', Role::class);
|
||||
|
||||
$role = Role::create($request->getRolePayload());
|
||||
|
||||
$this->syncAbilities($request, $role);
|
||||
|
||||
return new RoleResource($role);
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the specified resource.
|
||||
*
|
||||
* @param \Spatie\Permission\Models\Role $role
|
||||
* @return Response
|
||||
*/
|
||||
public function show(Role $role)
|
||||
{
|
||||
$this->authorize('view', $role);
|
||||
|
||||
return new RoleResource($role);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the specified resource in storage.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param \Spatie\Permission\Models\Role $role
|
||||
* @return Response
|
||||
*/
|
||||
public function update(RoleRequest $request, Role $role)
|
||||
{
|
||||
$this->authorize('update', $role);
|
||||
|
||||
$role->update($request->getRolePayload());
|
||||
|
||||
$this->syncAbilities($request, $role);
|
||||
|
||||
return new RoleResource($role);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified resource from storage.
|
||||
*
|
||||
* @param \Spatie\Permission\Models\Role $role
|
||||
* @return Response
|
||||
*/
|
||||
public function destroy(Role $role)
|
||||
{
|
||||
$this->authorize('delete', $role);
|
||||
|
||||
$users = User::whereIs($role->name)->get()->toArray();
|
||||
|
||||
if (! empty($users)) {
|
||||
return respondJson('role_attached_to_users', 'Roles Attached to user');
|
||||
}
|
||||
|
||||
$role->delete();
|
||||
|
||||
return response()->json([
|
||||
'success' => true,
|
||||
]);
|
||||
}
|
||||
|
||||
private function syncAbilities(RoleRequest $request, $role)
|
||||
{
|
||||
foreach (config('abilities.abilities') as $ability) {
|
||||
$check = array_search($ability['ability'], array_column($request->abilities, 'ability'));
|
||||
if ($check !== false) {
|
||||
BouncerFacade::allow($role)->to($ability['ability'], $ability['model']);
|
||||
} else {
|
||||
BouncerFacade::disallow($role)->to($ability['ability'], $ability['model']);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
53
app/Http/Controllers/Company/Settings/CompanyController.php
Normal file
53
app/Http/Controllers/Company/Settings/CompanyController.php
Normal file
@@ -0,0 +1,53 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Company\Settings;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\CompanyLogoRequest;
|
||||
use App\Http\Requests\CompanyRequest;
|
||||
use App\Http\Resources\CompanyResource;
|
||||
use App\Models\Company;
|
||||
|
||||
class CompanyController extends Controller
|
||||
{
|
||||
public function updateCompany(CompanyRequest $request)
|
||||
{
|
||||
$company = Company::find($request->header('company'));
|
||||
|
||||
$this->authorize('manage company', $company);
|
||||
|
||||
$company->update($request->getCompanyPayload());
|
||||
|
||||
$company->address()->updateOrCreate(['company_id' => $company->id], $request->address);
|
||||
|
||||
return new CompanyResource($company);
|
||||
}
|
||||
|
||||
public function uploadCompanyLogo(CompanyLogoRequest $request)
|
||||
{
|
||||
$company = Company::find($request->header('company'));
|
||||
|
||||
$this->authorize('manage company', $company);
|
||||
|
||||
$data = json_decode($request->company_logo);
|
||||
|
||||
if (isset($request->is_company_logo_removed) && (bool) $request->is_company_logo_removed) {
|
||||
$company->clearMediaCollection('logo');
|
||||
}
|
||||
if ($data) {
|
||||
$company = Company::find($request->header('company'));
|
||||
|
||||
if ($company) {
|
||||
$company->clearMediaCollection('logo');
|
||||
|
||||
$company->addMediaFromBase64($data->data)
|
||||
->usingFileName($data->name)
|
||||
->toMediaCollection('logo');
|
||||
}
|
||||
}
|
||||
|
||||
return response()->json([
|
||||
'success' => true,
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Company\Settings;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Company;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\Response;
|
||||
|
||||
class CompanyCurrencyCheckTransactionsController extends Controller
|
||||
{
|
||||
/**
|
||||
* Handle the incoming request.
|
||||
*
|
||||
* @return Response
|
||||
*/
|
||||
public function __invoke(Request $request)
|
||||
{
|
||||
$company = Company::find($request->header('company'));
|
||||
|
||||
$this->authorize('manage company', $company);
|
||||
|
||||
return response()->json([
|
||||
'has_transactions' => $company->hasTransactions(),
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,155 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Company\Settings;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Mail\TestMail;
|
||||
use App\Models\CompanySetting;
|
||||
use App\Services\CompanyMailConfigService;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Mail;
|
||||
|
||||
class CompanyMailConfigurationController extends Controller
|
||||
{
|
||||
public function getDefaultConfig(Request $request): JsonResponse
|
||||
{
|
||||
$mailConfig = [
|
||||
'from_name' => config('mail.from.name'),
|
||||
'from_mail' => config('mail.from.address'),
|
||||
];
|
||||
|
||||
return response()->json($mailConfig);
|
||||
}
|
||||
|
||||
public function getMailConfig(Request $request): JsonResponse
|
||||
{
|
||||
$companyId = $request->header('company');
|
||||
|
||||
$useCustom = CompanySetting::getSetting('use_custom_mail_config', $companyId) ?? 'NO';
|
||||
$driver = CompanySetting::getSetting('company_mail_driver', $companyId) ?? '';
|
||||
|
||||
$data = [
|
||||
'use_custom_mail_config' => $useCustom,
|
||||
'mail_driver' => $driver,
|
||||
'from_name' => CompanySetting::getSetting('company_from_name', $companyId) ?? '',
|
||||
'from_mail' => CompanySetting::getSetting('company_from_mail', $companyId) ?? '',
|
||||
];
|
||||
|
||||
switch ($driver) {
|
||||
case 'smtp':
|
||||
$data = array_merge($data, [
|
||||
'mail_host' => CompanySetting::getSetting('company_mail_host', $companyId) ?? '',
|
||||
'mail_port' => CompanySetting::getSetting('company_mail_port', $companyId) ?? '',
|
||||
'mail_username' => CompanySetting::getSetting('company_mail_username', $companyId) ?? '',
|
||||
'mail_password' => CompanySetting::getSetting('company_mail_password', $companyId) ?? '',
|
||||
'mail_encryption' => CompanySetting::getSetting('company_mail_encryption', $companyId) ?? 'none',
|
||||
'mail_scheme' => CompanySetting::getSetting('company_mail_scheme', $companyId) ?? '',
|
||||
'mail_url' => CompanySetting::getSetting('company_mail_url', $companyId) ?? '',
|
||||
'mail_timeout' => CompanySetting::getSetting('company_mail_timeout', $companyId) ?? '',
|
||||
'mail_local_domain' => CompanySetting::getSetting('company_mail_local_domain', $companyId) ?? '',
|
||||
]);
|
||||
break;
|
||||
|
||||
case 'mailgun':
|
||||
$data = array_merge($data, [
|
||||
'mail_mailgun_domain' => CompanySetting::getSetting('company_mail_mailgun_domain', $companyId) ?? '',
|
||||
'mail_mailgun_secret' => CompanySetting::getSetting('company_mail_mailgun_secret', $companyId) ?? '',
|
||||
'mail_mailgun_endpoint' => CompanySetting::getSetting('company_mail_mailgun_endpoint', $companyId) ?? 'api.mailgun.net',
|
||||
'mail_mailgun_scheme' => CompanySetting::getSetting('company_mail_mailgun_scheme', $companyId) ?? 'https',
|
||||
]);
|
||||
break;
|
||||
|
||||
case 'ses':
|
||||
$data = array_merge($data, [
|
||||
'mail_ses_key' => CompanySetting::getSetting('company_mail_ses_key', $companyId) ?? '',
|
||||
'mail_ses_secret' => CompanySetting::getSetting('company_mail_ses_secret', $companyId) ?? '',
|
||||
'mail_ses_region' => CompanySetting::getSetting('company_mail_ses_region', $companyId) ?? 'us-east-1',
|
||||
]);
|
||||
break;
|
||||
|
||||
case 'sendmail':
|
||||
$data = array_merge($data, [
|
||||
'mail_sendmail_path' => CompanySetting::getSetting('company_mail_sendmail_path', $companyId) ?? '/usr/sbin/sendmail -bs -i',
|
||||
]);
|
||||
break;
|
||||
}
|
||||
|
||||
return response()->json($data);
|
||||
}
|
||||
|
||||
public function saveMailConfig(Request $request): JsonResponse
|
||||
{
|
||||
$this->authorize('owner only');
|
||||
|
||||
$companyId = $request->header('company');
|
||||
$driver = $request->get('mail_driver', '');
|
||||
|
||||
$settings = [
|
||||
'use_custom_mail_config' => $request->get('use_custom_mail_config', 'NO'),
|
||||
'company_mail_driver' => $driver,
|
||||
'company_from_name' => $request->get('from_name', ''),
|
||||
'company_from_mail' => $request->get('from_mail', ''),
|
||||
];
|
||||
|
||||
switch ($driver) {
|
||||
case 'smtp':
|
||||
$settings = array_merge($settings, [
|
||||
'company_mail_host' => $request->get('mail_host', ''),
|
||||
'company_mail_port' => $request->get('mail_port', ''),
|
||||
'company_mail_username' => $request->get('mail_username', ''),
|
||||
'company_mail_password' => $request->get('mail_password', ''),
|
||||
'company_mail_encryption' => $request->get('mail_encryption', 'none'),
|
||||
'company_mail_scheme' => $request->get('mail_scheme', ''),
|
||||
'company_mail_url' => $request->get('mail_url', ''),
|
||||
'company_mail_timeout' => $request->get('mail_timeout', ''),
|
||||
'company_mail_local_domain' => $request->get('mail_local_domain', ''),
|
||||
]);
|
||||
break;
|
||||
|
||||
case 'mailgun':
|
||||
$settings = array_merge($settings, [
|
||||
'company_mail_mailgun_domain' => $request->get('mail_mailgun_domain', ''),
|
||||
'company_mail_mailgun_secret' => $request->get('mail_mailgun_secret', ''),
|
||||
'company_mail_mailgun_endpoint' => $request->get('mail_mailgun_endpoint', 'api.mailgun.net'),
|
||||
'company_mail_mailgun_scheme' => $request->get('mail_mailgun_scheme', 'https'),
|
||||
]);
|
||||
break;
|
||||
|
||||
case 'ses':
|
||||
$settings = array_merge($settings, [
|
||||
'company_mail_ses_key' => $request->get('mail_ses_key', ''),
|
||||
'company_mail_ses_secret' => $request->get('mail_ses_secret', ''),
|
||||
'company_mail_ses_region' => $request->get('mail_ses_region', 'us-east-1'),
|
||||
]);
|
||||
break;
|
||||
|
||||
case 'sendmail':
|
||||
$settings = array_merge($settings, [
|
||||
'company_mail_sendmail_path' => $request->get('mail_sendmail_path', '/usr/sbin/sendmail -bs -i'),
|
||||
]);
|
||||
break;
|
||||
}
|
||||
|
||||
CompanySetting::setSettings($settings, $companyId);
|
||||
|
||||
return response()->json(['success' => true]);
|
||||
}
|
||||
|
||||
public function testMailConfig(Request $request): JsonResponse
|
||||
{
|
||||
$this->authorize('owner only');
|
||||
|
||||
$this->validate($request, [
|
||||
'to' => 'required|email',
|
||||
'subject' => 'required',
|
||||
'message' => 'required',
|
||||
]);
|
||||
|
||||
CompanyMailConfigService::apply($request->header('company'));
|
||||
|
||||
Mail::to($request->to)->send(new TestMail($request->subject, $request->message));
|
||||
|
||||
return response()->json(['success' => true]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Company\Settings;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\GetSettingsRequest;
|
||||
use App\Http\Requests\UpdateSettingsRequest;
|
||||
use App\Models\Company;
|
||||
use App\Models\CompanySetting;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Support\Arr;
|
||||
|
||||
class CompanySettingsController extends Controller
|
||||
{
|
||||
public function show(GetSettingsRequest $request): JsonResponse
|
||||
{
|
||||
$settings = CompanySetting::getSettings((array) $request->settings, $request->header('company'));
|
||||
|
||||
return response()->json($settings);
|
||||
}
|
||||
|
||||
public function update(UpdateSettingsRequest $request): JsonResponse
|
||||
{
|
||||
$company = Company::find($request->header('company'));
|
||||
$this->authorize('manage company', $company);
|
||||
|
||||
$data = $request->settings;
|
||||
|
||||
if (
|
||||
Arr::exists($data, 'currency') &&
|
||||
(CompanySetting::getSetting('currency', $company->id) !== $data['currency']) &&
|
||||
$company->hasTransactions()
|
||||
) {
|
||||
return response()->json([
|
||||
'success' => false,
|
||||
'message' => 'Cannot update company currency after transactions are created.',
|
||||
]);
|
||||
}
|
||||
|
||||
CompanySetting::setSettings($data, $request->header('company'));
|
||||
|
||||
return response()->json([
|
||||
'success' => true,
|
||||
]);
|
||||
}
|
||||
}
|
||||
95
app/Http/Controllers/Company/Settings/TaxTypesController.php
Normal file
95
app/Http/Controllers/Company/Settings/TaxTypesController.php
Normal file
@@ -0,0 +1,95 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Company\Settings;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\TaxTypeRequest;
|
||||
use App\Http\Resources\TaxTypeResource;
|
||||
use App\Models\TaxType;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\Response;
|
||||
|
||||
class TaxTypesController extends Controller
|
||||
{
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*
|
||||
* @return Response
|
||||
*/
|
||||
public function index(Request $request)
|
||||
{
|
||||
$this->authorize('viewAny', TaxType::class);
|
||||
|
||||
$limit = $request->has('limit') ? $request->limit : 5;
|
||||
|
||||
$taxTypes = TaxType::applyFilters($request->all())
|
||||
->where('type', TaxType::TYPE_GENERAL)
|
||||
->whereCompany()
|
||||
->latest()
|
||||
->paginateData($limit);
|
||||
|
||||
return TaxTypeResource::collection($taxTypes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*
|
||||
* @param Request $request
|
||||
* @return Response
|
||||
*/
|
||||
public function store(TaxTypeRequest $request)
|
||||
{
|
||||
$this->authorize('create', TaxType::class);
|
||||
|
||||
$taxType = TaxType::create($request->getTaxTypePayload());
|
||||
|
||||
return new TaxTypeResource($taxType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the specified resource.
|
||||
*
|
||||
* @return Response
|
||||
*/
|
||||
public function show(TaxType $taxType)
|
||||
{
|
||||
$this->authorize('view', $taxType);
|
||||
|
||||
return new TaxTypeResource($taxType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the specified resource in storage.
|
||||
*
|
||||
* @param Request $request
|
||||
* @return Response
|
||||
*/
|
||||
public function update(TaxTypeRequest $request, TaxType $taxType)
|
||||
{
|
||||
$this->authorize('update', $taxType);
|
||||
|
||||
$taxType->update($request->getTaxTypePayload());
|
||||
|
||||
return new TaxTypeResource($taxType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified resource from storage.
|
||||
*
|
||||
* @return Response
|
||||
*/
|
||||
public function destroy(TaxType $taxType)
|
||||
{
|
||||
$this->authorize('delete', $taxType);
|
||||
|
||||
if ($taxType->taxes() && $taxType->taxes()->count() > 0) {
|
||||
return respondJson('taxes_attached', 'Taxes Attached.');
|
||||
}
|
||||
|
||||
$taxType->delete();
|
||||
|
||||
return response()->json([
|
||||
'success' => true,
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Company\Settings;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\AvatarRequest;
|
||||
use App\Http\Requests\ProfileRequest;
|
||||
use App\Http\Resources\UserResource;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class UserProfileController extends Controller
|
||||
{
|
||||
public function show(Request $request)
|
||||
{
|
||||
return new UserResource($request->user());
|
||||
}
|
||||
|
||||
public function update(ProfileRequest $request)
|
||||
{
|
||||
$user = $request->user();
|
||||
|
||||
$user->update($request->validated());
|
||||
|
||||
return new UserResource($user);
|
||||
}
|
||||
|
||||
public function uploadAvatar(AvatarRequest $request)
|
||||
{
|
||||
$user = auth()->user();
|
||||
|
||||
if (isset($request->is_admin_avatar_removed) && (bool) $request->is_admin_avatar_removed) {
|
||||
$user->clearMediaCollection('admin_avatar');
|
||||
}
|
||||
if ($user && $request->hasFile('admin_avatar')) {
|
||||
$user->clearMediaCollection('admin_avatar');
|
||||
|
||||
$user->addMediaFromRequest('admin_avatar')
|
||||
->toMediaCollection('admin_avatar');
|
||||
}
|
||||
|
||||
if ($user && $request->has('avatar')) {
|
||||
$data = json_decode($request->avatar);
|
||||
$user->clearMediaCollection('admin_avatar');
|
||||
|
||||
$user->addMediaFromBase64($data->data)
|
||||
->usingFileName($data->name)
|
||||
->toMediaCollection('admin_avatar');
|
||||
}
|
||||
|
||||
return new UserResource($user);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Company\Settings;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\GetSettingsRequest;
|
||||
use App\Http\Requests\UpdateSettingsRequest;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
|
||||
class UserSettingsController extends Controller
|
||||
{
|
||||
public function show(GetSettingsRequest $request): JsonResponse
|
||||
{
|
||||
$user = $request->user();
|
||||
|
||||
return response()->json($user->getSettings((array) $request->settings));
|
||||
}
|
||||
|
||||
public function update(UpdateSettingsRequest $request): JsonResponse
|
||||
{
|
||||
$user = $request->user();
|
||||
|
||||
$user->setSettings($request->settings);
|
||||
|
||||
return response()->json([
|
||||
'success' => true,
|
||||
]);
|
||||
}
|
||||
}
|
||||
103
app/Http/Controllers/Company/Users/UsersController.php
Normal file
103
app/Http/Controllers/Company/Users/UsersController.php
Normal file
@@ -0,0 +1,103 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Company\Users;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\DeleteUserRequest;
|
||||
use App\Http\Requests\UserRequest;
|
||||
use App\Http\Resources\UserResource;
|
||||
use App\Models\User;
|
||||
use App\Services\UserService;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class UsersController extends Controller
|
||||
{
|
||||
public function __construct(
|
||||
private readonly UserService $userService,
|
||||
) {}
|
||||
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*
|
||||
* @return JsonResponse
|
||||
*/
|
||||
public function index(Request $request)
|
||||
{
|
||||
$this->authorize('viewAny', User::class);
|
||||
|
||||
$limit = $request->has('limit') ? $request->limit : 10;
|
||||
|
||||
$user = $request->user();
|
||||
|
||||
$users = User::whereCompany()
|
||||
->applyFilters($request->all())
|
||||
->where('id', '<>', $user->id)
|
||||
->latest()
|
||||
->paginate($limit);
|
||||
|
||||
return UserResource::collection($users)
|
||||
->additional(['meta' => [
|
||||
'user_total_count' => User::whereCompany()->count(),
|
||||
]]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*
|
||||
* @return JsonResponse
|
||||
*/
|
||||
public function store(UserRequest $request)
|
||||
{
|
||||
$this->authorize('create', User::class);
|
||||
|
||||
$user = $this->userService->create($request);
|
||||
|
||||
return new UserResource($user);
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the specified resource.
|
||||
*
|
||||
* @return JsonResponse
|
||||
*/
|
||||
public function show(User $user)
|
||||
{
|
||||
$this->authorize('view', $user);
|
||||
|
||||
return new UserResource($user);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the specified resource in storage.
|
||||
*
|
||||
* @return JsonResponse
|
||||
*/
|
||||
public function update(UserRequest $request, User $user)
|
||||
{
|
||||
$this->authorize('update', $user);
|
||||
|
||||
$this->userService->update($user, $request);
|
||||
|
||||
return new UserResource($user);
|
||||
}
|
||||
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*
|
||||
* @param Request $request
|
||||
* @return JsonResponse
|
||||
*/
|
||||
public function delete(DeleteUserRequest $request)
|
||||
{
|
||||
$this->authorize('delete multiple users', User::class);
|
||||
|
||||
if ($request->users) {
|
||||
$this->userService->delete($request->users);
|
||||
}
|
||||
|
||||
return response()->json([
|
||||
'success' => true,
|
||||
]);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user