Compare commits

...

123 Commits
5.0.6 ... 6.0.4

Author SHA1 Message Date
2383e89daa new build 604 2022-02-17 13:48:06 +05:30
6529fa1892 Merge branch 'fix-send-invoice-issue' into 'master'
fix send invoices and payments issues

See merge request mohit.panjvani/crater-web!1443
2022-02-17 08:15:40 +00:00
eef74fd2fc Merge branch 'change-logout-request' into 'master'
fixed customer logout error

See merge request mohit.panjvani/crater-web!1445
2022-02-17 08:14:43 +00:00
2f69b6fa71 fixed customer logout error 2022-02-17 12:39:10 +05:30
7170fb0cef fix send invoices and payments issues 2022-02-16 18:59:49 +05:30
db7a084a19 Merge branch 'set-default-country' into 'master'
set "United States" as default country for company in installation wizard

See merge request mohit.panjvani/crater-web!1442
2022-02-16 09:09:03 +00:00
e24a89fe39 set "United States" as default country for company in installtion wizard 2022-02-16 12:05:08 +05:30
6a3e9e132f fix formatting 2022-02-16 11:19:30 +05:30
68575b69b9 new build 603 2022-02-16 10:47:32 +05:30
8da5f99511 Merge branch 'master' 2022-02-16 10:44:08 +05:30
912dbdc1c5 Merge branch 'fix_all_customer_load' into 'master'
Fix all customer load

See merge request mohit.panjvani/crater-web!1435
2022-02-16 05:13:53 +00:00
771d396bfb Merge branch 'master' of gitlab.com:mohit.panjvani/crater-web into fix_all_customer_load 2022-02-15 18:41:57 +05:30
30dc428b1a apply scroll to load data changes in customer and fixed search with scroll to load data issue in estimate, invoice, recurring invoice and payments 2022-02-15 18:41:05 +05:30
6f7555bdce add 603 update migration 2022-02-15 17:30:33 +05:30
13cbb5439f fix search pagination 2022-02-15 13:01:29 +05:30
a0cd12913d fix template selection issue when image is not loaded 2022-02-15 12:16:01 +05:30
67e93dcb00 Merge branch 'mark-as-default-template' into 'master'
added mark as default changes in estimate and invoice template

See merge request mohit.panjvani/crater-web!1440
2022-02-15 06:16:57 +00:00
7427f8a4ac new build 2022-02-15 11:44:39 +05:30
10ceaa0e2c Merge branch 'master' 2022-02-15 11:40:59 +05:30
15256a19db Merge branch 'fix-download-expense-issue' into 'master'
fixed uploaded attachment not removed

See merge request mohit.panjvani/crater-web!1441
2022-02-15 06:10:04 +00:00
8ba84f68c7 fixed uploaded attachment not removed 2022-02-15 06:10:04 +00:00
9e23f9b9b1 fix search issues 2022-02-15 11:32:30 +05:30
7f4cdfffc6 New Crowdin updates (#791)
* New translations en.json (Romanian)

* New translations en.json (Slovak)

* New translations en.json (Hindi)

* New translations en.json (Latvian)

* New translations en.json (Croatian)

* New translations en.json (Persian)

* New translations en.json (Indonesian)

* New translations en.json (Portuguese, Brazilian)

* New translations en.json (Vietnamese)

* New translations en.json (Chinese Traditional)

* New translations en.json (Turkish)

* New translations en.json (Swedish)

* New translations en.json (Slovenian)

* New translations en.json (Russian)

* New translations en.json (French)

* New translations en.json (Portuguese)

* New translations en.json (Polish)

* New translations en.json (Dutch)

* New translations en.json (Lithuanian)

* New translations en.json (Japanese)

* New translations en.json (Italian)

* New translations en.json (Finnish)

* New translations en.json (Greek)

* New translations en.json (German)

* New translations en.json (Czech)

* New translations en.json (Arabic)

* New translations en.json (Spanish)

* New translations en.json (Serbian (Latin))

* New translations en.json (Portuguese, Brazilian)

* New translations en.json (Portuguese)

* New translations en.json (German)
2022-02-15 11:03:54 +05:30
c9d6824f8c Fixed the "Download Expenses File" URL (#785)
* Fixed the download PDF URL

Added the "/reports" prefix to the "Download PDF" Button of the Create.vue file. Now the download redirect works correctly.

Fixed with @SpyrosKoustas.

* Fixed the missing "/reports" prefix

Added the missing "/reports" prefix so that the project must not be rebuilt.

Fixed with @Dimitris-Provatas

Co-authored-by: Spyros Georg Koustas <spyros.koustas@hotmail.com>
2022-02-15 11:00:31 +05:30
84f5890294 Merge branch 'fix_all_customer_load' 2022-02-15 10:51:54 +05:30
ab8089fe98 Merge branch 'master' into fix_all_customer_load 2022-02-15 10:45:50 +05:30
383ba65d7c Merge branch 'master' of https://github.com/bytefury/crater 2022-02-15 10:45:08 +05:30
f34dac9d3f Merge branch 'fix-recurring-invoice-issue' into 'master'
fixed send invoice modal not open in recurring invoice

See merge request mohit.panjvani/crater-web!1439
2022-02-15 05:13:40 +00:00
c3965613b5 Merge branch 'change-logout-request' into 'master'
change from "GET" to "POST" request for logout user or customer

See merge request mohit.panjvani/crater-web!1438
2022-02-15 05:13:22 +00:00
c07e309918 rename variable name 2022-02-14 15:16:26 +05:30
35e71ec110 fix select cutoff issue on invoice create 2022-02-14 14:28:28 +05:30
82dbee4794 Update Crowdin configuration file 2022-02-14 12:08:04 +05:30
d883e89819 fix formatting 2022-02-14 11:24:59 +05:30
00133d66c2 added mark as default changes in estimate and invoice template 2022-02-11 12:23:36 +05:30
e8a88dbad3 change customer logout route method 2022-02-11 09:51:41 +05:30
2b7028b7c8 changed route method 2022-02-11 09:39:11 +05:30
513d43d92f Merge branch 'master' 2022-02-10 11:50:40 +05:30
b781f11175 Merge branch 'master' of https://github.com/bytefury/crater 2022-02-10 11:50:13 +05:30
ca1aa604e3 fixed send modal not open in recurring invoice 2022-02-08 16:27:26 +05:30
e1e1157f2d change from "GET" to "POST" request for logout user or customer 2022-02-08 12:38:52 +05:30
3f2c774f91 refactor and apply scroll to load data in estimates, invoices and payments 2022-02-08 11:57:47 +05:30
9448677dad #773 PDF download naming (#778) 2022-02-08 07:40:14 +05:30
9709489c66 Merge branch 'fix-dashboard-issue' into 'master'
fix dashboard issue

See merge request mohit.panjvani/crater-web!1437
2022-02-07 12:28:53 +00:00
2fcc87180f fix dashboard issue 2022-02-05 18:16:10 +05:30
0c77562d0e minor refactor 2022-02-05 13:31:06 +05:30
5f53138dc5 fix: Poppins semi-bold font 404 error (#771) 2022-02-04 18:18:14 +05:30
2019e9be03 Merge branch 'text-align-extension' into 'master'
Add extension-text-align

See merge request mohit.panjvani/crater-web!1434
2022-02-03 13:36:54 +00:00
938e6f2a9f Merge branch 'fix-expense-receipt' into 'master'
fix receipt not uploading in expense

See merge request mohit.panjvani/crater-web!1436
2022-02-03 12:51:02 +00:00
c82dc94252 fix receipt not uploading in expense 2022-02-03 11:39:18 +05:30
c6b36d78b9 updated customer and category added in first in dropdown list 2022-02-02 18:57:38 +05:30
1d402e0143 add scroll to load invoices and fixed limited category and customer issue in payment and expense 2022-02-02 18:51:32 +05:30
75a0ed1ffc Add extension-text-align 2022-02-02 16:30:19 +05:30
577c015d14 Merge branch 'remove-link' into 'master'
remove links

See merge request mohit.panjvani/crater-web!1428
2022-02-02 09:33:41 +00:00
760f4566aa Customer view field resolve fix (#757)
* fixed customer view field resolve

* fixed customer view field resolve estimate payment
2022-01-29 00:07:26 +05:30
d7ec554eba Merge branch 'admin-portal-logo' into 'master'
add admin portal logo

See merge request mohit.panjvani/crater-web!1427
2022-01-28 07:11:54 +00:00
c194e98a7b add admin portal logo 2022-01-28 07:11:54 +00:00
6a34708a37 Update french translation (#723)
Missing translations
2022-01-27 17:24:03 +05:30
ab863a8d88 Added Czech language (#702) 2022-01-27 17:23:37 +05:30
f594556de0 Merge branch 'invoice-custom-field' into 'master'
fix custom field invoice issue

See merge request mohit.panjvani/crater-web!1432
2022-01-27 10:27:31 +00:00
30f36461c2 fix custom field invoice issue 2022-01-27 15:04:32 +05:30
980de6d492 remove links 2022-01-20 16:26:09 +05:30
ff3cd0f7b9 Customer avatar validation (#732)
* Customer avatar validation

https://huntr.dev/bounties/19f3e5f7-b419-44b1-9c37-7e4404cbec94/

* Customer avatar validation test

https://huntr.dev/bounties/19f3e5f7-b419-44b1-9c37-7e4404cbec94/
2022-01-19 17:08:34 +05:30
323b7d8ea6 Adds Nepali Rupee as currency (#675)
Co-authored-by: Ayush Jha <ayush.jha@wmcglobal.com>
2022-01-18 21:42:18 +05:30
dc7282d6e9 Added Macedonian Denar currency (#736)
* Add Macedonian Denar currency

* Typo fix

* Swap currency symbol
2022-01-18 21:35:18 +05:30
85836c3f9c Update readme.md (#719) 2022-01-13 21:48:16 +05:30
221184df41 new version 2022-01-13 18:19:56 +05:30
f313a8c164 new build 2022-01-13 18:07:39 +05:30
8f4fea3811 Merge branch 'error-message' into 'master'
add error message

See merge request mohit.panjvani/crater-web!1424
2022-01-13 11:52:23 +00:00
dca97e80e7 add error message 2022-01-13 17:19:27 +05:30
9e6b4bd862 Merge branch 'payment-method-delete' into 'master'
solve payment method delete issue

See merge request mohit.panjvani/crater-web!1423
2022-01-13 07:23:19 +00:00
55beed430a solve payment method delete issue 2022-01-13 12:25:46 +05:30
dd324c8bb6 solve payment method delete issue 2022-01-13 12:23:26 +05:30
e3f3809f2d fix formatting errors 2022-01-12 21:12:54 +05:30
d877b16776 add 601 migration 2022-01-12 18:59:35 +05:30
eac1bbb622 sync languages with crowdin 2022-01-12 17:58:25 +05:30
4ef5e7e54b Merge branch 'master' of https://github.com/bytefury/crater 2022-01-12 17:39:26 +05:30
e2bb414efe Fix HTML injection exploit (#682)
Escape html special characters from the $fields array to prevent html injection in the generated pdfs.
2022-01-12 17:39:15 +05:30
941bc4bdb8 Update dompdf version 2022-01-12 11:44:45 +00:00
a14655d73b Update dompdf version 2022-01-12 11:44:45 +00:00
d303b1a71c Patch on French translation (#711)
* Update fr.json

A few updates on some French translation typos (caps mostly).
"Item>Price" also needed to be more accurate, so just added "Unit price".

* Update fr.json

* Clarified pdf_price_label as it was ambiguous
* Translated PDF reports strings
* Few typos & missing words
2022-01-12 13:16:12 +05:30
f677a54c2a fix logo path 2022-01-12 12:33:42 +05:30
37fa96b29a Merge branch 'route' into 'master'
route issue fix

See merge request mohit.panjvani/crater-web!1417
2022-01-11 12:25:42 +00:00
147be77859 route issue fix 2022-01-11 17:27:55 +05:30
6ef2553423 Merge branch 'master' 2022-01-11 16:59:23 +05:30
22f6a48b5b fix csfixer warnings 2022-01-11 16:54:15 +05:30
897d759758 Merge branch 'payment-issue' into 'master'
solve payment issue

See merge request mohit.panjvani/crater-web!1415
2022-01-11 10:45:43 +00:00
bcd80377cf solve payment issue 2022-01-11 15:06:07 +05:30
dcb3ddecb9 update v6 2022-01-10 19:33:59 +05:30
1197215ff6 new build 2022-01-10 19:07:09 +05:30
4ca56de585 Merge branch 'fix-tests-master' into 'master'
Fix tests master

See merge request mohit.panjvani/crater-web!1413
2022-01-10 13:35:31 +00:00
b7c344132d fix web route 2022-01-10 19:03:06 +05:30
9eae813c24 fix tests 2022-01-10 19:02:49 +05:30
54f76f7cbe fix composer lock file 2022-01-10 16:10:49 +05:30
bdea879273 v6 update 2022-01-10 16:06:17 +05:30
6c5dcfe227 Merge branch 'minor-fix' into 'master'
Minor fix

See merge request mohit.panjvani/crater-web!1365
2021-12-31 11:58:54 +00:00
f79becad07 Merge branch 'dompdf-package-issue' into 'master'
downgrade dompdf issue

See merge request mohit.panjvani/crater-web!1366
2021-12-31 11:57:55 +00:00
c150c4edeb downgrade dompdf issue 2021-12-31 15:35:14 +05:30
d2dee7d511 fix customer request 2021-12-31 15:32:50 +05:30
fa9134610c fix test 2021-12-31 15:32:39 +05:30
02aabacd50 Merge branch 'increase-series-length' 2021-12-29 18:20:44 +05:30
a20c0a5ef9 Merge branch 'cron-job-org' into 'master'
add cronjob.org support

See merge request mohit.panjvani/crater-web!1316
2021-12-29 12:48:24 +00:00
df33776873 Merge branch 'fix-parse-condition' into 'master'
fix parse condition

See merge request mohit.panjvani/crater-web!1344
2021-12-29 12:46:17 +00:00
faf1ef0998 run csfixer 2021-12-29 18:05:14 +05:30
65404d5d6f Merge branch 'master' of https://github.com/bytefury/crater 2021-12-29 18:03:39 +05:30
cdc913d16c Unrestricted php file upload fix (#681)
https://huntr.dev/bounties/d7453360-baca-4e56-985f-481275fa38db/
2021-12-29 18:03:20 +05:30
c9d0a63854 Update readme.md (#680) 2021-12-27 20:08:25 +05:30
2fd8d8a5f4 solve trailing data error 2021-12-18 15:08:05 +05:30
2765f35f98 refactor parse condition 2021-12-18 13:14:46 +05:30
9652e3bdf5 fix parse condition 2021-12-18 12:43:20 +05:30
d69b7fd491 Allow invoices to be sent/resent from the invoice view page (#623)
* Allow invoices to be sent/resent from the invoice view page
2021-12-17 20:40:41 +05:30
f5c4f66165 Fix an issue with due date + expiry date not setting correctly & mark as sent button issue 2021-12-17 08:25:57 +00:00
848970fc08 Fix an issue with due date + expiry date not setting correctly & mark as sent button issue 2021-12-17 08:25:56 +00:00
37226fb35b Merge branch 'v5-fix-payment-condition' into 'master'
solve condition for payments migration

See merge request mohit.panjvani/crater-web!1342
2021-12-17 08:23:48 +00:00
f59bae9518 solve condition for payments migration 2021-12-17 13:30:02 +05:30
d2dcc44817 increase series param length to 6 2021-12-16 20:13:49 +05:30
4a85a5d2ab Merge branch 'fix-payment-update-issue' into 'master'
fix payment update issue

See merge request mohit.panjvani/crater-web!1337
2021-12-15 07:50:37 +00:00
7f04781604 Merge branch 'fix-date-formate-issue' into 'master'
date formatting issue fix

See merge request mohit.panjvani/crater-web!1339
2021-12-13 10:00:42 +00:00
99b1cc80c6 date formatting issue fix 2021-12-13 14:27:44 +05:30
6ce74bd59f added migration to calculate base amount for payments table 2021-12-13 11:34:47 +05:30
b24350aba6 fix payment update issue 2021-12-13 10:40:28 +05:30
b770e6277f remove currency tests 2021-12-10 18:04:42 +05:30
72398f0ac9 rename cron job issue 2021-12-04 15:42:45 +05:30
fbe25517e2 add cronjob.org support 2021-12-03 16:24:43 +05:30
781 changed files with 48607 additions and 14097 deletions

View File

@ -36,3 +36,5 @@ SANCTUM_STATEFUL_DOMAINS=crater.test
SESSION_DOMAIN=crater.test
TRUSTED_PROXIES="*"
CRON_JOB_AUTH_TOKEN=""

4
.gitignore vendored
View File

@ -1,3 +1,4 @@
/Modules
/node_modules
/public/storage
/public/hot
@ -12,3 +13,6 @@ Homestead.yaml
/.expo
/.vscode
/docker-compose/db/data/
.gitkeep
/public/docs
/.scribe

View File

@ -0,0 +1,45 @@
<?php
namespace Crater\Console\Commands;
use Crater\Space\ModuleInstaller;
use Illuminate\Console\Command;
class InstallModuleCommand extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'install:module {module} {version}';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Install cloned module.';
/**
* Create a new command instance.
*
* @return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*
* @return int
*/
public function handle()
{
ModuleInstaller::complete($this->argument('module'), $this->argument('version'));
return Command::SUCCESS;
}
}

View File

@ -16,7 +16,8 @@ class Kernel extends ConsoleKernel
protected $commands = [
Commands\ResetApp::class,
Commands\UpdateCommand::class,
Commands\CreateTemplateCommand::class
Commands\CreateTemplateCommand::class,
Commands\InstallModuleCommand::class,
];
/**

View File

@ -0,0 +1,26 @@
<?php
namespace Crater\Events;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;
class ModuleDisabledEvent
{
use Dispatchable;
use InteractsWithSockets;
use SerializesModels;
public $module;
/**
* Create a new event instance.
*
* @return void
*/
public function __construct($module)
{
$this->module = $module;
}
}

View File

@ -0,0 +1,26 @@
<?php
namespace Crater\Events;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;
class ModuleEnabledEvent
{
use Dispatchable;
use InteractsWithSockets;
use SerializesModels;
public $module;
/**
* Create a new event instance.
*
* @return void
*/
public function __construct($module)
{
$this->module = $module;
}
}

View File

@ -0,0 +1,26 @@
<?php
namespace Crater\Events;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;
class ModuleInstalledEvent
{
use Dispatchable;
use InteractsWithSockets;
use SerializesModels;
public $module;
/**
* Create a new event instance.
*
* @return void
*/
public function __construct($module)
{
$this->module = $module;
}
}

View File

@ -12,6 +12,7 @@ use Crater\Models\Expense;
use Crater\Models\Invoice;
use Crater\Models\Payment;
use Illuminate\Http\Request;
use Silber\Bouncer\BouncerFacade;
class DashboardController extends Controller
{
@ -151,8 +152,8 @@ class DashboardController extends Controller
'total_invoice_count' => $total_invoice_count,
'total_estimate_count' => $total_estimate_count,
'recent_due_invoices' => $recent_due_invoices,
'recent_estimates' => $recent_estimates,
'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,

View File

@ -83,6 +83,8 @@ class ConvertEstimateController extends Controller
'base_total' => $estimate->total * $exchange_rate,
'base_tax' => $estimate->tax * $exchange_rate,
'currency_id' => $estimate->currency_id,
'sales_tax_type' => $estimate->sales_tax_type,
'sales_tax_address_type' => $estimate->sales_tax_address_type,
]);
$invoice->unique_hash = Hashids::connection(Invoice::class)->encode($invoice->id);

View File

@ -21,6 +21,9 @@ class SendEstimatePreviewController extends Controller
$markdown = new Markdown(view(), config('mail.markdown'));
return $markdown->render('emails.send.estimate', ['data' => $estimate->sendEstimateData($request->all())]);
$data = $estimate->sendEstimateData($request->all());
$data['url'] = $estimate->estimatePdfUrl;
return $markdown->render('emails.send.estimate', ['data' => $data]);
}
}

View File

@ -39,7 +39,7 @@ class ExpensesController extends Controller
/**
* Store a newly created resource in storage.
*
* @param \Illuminate\Http\Request $request
* @param \Crater\Http\Requests\ExpenseRequest $request
* @return \Illuminate\Http\JsonResponse
*/
public function store(ExpenseRequest $request)
@ -67,7 +67,7 @@ class ExpensesController extends Controller
/**
* Update the specified resource in storage.
*
* @param \Illuminate\Http\Request $request
* @param \Crater\Http\Requests\ExpenseRequest $request
* @param \Crater\Models\Expense $expense
* @return \Illuminate\Http\JsonResponse
*/

View File

@ -3,19 +3,19 @@
namespace Crater\Http\Controllers\V1\Admin\Expense;
use Crater\Http\Controllers\Controller;
use Crater\Http\Requests\UploadExpenseReceiptRequest;
use Crater\Models\Expense;
use Illuminate\Http\Request;
class UploadReceiptController extends Controller
{
/**
* Upload the expense receipts to storage.
*
* @param \Illuminate\Http\Request $request
* @param \Crater\Http\Requests\ExpenseRequest $request
* @param Expense $expense
* @return \Illuminate\Http\JsonResponse
*/
public function __invoke(Request $request, Expense $expense)
public function __invoke(UploadExpenseReceiptRequest $request, Expense $expense)
{
$this->authorize('update', $expense);

View File

@ -8,6 +8,8 @@ use Crater\Http\Resources\UserResource;
use Crater\Models\Company;
use Crater\Models\CompanySetting;
use Crater\Models\Currency;
use Crater\Models\Module;
use Crater\Models\Setting;
use Crater\Traits\GeneratesMenuTrait;
use Illuminate\Http\Request;
use Silber\Bouncer\BouncerFacade;
@ -47,6 +49,15 @@ class BootstrapController extends Controller
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'
]);
return response()->json([
'current_user' => new UserResource($current_user),
'current_user_settings' => $current_user_settings,
@ -56,8 +67,10 @@ class BootstrapController extends Controller
'current_company_settings' => $current_company_settings,
'current_company_currency' => $current_company_currency,
'config' => config('crater'),
'global_settings' => $global_settings,
'main_menu' => $main_menu,
'setting_menu' => $setting_menu,
'modules' => Module::where('enabled', true)->pluck('name'),
]);
}
}

View File

@ -20,6 +20,7 @@ class SearchController extends Controller
$user = $request->user();
$customers = Customer::applyFilters($request->only(['search']))
->whereCompany()
->latest()
->paginate(10);

View File

@ -76,6 +76,8 @@ class CloneInvoiceController extends Controller
'base_tax' => $invoice->tax * $exchange_rate,
'base_due_amount' => $invoice->total * $exchange_rate,
'currency_id' => $invoice->currency_id,
'sales_tax_type' => $invoice->sales_tax_type,
'sales_tax_address_type' => $invoice->sales_tax_address_type,
]);
$newInvoice->unique_hash = Hashids::connection(Invoice::class)->encode($newInvoice->id);

View File

@ -102,7 +102,7 @@ class InvoicesController extends Controller
{
$this->authorize('delete multiple invoices');
Invoice::destroy($request->ids);
Invoice::deleteInvoices($request->ids);
return response()->json([
'success' => true,

View File

@ -21,6 +21,9 @@ class SendInvoicePreviewController extends Controller
$markdown = new Markdown(view(), config('mail.markdown'));
return $markdown->render('emails.send.invoice', ['data' => $invoice->sendInvoiceData($request->all())]);
$data = $invoice->sendInvoiceData($request->all());
$data['url'] = $invoice->invoicePdfUrl;
return $markdown->render('emails.send.invoice', ['data' => $data]);
}
}

View File

@ -0,0 +1,25 @@
<?php
namespace Crater\Http\Controllers\V1\Admin\Modules;
use Crater\Http\Controllers\Controller;
use Crater\Space\ModuleInstaller;
use Illuminate\Http\Request;
class ApiTokenController extends Controller
{
/**
* Handle the incoming request.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function __invoke(Request $request)
{
$this->authorize('manage modules');
$response = ModuleInstaller::checkToken($request->api_token);
return $response;
}
}

View File

@ -0,0 +1,27 @@
<?php
namespace Crater\Http\Controllers\V1\Admin\Modules;
use Crater\Http\Controllers\Controller;
use Crater\Space\ModuleInstaller;
use Illuminate\Http\Request;
class CompleteModuleInstallationController extends Controller
{
/**
* Handle the incoming request.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function __invoke(Request $request)
{
$this->authorize('manage modules');
$response = ModuleInstaller::complete($request->module, $request->version);
return response()->json([
'success' => $response
]);
}
}

View File

@ -0,0 +1,27 @@
<?php
namespace Crater\Http\Controllers\V1\Admin\Modules;
use Crater\Http\Controllers\Controller;
use Crater\Space\ModuleInstaller;
use Illuminate\Http\Request;
class CopyModuleController extends Controller
{
/**
* Handle the incoming request.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function __invoke(Request $request)
{
$this->authorize('manage modules');
$response = ModuleInstaller::copyFiles($request->module, $request->path);
return response()->json([
'success' => $response
]);
}
}

View File

@ -0,0 +1,32 @@
<?php
namespace Crater\Http\Controllers\V1\Admin\Modules;
use Crater\Events\ModuleDisabledEvent;
use Crater\Http\Controllers\Controller;
use Crater\Models\Module as ModelsModule;
use Illuminate\Http\Request;
use Nwidart\Modules\Facades\Module;
class DisableModuleController extends Controller
{
/**
* Handle the incoming request.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function __invoke(Request $request, string $module)
{
$this->authorize('manage modules');
$module = ModelsModule::where('name', $module)->first();
$module->update(['enabled' => false]);
$installedModule = Module::find($module->name);
$installedModule->disable();
ModuleDisabledEvent::dispatch($module);
return response()->json(['success' => true]);
}
}

View File

@ -0,0 +1,25 @@
<?php
namespace Crater\Http\Controllers\V1\Admin\Modules;
use Crater\Http\Controllers\Controller;
use Crater\Space\ModuleInstaller;
use Illuminate\Http\Request;
class DownloadModuleController extends Controller
{
/**
* Handle the incoming request.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function __invoke(Request $request)
{
$this->authorize('manage modules');
$response = ModuleInstaller::download($request->module, $request->version);
return response()->json($response);
}
}

View File

@ -0,0 +1,32 @@
<?php
namespace Crater\Http\Controllers\V1\Admin\Modules;
use Crater\Events\ModuleEnabledEvent;
use Crater\Http\Controllers\Controller;
use Crater\Models\Module as ModelsModule;
use Illuminate\Http\Request;
use Nwidart\Modules\Facades\Module;
class EnableModuleController extends Controller
{
/**
* Handle the incoming request.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function __invoke(Request $request, string $module)
{
$this->authorize('manage modules');
$module = ModelsModule::where('name', $module)->first();
$module->update(['enabled' => true]);
$installedModule = Module::find($module->name);
$installedModule->enable();
ModuleEnabledEvent::dispatch($module);
return response()->json(['success' => true]);
}
}

View File

@ -0,0 +1,33 @@
<?php
namespace Crater\Http\Controllers\V1\Admin\Modules;
use Crater\Http\Controllers\Controller;
use Crater\Http\Resources\ModuleResource;
use Crater\Space\ModuleInstaller;
use Illuminate\Http\Request;
class ModuleController extends Controller
{
/**
* Handle the incoming request.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function __invoke(Request $request, string $module)
{
$this->authorize('manage modules');
$response = ModuleInstaller::getModule($module);
if (! $response->success) {
return response()->json($response);
}
return (new ModuleResource($response->module))
->additional(['meta' => [
'modules' => ModuleResource::collection(collect($response->modules))
]]);
}
}

View File

@ -0,0 +1,25 @@
<?php
namespace Crater\Http\Controllers\V1\Admin\Modules;
use Crater\Http\Controllers\Controller;
use Crater\Space\ModuleInstaller;
use Illuminate\Http\Request;
class ModulesController extends Controller
{
/**
* Handle the incoming request.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function __invoke(Request $request)
{
$this->authorize('manage modules');
$response = ModuleInstaller::getModules();
return $response;
}
}

View File

@ -0,0 +1,28 @@
<?php
namespace Crater\Http\Controllers\V1\Admin\Modules;
use Crater\Http\Controllers\Controller;
use Crater\Space\ModuleInstaller;
use Illuminate\Http\Request;
class UnzipModuleController extends Controller
{
/**
* Handle the incoming request.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function __invoke(Request $request)
{
$this->authorize('manage modules');
$path = ModuleInstaller::unzip($request->module, $request->path);
return response()->json([
'success' => true,
'path' => $path
]);
}
}

View File

@ -0,0 +1,25 @@
<?php
namespace Crater\Http\Controllers\V1\Admin\Modules;
use Crater\Http\Controllers\Controller;
use Crater\Space\ModuleInstaller;
use Illuminate\Http\Request;
class UploadModuleController extends Controller
{
/**
* Handle the incoming request.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function __invoke(Request $request)
{
$this->authorize('manage modules');
$response = ModuleInstaller::upload($request);
return response()->json($response);
}
}

View File

@ -22,6 +22,7 @@ class PaymentMethodsController extends Controller
$limit = $request->has('limit') ? $request->limit : 5;
$paymentMethods = PaymentMethod::applyFilters($request->all())
->where('type', PaymentMethod::TYPE_GENERAL)
->whereCompany()
->latest()
->paginateData($limit);
@ -68,7 +69,7 @@ class PaymentMethodsController extends Controller
{
$this->authorize('update', $paymentMethod);
$paymentMethod->update($request->validated());
$paymentMethod->update($request->getPaymentMethodPayload());
return new PaymentMethodResource($paymentMethod);
}
@ -83,12 +84,14 @@ class PaymentMethodsController extends Controller
{
$this->authorize('delete', $paymentMethod);
$payments = $paymentMethod->payments;
if ($payments->count() > 0) {
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([

View File

@ -21,6 +21,9 @@ class SendPaymentPreviewController extends Controller
$markdown = new Markdown(view(), config('mail.markdown'));
return $markdown->render('emails.send.payment', ['data' => $payment->sendPaymentData($request->all())]);
$data = $payment->sendPaymentData($request->all());
$data['url'] = $payment->paymentPdfUrl;
return $markdown->render('emails.send.payment', ['data' => $data]);
}
}

View File

@ -3,6 +3,8 @@
namespace Crater\Http\Controllers\V1\Admin\Settings;
use Crater\Http\Controllers\Controller;
use Crater\Http\Requests\AvatarRequest;
use Crater\Http\Requests\CompanyLogoRequest;
use Crater\Http\Requests\CompanyRequest;
use Crater\Http\Requests\ProfileRequest;
use Crater\Http\Resources\CompanyResource;
@ -48,7 +50,7 @@ class CompanyController extends Controller
$this->authorize('manage company', $company);
$company->update($request->only('name'));
$company->update($request->getCompanyPayload());
$company->address()->updateOrCreate(['company_id' => $company->id], $request->address);
@ -58,10 +60,10 @@ class CompanyController extends Controller
/**
* Upload the company logo to storage.
*
* @param \Illuminate\Http\Request $request
* @param \Crater\Http\Requests\CompanyLogoRequest $request
* @return \Illuminate\Http\JsonResponse
*/
public function uploadCompanyLogo(Request $request)
public function uploadCompanyLogo(CompanyLogoRequest $request)
{
$company = Company::find($request->header('company'));
@ -69,6 +71,9 @@ class CompanyController extends Controller
$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'));
@ -89,13 +94,16 @@ class CompanyController extends Controller
/**
* Upload the Admin Avatar to public storage.
*
* @param \Illuminate\Http\Request $request
* @param \Crater\Http\Requests\AvatarRequest $request
* @return \Illuminate\Http\JsonResponse
*/
public function uploadAvatar(Request $request)
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');

View File

@ -0,0 +1,28 @@
<?php
namespace Crater\Http\Controllers\V1\Admin\Settings;
use Crater\Http\Controllers\Controller;
use Crater\Http\Requests\GetSettingRequest;
use Crater\Models\Setting;
use Illuminate\Http\Request;
class GetSettingsController extends Controller
{
/**
* Handle the incoming request.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function __invoke(GetSettingRequest $request)
{
$this->authorize('manage settings');
$setting = Setting::getSetting($request->key);
return response()->json([
$request->key => $setting
]);
}
}

View File

@ -22,6 +22,7 @@ class TaxTypesController extends Controller
$limit = $request->has('limit') ? $request->limit : 5;
$taxTypes = TaxType::applyFilters($request->all())
->where('type', TaxType::TYPE_GENERAL)
->whereCompany()
->latest()
->paginateData($limit);

View File

@ -0,0 +1,29 @@
<?php
namespace Crater\Http\Controllers\V1\Admin\Settings;
use Crater\Http\Controllers\Controller;
use Crater\Http\Requests\SettingRequest;
use Crater\Models\Setting;
use Illuminate\Http\Request;
class UpdateSettingsController extends Controller
{
/**
* Handle the incoming request.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function __invoke(SettingRequest $request)
{
$this->authorize('manage settings');
Setting::setSettings($request->settings);
return response()->json([
'success' => true,
$request->settings
]);
}
}

View File

@ -0,0 +1,56 @@
<?php
namespace Crater\Http\Controllers\V1\Customer\Auth;
use Crater\Http\Controllers\Controller;
use Illuminate\Foundation\Auth\SendsPasswordResetEmails;
use Illuminate\Http\Request;
use Password;
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;
public function broker()
{
return Password::broker('customers');
}
/**
* Get the response for a successful password reset link.
*
* @param \Illuminate\Http\Request $request
* @param string $response
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Http\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 \Illuminate\Http\Request $request
* @param string $response
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Http\JsonResponse
*/
protected function sendResetLinkFailedResponse(Request $request, $response)
{
return response('Email could not be sent to this email address.', 403);
}
}

View File

@ -0,0 +1,45 @@
<?php
namespace Crater\Http\Controllers\V1\Customer\Auth;
use Crater\Http\Controllers\Controller;
use Crater\Http\Requests\Customer\CustomerLoginRequest;
use Crater\Models\Company;
use Crater\Models\Customer;
use Hash;
use Illuminate\Support\Facades\Auth;
use Illuminate\Validation\ValidationException;
class LoginController extends Controller
{
/**
* Handle the incoming request.
*
* @param \Crater\Http\Requests\Customer\CustomerLoginRequest $request
* @return \Illuminate\Http\Response
*/
public function __invoke(CustomerLoginRequest $request, Company $company)
{
$user = Customer::where('email', $request->email)
->where('company_id', $company->id)
->first();
if (! $user || ! Hash::check($request->password, $user->password)) {
throw ValidationException::withMessages([
'email' => ['The provided credentials are incorrect.'],
]);
}
if (! $user->enable_portal) {
throw ValidationException::withMessages([
'email' => ['Customer portal not available for this user.'],
]);
}
Auth::guard('customer')->login($user);
return response()->json([
'success' => true
]);
}
}

View File

@ -0,0 +1,83 @@
<?php
namespace Crater\Http\Controllers\V1\Customer\Auth;
use Crater\Http\Controllers\Controller;
use Crater\Providers\RouteServiceProvider;
use Illuminate\Auth\Events\PasswordReset;
use Illuminate\Foundation\Auth\ResetsPasswords;
use Illuminate\Http\Request;
use Illuminate\Support\Str;
use Password;
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 = RouteServiceProvider::CUSTOMER_HOME;
public function broker()
{
return Password::broker('customers');
}
/**
* Get the response for a successful password reset.
*
* @param \Illuminate\Http\Request $request
* @param string $response
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Http\JsonResponse
*/
protected function sendResetResponse(Request $request, $response)
{
return response()->json([
'message' => 'Password reset successfully.',
]);
}
/**
* Reset the given user's password.
*
* @param \Illuminate\Contracts\Auth\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 \Illuminate\Http\Request $request
* @param string $response
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Http\JsonResponse
*/
protected function sendResetFailedResponse(Request $request, $response)
{
return response('Failed, Invalid Token.', 403);
}
}

View File

@ -0,0 +1,36 @@
<?php
namespace Crater\Http\Controllers\V1\Customer\Estimate;
use Crater\Http\Controllers\Controller;
use Crater\Http\Resources\Customer\EstimateResource;
use Crater\Models\Company;
use Crater\Models\Estimate;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
class AcceptEstimateController extends Controller
{
/**
* Handle the incoming request.
*
* @param \Illuminate\Http\Request $request
* @param Estimate $estimate
* @return \Illuminate\Http\Response
*/
public function __invoke(Request $request, Company $company, $id)
{
$estimate = $company->estimates()
->whereCustomer(Auth::guard('customer')->id())
->where('id', $id)
->first();
if (! $estimate) {
return response()->json(['error' => 'estimate_not_found'], 404);
}
$estimate->update($request->only('status'));
return new EstimateResource($estimate);
}
}

View File

@ -0,0 +1,67 @@
<?php
namespace Crater\Http\Controllers\V1\Customer\Estimate;
use Crater\Http\Controllers\Controller;
use Crater\Http\Resources\Customer\EstimateResource;
use Crater\Models\Company;
use Crater\Models\Estimate;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
class EstimatesController extends Controller
{
/**
* Display a listing of the resource.
*
* @return \Illuminate\Http\Response
*/
public function index(Request $request)
{
$limit = $request->has('limit') ? $request->limit : 10;
$estimates = Estimate::with([
'items',
'customer',
'taxes',
'creator',
])
->where('status', '<>', 'DRAFT')
->whereCustomer(Auth::guard('customer')->id())
->applyFilters($request->only([
'status',
'estimate_number',
'from_date',
'to_date',
'orderByField',
'orderBy',
]))
->latest()
->paginateData($limit);
return (EstimateResource::collection($estimates))
->additional(['meta' => [
'estimateTotalCount' => Estimate::where('status', '<>', 'DRAFT')->whereCustomer(Auth::guard('customer')->id())->count(),
]]);
}
/**
* Display the specified resource.
*
* @param Estimate $estimate
* @return \Illuminate\Http\Response
*/
public function show(Company $company, $id)
{
$estimate = $company->estimates()
->whereCustomer(Auth::guard('customer')->id())
->where('id', $id)
->first();
if (! $estimate) {
return response()->json(['error' => 'estimate_not_found'], 404);
}
return new EstimateResource($estimate);
}
}

View File

@ -3,41 +3,51 @@
namespace Crater\Http\Controllers\V1\Customer;
use Crater\Http\Controllers\Controller;
use Crater\Http\Resources\EstimateResource;
use Crater\Mail\EstimateViewedMail;
use Crater\Models\CompanySetting;
use Crater\Models\Customer;
use Crater\Models\EmailLog;
use Crater\Models\Estimate;
use Illuminate\Http\Request;
class EstimatePdfController extends Controller
{
/**
* Handle the incoming request.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function __invoke(Estimate $estimate)
public function getPdf(EmailLog $emailLog, Request $request)
{
if ($estimate && ($estimate->status == Estimate::STATUS_SENT || $estimate->status == Estimate::STATUS_DRAFT)) {
$estimate->status = Estimate::STATUS_VIEWED;
$estimate->save();
$notifyEstimateViewed = CompanySetting::getSetting(
'notify_estimate_viewed',
$estimate->company_id
);
$estimate = Estimate::find($emailLog->mailable_id);
if ($notifyEstimateViewed == 'YES') {
$data['estimate'] = Estimate::findOrFail($estimate->id)->toArray();
$data['user'] = Customer::find($estimate->customer_id)->toArray();
$notificationEmail = CompanySetting::getSetting(
'notification_email',
if (! $emailLog->isExpired()) {
if ($estimate && ($estimate->status == Estimate::STATUS_SENT || $estimate->status == Estimate::STATUS_DRAFT)) {
$estimate->status = Estimate::STATUS_VIEWED;
$estimate->save();
$notifyEstimateViewed = CompanySetting::getSetting(
'notify_estimate_viewed',
$estimate->company_id
);
\Mail::to($notificationEmail)->send(new EstimateViewedMail($data));
if ($notifyEstimateViewed == 'YES') {
$data['estimate'] = Estimate::findOrFail($estimate->id)->toArray();
$data['user'] = Customer::find($estimate->customer_id)->toArray();
$notificationEmail = CompanySetting::getSetting(
'notification_email',
$estimate->company_id
);
\Mail::to($notificationEmail)->send(new EstimateViewedMail($data));
}
}
return $estimate->getGeneratedPDFOrStream('estimate');
}
return $estimate->getGeneratedPDFOrStream('estimate');
abort(403, 'Link Expired.');
}
public function getEstimate(EmailLog $emailLog)
{
$estimate = Estimate::find($emailLog->mailable_id);
return new EstimateResource($estimate);
}
}

View File

@ -0,0 +1,59 @@
<?php
namespace Crater\Http\Controllers\V1\Customer\Expense;
use Crater\Http\Controllers\Controller;
use Crater\Http\Resources\Customer\ExpenseResource;
use Crater\Models\Company;
use Crater\Models\Expense;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
class ExpensesController extends Controller
{
/**
* Display a listing of the resource.
*
* @return \Illuminate\Http\Response
*/
public function index(Request $request)
{
$limit = $request->has('limit') ? $request->limit : 10;
$expenses = Expense::with('category', 'creator', 'fields')
->whereUser(Auth::guard('customer')->id())
->applyFilters($request->only([
'expense_category_id',
'from_date',
'to_date',
'orderByField',
'orderBy',
]))
->paginateData($limit);
return (ExpenseResource::collection($expenses))
->additional(['meta' => [
'expenseTotalCount' => Expense::whereCustomer(Auth::guard('customer')->id())->count(),
]]);
}
/**
* Display the specified resource.
*
* @param \Crater\Models\Expense $expense
* @return \Illuminate\Http\Response
*/
public function show(Company $company, $id)
{
$expense = $company->expenses()
->whereUser(Auth::guard('customer')->id())
->where('id', $id)
->first();
if (! $expense) {
return response()->json(['error' => 'expense_not_found'], 404);
}
return new ExpenseResource($expense);
}
}

View File

@ -0,0 +1,40 @@
<?php
namespace Crater\Http\Controllers\V1\Customer\General;
use Crater\Http\Controllers\Controller;
use Crater\Http\Resources\Customer\CustomerResource;
use Crater\Models\Currency;
use Crater\Models\Module;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
class BootstrapController extends Controller
{
/**
* Handle the incoming request.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function __invoke(Request $request)
{
$customer = Auth::guard('customer')->user();
foreach (\Menu::get('customer_portal_menu')->items->toArray() as $data) {
if ($customer) {
$menu[] = [
'title' => $data->title,
'link' => $data->link->path['url'],
];
}
}
return (new CustomerResource($customer))
->additional(['meta' => [
'menu' => $menu,
'current_customer_currency' => Currency::find($customer->currency_id),
'modules' => Module::where('enabled', true)->pluck('name'),
]]);
}
}

View File

@ -0,0 +1,45 @@
<?php
namespace Crater\Http\Controllers\V1\Customer\General;
use Crater\Http\Controllers\Controller;
use Crater\Models\Estimate;
use Crater\Models\Invoice;
use Crater\Models\Payment;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
class DashboardController extends Controller
{
/**
* Handle the incoming request.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function __invoke(Request $request)
{
$user = Auth::guard('customer')->user();
$amountDue = Invoice::whereCustomer($user->id)
->where('status', '<>', 'DRAFT')
->sum('due_amount');
$invoiceCount = Invoice::whereCustomer($user->id)
->where('status', '<>', 'DRAFT')
->count();
$estimatesCount = Estimate::whereCustomer($user->id)
->where('status', '<>', 'DRAFT')
->count();
$paymentCount = Payment::whereCustomer($user->id)
->count();
return response()->json([
'due_amount' => $amountDue,
'recentInvoices' => Invoice::whereCustomer($user->id)->where('status', '<>', 'DRAFT')->take(5)->latest()->get(),
'recentEstimates' => Estimate::whereCustomer($user->id)->where('status', '<>', 'DRAFT')->take(5)->latest()->get(),
'invoice_count' => $invoiceCount,
'estimate_count' => $estimatesCount,
'payment_count' => $paymentCount,
]);
}
}

View File

@ -0,0 +1,49 @@
<?php
namespace Crater\Http\Controllers\V1\Customer\General;
use Crater\Http\Controllers\Controller;
use Crater\Http\Requests\Customer\CustomerProfileRequest;
use Crater\Http\Resources\Customer\CustomerResource;
use Crater\Models\Company;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
class ProfileController extends Controller
{
public function updateProfile(Company $company, CustomerProfileRequest $request)
{
$customer = Auth::guard('customer')->user();
$customer->update($request->validated());
if (isset($request->is_customer_avatar_removed) && (bool) $request->is_customer_avatar_removed) {
$customer->clearMediaCollection('customer_avatar');
}
if ($customer && $request->hasFile('customer_avatar')) {
$customer->clearMediaCollection('customer_avatar');
$customer->addMediaFromRequest('customer_avatar')
->toMediaCollection('customer_avatar');
}
if ($request->billing !== null) {
$customer->shippingAddress()->delete();
$customer->addresses()->create($request->getShippingAddress());
}
if ($request->shipping !== null) {
$customer->billingAddress()->delete();
$customer->addresses()->create($request->getBillingAddress());
}
return new CustomerResource($customer);
}
public function getUser(Request $request)
{
$customer = Auth::guard('customer')->user();
return new CustomerResource($customer);
}
}

View File

@ -0,0 +1,49 @@
<?php
namespace Crater\Http\Controllers\V1\Customer\Invoice;
use Crater\Http\Controllers\Controller;
use Crater\Http\Resources\Customer\InvoiceResource;
use Crater\Models\Company;
use Crater\Models\Invoice;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
class InvoicesController extends Controller
{
/**
* Display a listing of the resource.
*
* @return \Illuminate\Http\Response
*/
public function index(Request $request)
{
$limit = $request->has('limit') ? $request->limit : 10;
$invoices = Invoice::with(['items', 'customer', 'creator', 'taxes'])
->where('status', '<>', 'DRAFT')
->applyFilters($request->all())
->whereCustomer(Auth::guard('customer')->id())
->latest()
->paginateData($limit);
return (InvoiceResource::collection($invoices))
->additional(['meta' => [
'invoiceTotalCount' => Invoice::where('status', '<>', 'DRAFT')->whereCustomer(Auth::guard('customer')->id())->count(),
]]);
}
public function show(Company $company, $id)
{
$invoice = $company->invoices()
->whereCustomer(Auth::guard('customer')->id())
->where('id', $id)
->first();
if (! $invoice) {
return response()->json(['error' => 'invoice_not_found'], 404);
}
return new InvoiceResource($invoice);
}
}

View File

@ -3,42 +3,59 @@
namespace Crater\Http\Controllers\V1\Customer;
use Crater\Http\Controllers\Controller;
use Crater\Http\Resources\Customer\InvoiceResource as CustomerInvoiceResource;
use Crater\Mail\InvoiceViewedMail;
use Crater\Models\CompanySetting;
use Crater\Models\Customer;
use Crater\Models\EmailLog;
use Crater\Models\Invoice;
use Illuminate\Http\Request;
class InvoicePdfController extends Controller
{
/**
* Handle the incoming request.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function __invoke(Invoice $invoice)
public function getPdf(EmailLog $emailLog, Request $request)
{
if ($invoice && ($invoice->status == Invoice::STATUS_SENT || $invoice->status == Invoice::STATUS_DRAFT)) {
$invoice->status = Invoice::STATUS_VIEWED;
$invoice->viewed = true;
$invoice->save();
$notifyInvoiceViewed = CompanySetting::getSetting(
'notify_invoice_viewed',
$invoice->company_id
);
$invoice = Invoice::find($emailLog->mailable_id);
if ($notifyInvoiceViewed == 'YES') {
$data['invoice'] = Invoice::findOrFail($invoice->id)->toArray();
$data['user'] = Customer::find($invoice->customer_id)->toArray();
$notificationEmail = CompanySetting::getSetting(
'notification_email',
if (! $emailLog->isExpired()) {
if ($invoice && ($invoice->status == Invoice::STATUS_SENT || $invoice->status == Invoice::STATUS_DRAFT)) {
$invoice->status = Invoice::STATUS_VIEWED;
$invoice->viewed = true;
$invoice->save();
$notifyInvoiceViewed = CompanySetting::getSetting(
'notify_invoice_viewed',
$invoice->company_id
);
\Mail::to($notificationEmail)->send(new InvoiceViewedMail($data));
if ($notifyInvoiceViewed == 'YES') {
$data['invoice'] = Invoice::findOrFail($invoice->id)->toArray();
$data['user'] = Customer::find($invoice->customer_id)->toArray();
$notificationEmail = CompanySetting::getSetting(
'notification_email',
$invoice->company_id
);
\Mail::to($notificationEmail)->send(new InvoiceViewedMail($data));
}
}
if ($request->has('pdf')) {
return $invoice->getGeneratedPDFOrStream('invoice');
}
return view('app')->with([
'customer_logo' => get_customer_logo($invoice->company_id),
'current_theme' => get_customer_portal_theme($invoice->company_id)
]);
}
return $invoice->getGeneratedPDFOrStream('invoice');
abort(403, 'Link Expired.');
}
public function getInvoice(EmailLog $emailLog)
{
$invoice = Invoice::find($emailLog->mailable_id);
return new CustomerInvoiceResource($invoice);
}
}

View File

@ -0,0 +1,23 @@
<?php
namespace Crater\Http\Controllers\V1\Customer\Payment;
use Crater\Http\Controllers\Controller;
use Crater\Http\Resources\Customer\PaymentMethodResource;
use Crater\Models\Company;
use Crater\Models\PaymentMethod;
use Illuminate\Http\Request;
class PaymentMethodController extends Controller
{
/**
* Handle the incoming request.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function __invoke(Request $request, Company $company)
{
return PaymentMethodResource::collection(PaymentMethod::where('company_id', $company->id)->get());
}
}

View File

@ -0,0 +1,61 @@
<?php
namespace Crater\Http\Controllers\V1\Customer\Payment;
use Crater\Http\Controllers\Controller;
use Crater\Http\Resources\Customer\PaymentResource;
use Crater\Models\Company;
use Crater\Models\Payment;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
class PaymentsController extends Controller
{
/**
* Display a listing of the resource.
*
* @return \Illuminate\Http\Response
*/
public function index(Request $request)
{
$limit = $request->has('limit') ? $request->limit : 10;
$payments = Payment::with(['customer', 'invoice', 'paymentMethod', 'creator'])
->whereCustomer(Auth::guard('customer')->id())
->leftJoin('invoices', 'invoices.id', '=', 'payments.invoice_id')
->applyFilters($request->only([
'payment_number',
'payment_method_id',
'orderByField',
'orderBy',
]))
->select('payments.*', 'invoices.invoice_number')
->latest()
->paginateData($limit);
return (PaymentResource::collection($payments))
->additional(['meta' => [
'paymentTotalCount' => Payment::whereCustomer(Auth::guard('customer')->id())->count(),
]]);
}
/**
* Display the specified resource.
*
* @param \Crater\Models\Payment $payment
* @return \Illuminate\Http\Response
*/
public function show(Company $company, $id)
{
$payment = $company->payments()
->whereCustomer(Auth::guard('customer')->id())
->where('id', $id)
->first();
if (! $payment) {
return response()->json(['error' => 'payment_not_found'], 404);
}
return new PaymentResource($payment);
}
}

View File

@ -0,0 +1,28 @@
<?php
namespace Crater\Http\Controllers\V1\Customer;
use Crater\Http\Controllers\Controller;
use Crater\Http\Resources\PaymentResource;
use Crater\Models\EmailLog;
use Crater\Models\Payment;
use Illuminate\Http\Request;
class PaymentPdfController extends Controller
{
public function getPdf(EmailLog $emailLog, Request $request)
{
if (! $emailLog->isExpired()) {
return $emailLog->mailable->getGeneratedPDFOrStream('payment');
}
abort(403, 'Link Expired.');
}
public function getPayment(EmailLog $emailLog)
{
$payment = Payment::find($emailLog->mailable_id);
return new PaymentResource($payment);
}
}

View File

@ -0,0 +1,35 @@
<?php
namespace Crater\Http\Controllers\V1\Modules;
use Crater\Http\Controllers\Controller;
use Crater\Services\Module\ModuleFacade;
use DateTime;
use Illuminate\Support\Arr;
use Request;
class ScriptController extends Controller
{
/**
* Serve the requested script.
*
* @param \Request $request
* @return \Illuminate\Http\Response
*
* @throws \Symfony\Component\HttpKernel\Exception\NotFoundHttpException
*/
public function __invoke(Request $request, string $script)
{
$path = Arr::get(ModuleFacade::allScripts(), $script);
abort_if(is_null($path), 404);
return response(
file_get_contents($path),
200,
[
'Content-Type' => 'application/javascript',
]
)->setLastModified(DateTime::createFromFormat('U', filemtime($path)));
}
}

View File

@ -0,0 +1,35 @@
<?php
namespace Crater\Http\Controllers\V1\Modules;
use Crater\Http\Controllers\Controller;
use Crater\Services\Module\ModuleFacade;
use DateTime;
use Illuminate\Support\Arr;
use Request;
class StyleController extends Controller
{
/**
* Serve the requested stylesheet.
*
* @param \Request $request
* @return \Illuminate\Http\Response
*
* @throws \Symfony\Component\HttpKernel\Exception\NotFoundHttpException
*/
public function __invoke(Request $request, string $style)
{
$path = Arr::get(ModuleFacade::allStyles(), $style);
abort_if(is_null($path), 404);
return response(
file_get_contents($path),
200,
[
'Content-Type' => 'text/css',
]
)->setLastModified(DateTime::createFromFormat('U', filemtime($path)));
}
}

View File

@ -17,6 +17,8 @@ class DownloadReceiptController extends Controller
*/
public function __invoke(Expense $expense)
{
$this->authorize('view', $expense);
if ($expense) {
$media = $expense->getFirstMedia('receipts');
if ($media) {

View File

@ -0,0 +1,23 @@
<?php
namespace Crater\Http\Controllers\V1\Webhook;
use Crater\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Artisan;
class CronJobController extends Controller
{
/**
* Handle the incoming request.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function __invoke(Request $request)
{
Artisan::call('schedule:run');
return response()->json(['success' => true]);
}
}

View File

@ -69,6 +69,9 @@ class Kernel extends HttpKernel
'redirect-if-unauthenticated' => \Crater\Http\Middleware\RedirectIfUnauthorized::class,
'customer-guest' => \Crater\Http\Middleware\CustomerGuest::class,
'company' => \Crater\Http\Middleware\CompanyMiddleware::class,
'pdf-auth' => \Crater\Http\Middleware\PdfMiddleware::class,
'cron-job' => \Crater\Http\Middleware\CronJobMiddleware::class,
'customer-portal' => \Crater\Http\Middleware\CustomerPortalMiddleware::class,
];
/**

View File

@ -0,0 +1,25 @@
<?php
namespace Crater\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
class CronJobMiddleware
{
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @return mixed
*/
public function handle(Request $request, Closure $next)
{
if ($request->header('x-authorization-token') && $request->header('x-authorization-token') == config('services.cron_job.auth_token')) {
return $next($request);
}
return response()->json(['unauthorized'], 401);
}
}

View File

@ -0,0 +1,30 @@
<?php
namespace Crater\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
class CustomerPortalMiddleware
{
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure(\Illuminate\Http\Request): (\Illuminate\Http\Response|\Illuminate\Http\RedirectResponse) $next
* @return \Illuminate\Http\Response|\Illuminate\Http\RedirectResponse
*/
public function handle(Request $request, Closure $next)
{
$user = Auth::guard('customer')->user();
if (! $user->enable_portal) {
Auth::guard('customer')->logout();
return response('Unauthorized.', 401);
}
return $next($request);
}
}

View File

@ -0,0 +1,26 @@
<?php
namespace Crater\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
class PdfMiddleware
{
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure(\Illuminate\Http\Request): (\Illuminate\Http\Response|\Illuminate\Http\RedirectResponse) $next
* @return \Illuminate\Http\Response|\Illuminate\Http\RedirectResponse
*/
public function handle(Request $request, Closure $next)
{
if (Auth::guard('web')->check() || Auth::guard('api')->check() || Auth::guard('customer')->check()) {
return $next($request);
}
return redirect('/login');
}
}

View File

@ -0,0 +1,40 @@
<?php
namespace Crater\Http\Requests;
use Crater\Rules\Base64Mime;
use Illuminate\Foundation\Http\FormRequest;
class AvatarRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
'admin_avatar' => [
'nullable',
'file',
'mimes:gif,jpg,png',
'max:20000'
],
'avatar' => [
'nullable',
new Base64Mime(['gif', 'jpg', 'png'])
]
];
}
}

View File

@ -3,6 +3,7 @@
namespace Crater\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Support\Str;
use Illuminate\Validation\Rule;
class CompaniesRequest extends FormRequest
@ -70,7 +71,8 @@ class CompaniesRequest extends FormRequest
'name'
])
->merge([
'owner_id' => $this->user()->id
'owner_id' => $this->user()->id,
'slug' => Str::slug($this->name)
])
->toArray();
}

View File

@ -0,0 +1,34 @@
<?php
namespace Crater\Http\Requests;
use Crater\Rules\Base64Mime;
use Illuminate\Foundation\Http\FormRequest;
class CompanyLogoRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
'company_logo' => [
'nullable',
new Base64Mime(['gif', 'jpg', 'png'])
]
];
}
}

View File

@ -29,9 +29,22 @@ class CompanyRequest extends FormRequest
'required',
Rule::unique('companies')->ignore($this->header('company'), 'id'),
],
'slug' => [
'nullable'
],
'address.country_id' => [
'required',
],
];
}
public function getCompanyPayload()
{
return collect($this->validated())
->only([
'name',
'slug'
])
->toArray();
}
}

View File

@ -0,0 +1,37 @@
<?php
namespace Crater\Http\Requests\Customer;
use Illuminate\Foundation\Http\FormRequest;
class CustomerLoginRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
'email' => [
'required',
'string'
],
'password' => [
'required',
'string'
]
];
}
}

View File

@ -0,0 +1,122 @@
<?php
namespace Crater\Http\Requests\Customer;
use Crater\Models\Address;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Support\Facades\Auth;
use Illuminate\Validation\Rule;
class CustomerProfileRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
'name' => [
'nullable',
],
'password' => [
'nullable',
'min:8',
],
'email' => [
'nullable',
'email',
Rule::unique('customers')->where('company_id', $this->header('company'))->ignore(Auth::id(), 'id'),
],
'billing.name' => [
'nullable',
],
'billing.address_street_1' => [
'nullable',
],
'billing.address_street_2' => [
'nullable',
],
'billing.city' => [
'nullable',
],
'billing.state' => [
'nullable',
],
'billing.country_id' => [
'nullable',
],
'billing.zip' => [
'nullable',
],
'billing.phone' => [
'nullable',
],
'billing.fax' => [
'nullable',
],
'shipping.name' => [
'nullable',
],
'shipping.address_street_1' => [
'nullable',
],
'shipping.address_street_2' => [
'nullable',
],
'shipping.city' => [
'nullable',
],
'shipping.state' => [
'nullable',
],
'shipping.country_id' => [
'nullable',
],
'shipping.zip' => [
'nullable',
],
'shipping.phone' => [
'nullable',
],
'shipping.fax' => [
'nullable',
],
'customer_avatar' => [
'nullable',
'file',
'mimes:gif,jpg,png',
'max:20000'
]
];
}
public function getShippingAddress()
{
return collect($this->shipping)
->merge([
'type' => Address::SHIPPING_TYPE
])
->toArray();
}
public function getBillingAddress()
{
return collect($this->billing)
->merge([
'type' => Address::BILLING_TYPE
])
->toArray();
}
}

View File

@ -0,0 +1,33 @@
<?php
namespace Crater\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class CustomerEstimateStatusRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
'status' => [
'required',
'in:ACCEPTED,REJECTED',
]
];
}
}

View File

@ -54,7 +54,8 @@ class CustomerRequest extends FormRequest
'nullable',
],
'enable_portal' => [
'nullable',
'boolean'
],
'currency_id' => [
'nullable',
@ -119,7 +120,7 @@ class CustomerRequest extends FormRequest
$rules['email'] = [
'email',
'nullable',
Rule::unique('customers')->ignore($this->route('customer')->id),
Rule::unique('customers')->where('company_id', $this->header('company'))->ignore($this->route('customer')->id),
];
};

View File

@ -51,6 +51,12 @@ class ExpenseRequest extends FormRequest
'currency_id' => [
'required'
],
'attachment_receipt' => [
'nullable',
'file',
'mimes:jpg,png,pdf,doc,docx,xls,xlsx,ppt,pptx',
'max:20000'
]
];
if ($companyCurrency && $this->currency_id) {

View File

@ -0,0 +1,33 @@
<?php
namespace Crater\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class GetSettingRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
'key' => [
'required',
'string'
]
];
}
}

View File

@ -2,6 +2,7 @@
namespace Crater\Http\Requests;
use Crater\Models\PaymentMethod;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Validation\Rule;
@ -43,4 +44,14 @@ class PaymentMethodRequest extends FormRequest
return $data;
}
public function getPaymentMethodPayload()
{
return collect($this->validated())
->merge([
'company_id' => $this->header('company'),
'type' => PaymentMethod::TYPE_GENERAL,
])
->toArray();
}
}

View File

@ -24,10 +24,7 @@ class SettingRequest extends FormRequest
public function rules()
{
return [
'key' => [
'required',
],
'value' => [
'settings' => [
'required',
],
];

View File

@ -2,6 +2,7 @@
namespace Crater\Http\Requests;
use Crater\Models\TaxType;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Validation\Rule;
@ -28,6 +29,7 @@ class TaxTypeRequest extends FormRequest
'name' => [
'required',
Rule::unique('tax_types')
->where('type', TaxType::TYPE_GENERAL)
->where('company_id', $this->header('company'))
],
'percent' => [
@ -49,6 +51,7 @@ class TaxTypeRequest extends FormRequest
'required',
Rule::unique('tax_types')
->ignore($this->route('tax_type')->id)
->where('type', TaxType::TYPE_GENERAL)
->where('company_id', $this->header('company'))
];
}
@ -60,7 +63,8 @@ class TaxTypeRequest extends FormRequest
{
return collect($this->validated())
->merge([
'company_id' => $this->header('company')
'company_id' => $this->header('company'),
'type' => TaxType::TYPE_GENERAL
])
->toArray();
}

View File

@ -0,0 +1,34 @@
<?php
namespace Crater\Http\Requests;
use Crater\Rules\Base64Mime;
use Illuminate\Foundation\Http\FormRequest;
class UploadExpenseReceiptRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
'upload_receipt' => [
'nullable',
new Base64Mime(['gif', 'jpg', 'png'])
]
];
}
}

View File

@ -21,6 +21,7 @@ class CompanyResource extends JsonResource
'logo_path' => $this->logo_path,
'unique_hash' => $this->unique_hash,
'owner_id' => $this->owner_id,
'slug' => $this->slug,
'address' => $this->when($this->address()->exists(), function () {
return new AddressResource($this->address);
}),

View File

@ -2,6 +2,7 @@
namespace Crater\Http\Resources;
use Crater\Models\CompanySetting;
use Illuminate\Http\Resources\Json\JsonResource;
class CustomFieldValueResource extends JsonResource
@ -28,6 +29,7 @@ class CustomFieldValueResource extends JsonResource
'custom_field_id' => $this->custom_field_id,
'company_id' => $this->company_id,
'default_answer' => $this->defaultAnswer,
'default_formatted_answer' => $this->dateTimeFormat(),
'custom_field' => $this->when($this->customField()->exists(), function () {
return new CustomFieldResource($this->customField);
}),
@ -36,4 +38,24 @@ class CustomFieldValueResource extends JsonResource
}),
];
}
public function dateTimeFormat()
{
$key = getCustomFieldValueKey($this->type);
$answer = $this->default_answer;
if (! $answer) {
return null;
}
if ($key == 'date_time_answer') {
return $answer->format('Y-m-d H:i');
}
if ($key == 'date_answer') {
return $answer->format(CompanySetting::getSetting('carbon_date_format', $this->company_id));
}
return $answer;
}
}

View File

@ -0,0 +1,19 @@
<?php
namespace Crater\Http\Resources\Customer;
use Illuminate\Http\Resources\Json\ResourceCollection;
class AddressCollection extends ResourceCollection
{
/**
* Transform the resource collection into an array.
*
* @param \Illuminate\Http\Request $request
* @return array
*/
public function toArray($request)
{
return parent::toArray($request);
}
}

View File

@ -0,0 +1,40 @@
<?php
namespace Crater\Http\Resources\Customer;
use Illuminate\Http\Resources\Json\JsonResource;
class AddressResource extends JsonResource
{
/**
* Transform the resource into an array.
*
* @param \Illuminate\Http\Request $request
* @return array
*/
public function toArray($request)
{
return [
'id' => $this->id,
'name' => $this->name,
'address_street_1' => $this->address_street_1,
'address_street_2' => $this->address_street_2,
'city' => $this->city,
'state' => $this->state,
'country_id' => $this->country_id,
'zip' => $this->zip,
'phone' => $this->phone,
'fax' => $this->fax,
'type' => $this->type,
'user_id' => $this->user_id,
'company_id' => $this->company_id,
'customer_id' => $this->customer_id,
'country' => $this->when($this->country()->exists(), function () {
return new CountryResource($this->country);
}),
'user' => $this->when($this->user()->exists(), function () {
return new UserResource($this->user);
}),
];
}
}

View File

@ -0,0 +1,30 @@
<?php
namespace Crater\Http\Resources\Customer;
use Illuminate\Http\Resources\Json\JsonResource;
class CompanyResource extends JsonResource
{
/**
* Transform the resource into an array.
*
* @param \Illuminate\Http\Request $request
* @return array
*/
public function toArray($request)
{
return [
'id' => $this->id,
'name' => $this->name,
'slug' => $this->slug,
'logo' => $this->logo,
'logo_path' => $this->logo_path,
'unique_hash' => $this->unique_hash,
'owner_id' => $this->owner_id,
'address' => $this->when($this->address()->exists(), function () {
return new AddressResource($this->address);
}),
];
}
}

View File

@ -0,0 +1,19 @@
<?php
namespace Crater\Http\Resources\Customer;
use Illuminate\Http\Resources\Json\ResourceCollection;
class CountryCollection extends ResourceCollection
{
/**
* Transform the resource collection into an array.
*
* @param \Illuminate\Http\Request $request
* @return array
*/
public function toArray($request)
{
return parent::toArray($request);
}
}

View File

@ -0,0 +1,24 @@
<?php
namespace Crater\Http\Resources\Customer;
use Illuminate\Http\Resources\Json\JsonResource;
class CountryResource extends JsonResource
{
/**
* Transform the resource into an array.
*
* @param \Illuminate\Http\Request $request
* @return array
*/
public function toArray($request)
{
return [
'id' => $this->id,
'code' => $this->code,
'name' => $this->name,
'phonecode' => $this->phonecode,
];
}
}

View File

@ -0,0 +1,19 @@
<?php
namespace Crater\Http\Resources\Customer;
use Illuminate\Http\Resources\Json\ResourceCollection;
class CurrencyCollection extends ResourceCollection
{
/**
* Transform the resource collection into an array.
*
* @param \Illuminate\Http\Request $request
* @return array
*/
public function toArray($request)
{
return parent::toArray($request);
}
}

View File

@ -0,0 +1,29 @@
<?php
namespace Crater\Http\Resources\Customer;
use Illuminate\Http\Resources\Json\JsonResource;
class CurrencyResource extends JsonResource
{
/**
* Transform the resource into an array.
*
* @param \Illuminate\Http\Request $request
* @return array
*/
public function toArray($request)
{
return [
'id' => $this->id,
'name' => $this->name,
'code' => $this->code,
'symbol' => $this->symbol,
'precision' => $this->precision,
'thousand_separator' => $this->thousand_separator,
'decimal_separator' => $this->decimal_separator,
'swap_currency_symbol' => $this->swap_currency_symbol,
'exchange_rate' => $this->exchange_rate
];
}
}

View File

@ -0,0 +1,19 @@
<?php
namespace Crater\Http\Resources\Customer;
use Illuminate\Http\Resources\Json\ResourceCollection;
class CustomFieldCollection extends ResourceCollection
{
/**
* Transform the resource collection into an array.
*
* @param \Illuminate\Http\Request $request
* @return array
*/
public function toArray($request)
{
return parent::toArray($request);
}
}

View File

@ -0,0 +1,42 @@
<?php
namespace Crater\Http\Resources\Customer;
use Illuminate\Http\Resources\Json\JsonResource;
class CustomFieldResource extends JsonResource
{
/**
* Transform the resource into an array.
*
* @param \Illuminate\Http\Request $request
* @return array
*/
public function toArray($request)
{
return [
'id' => $this->id,
'name' => $this->name,
'slug' => $this->slug,
'label' => $this->label,
'model_type' => $this->model_type,
'type' => $this->type,
'placeholder' => $this->placeholder,
'options' => $this->options,
'boolean_answer' => $this->boolean_answer,
'date_answer' => $this->date_answer,
'time_answer' => $this->time_answer,
'string_answer' => $this->string_answer,
'number_answer' => $this->number_answer,
'date_time_answer' => $this->date_time_answer,
'is_required' => $this->is_required,
'in_use' => $this->in_use,
'order' => $this->order,
'company_id' => $this->company_id,
'default_answer' => $this->default_answer,
'company' => $this->when($this->company()->exists(), function () {
return new CompanyResource($this->company);
}),
];
}
}

View File

@ -0,0 +1,19 @@
<?php
namespace Crater\Http\Resources\Customer;
use Illuminate\Http\Resources\Json\ResourceCollection;
class CustomFieldValueCollection extends ResourceCollection
{
/**
* Transform the resource collection into an array.
*
* @param \Illuminate\Http\Request $request
* @return array
*/
public function toArray($request)
{
return parent::toArray($request);
}
}

View File

@ -0,0 +1,39 @@
<?php
namespace Crater\Http\Resources\Customer;
use Illuminate\Http\Resources\Json\JsonResource;
class CustomFieldValueResource extends JsonResource
{
/**
* Transform the resource into an array.
*
* @param \Illuminate\Http\Request $request
* @return array
*/
public function toArray($request)
{
return [
'id' => $this->id,
'custom_field_valuable_type' => $this->custom_field_valuable_type,
'custom_field_valuable_id' => $this->custom_field_valuable_id,
'type' => $this->type,
'boolean_answer' => $this->boolean_answer,
'date_answer' => $this->date_answer,
'time_answer' => $this->time_answer,
'string_answer' => $this->string_answer,
'number_answer' => $this->number_answer,
'date_time_answer' => $this->date_time_answer,
'custom_field_id' => $this->custom_field_id,
'company_id' => $this->company_id,
'default_answer' => $this->defaultAnswer,
'custom_field' => $this->when($this->customField()->exists(), function () {
return new CustomFieldResource($this->customField);
}),
'company' => $this->when($this->company()->exists(), function () {
return new CompanyResource($this->company);
}),
];
}
}

View File

@ -0,0 +1,19 @@
<?php
namespace Crater\Http\Resources\Customer;
use Illuminate\Http\Resources\Json\ResourceCollection;
class CustomerCollection extends ResourceCollection
{
/**
* Transform the resource collection into an array.
*
* @param \Illuminate\Http\Request $request
* @return array
*/
public function toArray($request)
{
return parent::toArray($request);
}
}

View File

@ -0,0 +1,51 @@
<?php
namespace Crater\Http\Resources\Customer;
use Illuminate\Http\Resources\Json\JsonResource;
class CustomerResource extends JsonResource
{
/**
* Transform the resource into an array.
*
* @param \Illuminate\Http\Request $request
* @return array
*/
public function toArray($request)
{
return [
'id' => $this->id,
'name' => $this->name,
'email' => $this->email,
'phone' => $this->phone,
'contact_name' => $this->contact_name,
'company_name' => $this->company_name,
'website' => $this->website,
'enable_portal' => $this->enable_portal,
'currency_id' => $this->currency_id,
'company_id' => $this->company_id,
'facebook_id' => $this->facebook_id,
'google_id' => $this->google_id,
'github_id' => $this->github_id,
'formatted_created_at' => $this->formattedCreatedAt,
'avatar' => $this->avatar,
'prefix' => $this->prefix,
'billing' => $this->when($this->billingAddress()->exists(), function () {
return new AddressResource($this->billingAddress);
}),
'shipping' => $this->when($this->shippingAddress()->exists(), function () {
return new AddressResource($this->shippingAddress);
}),
'fields' => $this->when($this->fields()->exists(), function () {
return CustomFieldValueResource::collection($this->fields);
}),
'company' => $this->when($this->company()->exists(), function () {
return new CompanyResource($this->company);
}),
'currency' => $this->when($this->currency()->exists(), function () {
return new CurrencyResource($this->currency);
}),
];
}
}

View File

@ -0,0 +1,19 @@
<?php
namespace Crater\Http\Resources\Customer;
use Illuminate\Http\Resources\Json\ResourceCollection;
class EstimateCollection extends ResourceCollection
{
/**
* Transform the resource collection into an array.
*
* @param \Illuminate\Http\Request $request
* @return array
*/
public function toArray($request)
{
return parent::toArray($request);
}
}

View File

@ -0,0 +1,19 @@
<?php
namespace Crater\Http\Resources\Customer;
use Illuminate\Http\Resources\Json\ResourceCollection;
class EstimateItemCollection extends ResourceCollection
{
/**
* Transform the resource collection into an array.
*
* @param \Illuminate\Http\Request $request
* @return array
*/
public function toArray($request)
{
return parent::toArray($request);
}
}

View File

@ -0,0 +1,45 @@
<?php
namespace Crater\Http\Resources\Customer;
use Illuminate\Http\Resources\Json\JsonResource;
class EstimateItemResource extends JsonResource
{
/**
* Transform the resource into an array.
*
* @param \Illuminate\Http\Request $request
* @return array
*/
public function toArray($request)
{
return [
'id' => $this->id,
'name' => $this->name,
'description' => $this->description,
'discount_type' => $this->discount_type,
'quantity' => $this->quantity,
'unit_name' => $this->unit_name,
'discount' => $this->discount,
'discount_val' => $this->discount_val,
'price' => $this->price,
'tax' => $this->tax,
'total' => $this->total,
'item_id' => $this->item_id,
'estimate_id' => $this->estimate_id,
'company_id' => $this->company_id,
'exchange_rate' => $this->exchange_rate,
'base_discount_val' => $this->base_discount_val,
'base_price' => $this->base_price,
'base_tax' => $this->base_tax,
'base_total' => $this->base_total,
'taxes' => $this->when($this->taxes()->exists(), function () {
return TaxResource::collection($this->taxes);
}),
'fields' => $this->when($this->fields()->exists(), function () {
return CustomFieldValueResource::collection($this->fields);
}),
];
}
}

View File

@ -0,0 +1,65 @@
<?php
namespace Crater\Http\Resources\Customer;
use Illuminate\Http\Resources\Json\JsonResource;
class EstimateResource extends JsonResource
{
/**
* Transform the resource into an array.
*
* @param \Illuminate\Http\Request $request
* @return array
*/
public function toArray($request)
{
return [
'id' => $this->id,
'estimate_date' => $this->estimate_date,
'expiry_date' => $this->expiry_date,
'estimate_number' => $this->estimate_number,
'status' => $this->status,
'reference_number' => $this->reference_number,
'tax_per_item' => $this->tax_per_item,
'discount_per_item' => $this->discount_per_item,
'notes' => $this->notes,
'discount' => $this->discount,
'discount_type' => $this->discount_type,
'discount_val' => $this->discount_val,
'sub_total' => $this->sub_total,
'total' => $this->total,
'tax' => $this->tax,
'unique_hash' => $this->unique_hash,
'template_name' => $this->template_name,
'customer_id' => $this->customer_id,
'exchange_rate' => $this->exchange_rate,
'base_discount_val' => $this->base_discount_val,
'base_sub_total' => $this->base_sub_total,
'base_total' => $this->base_total,
'base_tax' => $this->base_tax,
'currency_id' => $this->currency_id,
'formatted_expiry_date' => $this->formattedExpiryDate,
'formatted_estimate_date' => $this->formattedEstimateDate,
'estimate_pdf_url' => $this->estimatePdfUrl,
'items' => $this->when($this->items()->exists(), function () {
return EstimateItemResource::collection($this->items);
}),
'customer' => $this->when($this->customer()->exists(), function () {
return new CustomerResource($this->customer);
}),
'taxes' => $this->when($this->taxes()->exists(), function () {
return TaxResource::collection($this->taxes);
}),
'fields' => $this->when($this->fields()->exists(), function () {
return CustomFieldValueResource::collection($this->fields);
}),
'company' => $this->when($this->company()->exists(), function () {
return new CompanyResource($this->company);
}),
'currency' => $this->when($this->currency()->exists(), function () {
return new CurrencyResource($this->currency);
}),
];
}
}

View File

@ -0,0 +1,19 @@
<?php
namespace Crater\Http\Resources\Customer;
use Illuminate\Http\Resources\Json\ResourceCollection;
class ExpenseCategoryCollection extends ResourceCollection
{
/**
* Transform the resource collection into an array.
*
* @param \Illuminate\Http\Request $request
* @return array
*/
public function toArray($request)
{
return parent::toArray($request);
}
}

View File

@ -0,0 +1,29 @@
<?php
namespace Crater\Http\Resources\Customer;
use Illuminate\Http\Resources\Json\JsonResource;
class ExpenseCategoryResource extends JsonResource
{
/**
* Transform the resource into an array.
*
* @param \Illuminate\Http\Request $request
* @return array
*/
public function toArray($request)
{
return [
'id' => $this->id,
'name' => $this->name,
'description' => $this->description,
'company_id' => $this->company_id,
'amount' => $this->amount,
'formatted_created_at' => $this->formattedCreatedAt,
'company' => $this->when($this->company()->exists(), function () {
return new CompanyResource($this->company);
}),
];
}
}

View File

@ -0,0 +1,19 @@
<?php
namespace Crater\Http\Resources\Customer;
use Illuminate\Http\Resources\Json\ResourceCollection;
class ExpenseCollection extends ResourceCollection
{
/**
* Transform the resource collection into an array.
*
* @param \Illuminate\Http\Request $request
* @return array
*/
public function toArray($request)
{
return parent::toArray($request);
}
}

View File

@ -0,0 +1,54 @@
<?php
namespace Crater\Http\Resources\Customer;
use Illuminate\Http\Resources\Json\JsonResource;
class ExpenseResource extends JsonResource
{
/**
* Transform the resource into an array.
*
* @param \Illuminate\Http\Request $request
* @return array
*/
public function toArray($request)
{
return [
'id' => $this->id,
'expense_date' => $this->expense_date,
'amount' => $this->amount,
'notes' => $this->notes,
'customer_id' => $this->customer_id,
'attachment_receipt_url' => $this->receipt_url,
'attachment_receipt' => $this->receipt,
'attachment_receipt_meta' => $this->receipt_meta,
'company_id' => $this->company_id,
'expense_category_id' => $this->expense_category_id,
'formatted_expense_date' => $this->formattedExpenseDate,
'formatted_created_at' => $this->formattedCreatedAt,
'exchange_rate' => $this->exchange_rate,
'currency_id' => $this->currency_id,
'base_amount' => $this->base_amount,
'payment_method_id' => $this->payment_method_id,
'customer' => $this->when($this->customer()->exists(), function () {
return new CustomerResource($this->customer);
}),
'expense_category' => $this->when($this->category()->exists(), function () {
return new ExpenseCategoryResource($this->category);
}),
'fields' => $this->when($this->fields()->exists(), function () {
return CustomFieldValueResource::collection($this->fields);
}),
'company' => $this->when($this->company()->exists(), function () {
return new CompanyResource($this->company);
}),
'currency' => $this->when($this->currency()->exists(), function () {
return new CurrencyResource($this->currency);
}),
'payment_method' => $this->when($this->paymentMethod()->exists(), function () {
return new PaymentMethodResource($this->paymentMethod);
}),
];
}
}

View File

@ -0,0 +1,19 @@
<?php
namespace Crater\Http\Resources\Customer;
use Illuminate\Http\Resources\Json\ResourceCollection;
class InvoiceCollection extends ResourceCollection
{
/**
* Transform the resource collection into an array.
*
* @param \Illuminate\Http\Request $request
* @return array
*/
public function toArray($request)
{
return parent::toArray($request);
}
}

View File

@ -0,0 +1,19 @@
<?php
namespace Crater\Http\Resources\Customer;
use Illuminate\Http\Resources\Json\ResourceCollection;
class InvoiceItemCollection extends ResourceCollection
{
/**
* Transform the resource collection into an array.
*
* @param \Illuminate\Http\Request $request
* @return array
*/
public function toArray($request)
{
return parent::toArray($request);
}
}

View File

@ -0,0 +1,46 @@
<?php
namespace Crater\Http\Resources\Customer;
use Illuminate\Http\Resources\Json\JsonResource;
class InvoiceItemResource extends JsonResource
{
/**
* Transform the resource into an array.
*
* @param \Illuminate\Http\Request $request
* @return array
*/
public function toArray($request)
{
return [
'id' => $this->id,
'name' => $this->name,
'description' => $this->description,
'discount_type' => $this->discount_type,
'price' => $this->price,
'quantity' => $this->quantity,
'unit_name' => $this->unit_name,
'discount' => $this->discount,
'discount_val' => $this->discount_val,
'tax' => $this->tax,
'total' => $this->total,
'invoice_id' => $this->invoice_id,
'item_id' => $this->item_id,
'company_id' => $this->company_id,
'base_price' => $this->base_price,
'exchange_rate' => $this->exchange_rate,
'base_discount_val' => $this->base_discount_val,
'base_tax' => $this->base_tax,
'base_total' => $this->base_total,
'recurring_invoice_id' => $this->recurring_invoice_id,
'taxes' => $this->when($this->taxes()->exists(), function () {
return TaxResource::collection($this->taxes);
}),
'fields' => $this->when($this->fields()->exists(), function () {
return CustomFieldValueResource::collection($this->fields);
}),
];
}
}

View File

@ -0,0 +1,74 @@
<?php
namespace Crater\Http\Resources\Customer;
use Illuminate\Http\Resources\Json\JsonResource;
class InvoiceResource extends JsonResource
{
/**
* Transform the resource into an array.
*
* @param \Illuminate\Http\Request $request
* @return array
*/
public function toArray($request)
{
return [
'id' => $this->id,
'invoice_date' => $this->invoice_date,
'due_date' => $this->due_date,
'invoice_number' => $this->invoice_number,
'reference_number' => $this->reference_number,
'status' => $this->status,
'paid_status' => $this->paid_status,
'tax_per_item' => $this->tax_per_item,
'discount_per_item' => $this->discount_per_item,
'notes' => $this->getNotes(),
'discount_type' => $this->discount_type,
'discount' => $this->discount,
'discount_val' => $this->discount_val,
'sub_total' => $this->sub_total,
'total' => $this->total,
'tax' => $this->tax,
'due_amount' => $this->due_amount,
'sent' => $this->sent,
'viewed' => $this->viewed,
'unique_hash' => $this->unique_hash,
'template_name' => $this->template_name,
'customer_id' => $this->customer_id,
'recurring_invoice_id' => $this->recurring_invoice_id,
'sequence_number' => $this->sequence_number,
'base_discount_val' => $this->base_discount_val,
'base_sub_total' => $this->base_sub_total,
'base_total' => $this->base_total,
'base_tax' => $this->base_tax,
'base_due_amount' => $this->base_due_amount,
'currency_id' => $this->currency_id,
'formatted_created_at' => $this->formattedCreatedAt,
'formatted_notes' => $this->formattedNotes,
'invoice_pdf_url' => $this->invoicePdfUrl,
'formatted_invoice_date' => $this->formattedInvoiceDate,
'formatted_due_date' => $this->formattedDueDate,
'payment_module_enabled' => $this->payment_module_enabled,
'items' => $this->when($this->items()->exists(), function () {
return InvoiceItemResource::collection($this->items);
}),
'customer' => $this->when($this->customer()->exists(), function () {
return new CustomerResource($this->customer);
}),
'taxes' => $this->when($this->taxes()->exists(), function () {
return TaxResource::collection($this->taxes);
}),
'fields' => $this->when($this->fields()->exists(), function () {
return CustomFieldValueResource::collection($this->fields);
}),
'company' => $this->when($this->company()->exists(), function () {
return new CompanyResource($this->company);
}),
'currency' => $this->when($this->currency()->exists(), function () {
return new CurrencyResource($this->currency);
}),
];
}
}

View File

@ -0,0 +1,19 @@
<?php
namespace Crater\Http\Resources\Customer;
use Illuminate\Http\Resources\Json\ResourceCollection;
class ItemCollection extends ResourceCollection
{
/**
* Transform the resource collection into an array.
*
* @param \Illuminate\Http\Request $request
* @return array
*/
public function toArray($request)
{
return parent::toArray($request);
}
}

View File

@ -0,0 +1,19 @@
<?php
namespace Crater\Http\Resources\Customer;
use Illuminate\Http\Resources\Json\ResourceCollection;
class PaymentCollection extends ResourceCollection
{
/**
* Transform the resource collection into an array.
*
* @param \Illuminate\Http\Request $request
* @return array
*/
public function toArray($request)
{
return parent::toArray($request);
}
}

View File

@ -0,0 +1,19 @@
<?php
namespace Crater\Http\Resources\Customer;
use Illuminate\Http\Resources\Json\ResourceCollection;
class PaymentMethodCollection extends ResourceCollection
{
/**
* Transform the resource collection into an array.
*
* @param \Illuminate\Http\Request $request
* @return array
*/
public function toArray($request)
{
return parent::toArray($request);
}
}

Some files were not shown because too many files have changed in this diff Show More