mirror of
https://github.com/invoiceninja/invoiceninja.git
synced 2025-06-03 08:24:34 -04:00
Merge branch 'v2'
This commit is contained in:
commit
7d1eeafebe
2
.github/workflows/phpunit.yml
vendored
2
.github/workflows/phpunit.yml
vendored
@ -82,7 +82,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Migrate Database
|
- name: Migrate Database
|
||||||
run: |
|
run: |
|
||||||
php artisan migrate:fresh --seed --force && php artisan db:seed --class=RandomDataSeeder --force
|
php artisan migrate:fresh --seed --force && php artisan db:seed --force
|
||||||
|
|
||||||
- name: Prepare JS/CSS assets
|
- name: Prepare JS/CSS assets
|
||||||
run: |
|
run: |
|
||||||
|
5
.prettierrc
Normal file
5
.prettierrc
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"semi": true,
|
||||||
|
"singleQuote": true,
|
||||||
|
"trailingComma": "es5"
|
||||||
|
}
|
@ -2,6 +2,7 @@
|
|||||||
<img src="https://raw.githubusercontent.com/hillelcoren/invoice-ninja/master/public/images/round_logo.png" alt="Sublime's custom image"/>
|
<img src="https://raw.githubusercontent.com/hillelcoren/invoice-ninja/master/public/images/round_logo.png" alt="Sublime's custom image"/>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|

|
||||||
[](https://travis-ci.org/invoiceninja/invoiceninja)
|
[](https://travis-ci.org/invoiceninja/invoiceninja)
|
||||||
[](https://codecov.io/gh/invoiceninja/invoiceninja)
|
[](https://codecov.io/gh/invoiceninja/invoiceninja)
|
||||||
[](https://www.codacy.com/app/turbo124/invoiceninja?utm_source=github.com&utm_medium=referral&utm_content=invoiceninja/invoiceninja&utm_campaign=Badge_Grade)
|
[](https://www.codacy.com/app/turbo124/invoiceninja?utm_source=github.com&utm_medium=referral&utm_content=invoiceninja/invoiceninja&utm_campaign=Badge_Grade)
|
||||||
|
@ -5,7 +5,9 @@ namespace App\Console\Commands;
|
|||||||
use App;
|
use App;
|
||||||
use App\Libraries\CurlUtils;
|
use App\Libraries\CurlUtils;
|
||||||
use App\Models\Account;
|
use App\Models\Account;
|
||||||
|
use App\Models\Client;
|
||||||
use App\Models\ClientContact;
|
use App\Models\ClientContact;
|
||||||
|
use App\Models\CompanyLedger;
|
||||||
use App\Models\Contact;
|
use App\Models\Contact;
|
||||||
use App\Models\Invitation;
|
use App\Models\Invitation;
|
||||||
use App\Models\Invoice;
|
use App\Models\Invoice;
|
||||||
@ -287,56 +289,59 @@ class CheckData extends Command
|
|||||||
|
|
||||||
private function checkInvoiceBalances()
|
private function checkInvoiceBalances()
|
||||||
{
|
{
|
||||||
// $invoices = DB::table('invoices')
|
|
||||||
// ->leftJoin('payments', function($join) {
|
|
||||||
// $join->on('payments.invoice_id', '=', 'invoices.id')
|
|
||||||
// ->where('payments.payment_status_id', '!=', 2)
|
|
||||||
// ->where('payments.payment_status_id', '!=', 3)
|
|
||||||
// ->where('payments.is_deleted', '=', 0);
|
|
||||||
// })
|
|
||||||
// ->where('invoices.updated_at', '>', '2017-10-01')
|
|
||||||
// ->groupBy('invoices.id')
|
|
||||||
// ->havingRaw('(invoices.amount - invoices.balance) != coalesce(sum(payments.amount - payments.refunded), 0)')
|
|
||||||
// ->get(['invoices.id', 'invoices.amount', 'invoices.balance', DB::raw('coalesce(sum(payments.amount - payments.refunded), 0)')]);
|
|
||||||
|
|
||||||
// $this->logMessage($invoices->count() . ' invoices with incorrect balances');
|
$wrong_balances = 0;
|
||||||
|
$wrong_paid_to_dates = 0;
|
||||||
|
|
||||||
|
foreach(Client::cursor() as $client)
|
||||||
|
{
|
||||||
|
$invoice_balance = $client->invoices->where('is_deleted', false)->sum('balance');
|
||||||
|
|
||||||
|
$ledger = CompanyLedger::where('client_id', $client->id)->orderBy('id', 'DESC')->first();
|
||||||
|
|
||||||
|
if($ledger && $invoice_balance != $client->balance)
|
||||||
|
{
|
||||||
|
$wrong_balances++;
|
||||||
|
$this->logMessage($client->present()->name . " - " . $client->id . " - balances do not match {$invoice_balance} - {$client->balance} - {$ledger->balance}");
|
||||||
|
|
||||||
|
$this->isValid = false;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->logMessage("{$wrong_balances} clients with incorrect balances");
|
||||||
|
|
||||||
|
|
||||||
// if ($invoices->count() > 0) {
|
|
||||||
// $this->isValid = false;
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private function checkClientBalances()
|
private function checkClientBalances()
|
||||||
{
|
{
|
||||||
// find all clients where the balance doesn't equal the sum of the outstanding invoices
|
|
||||||
// $clients = DB::table('clients')
|
|
||||||
// ->join('invoices', 'invoices.client_id', '=', 'clients.id')
|
|
||||||
// ->join('accounts', 'accounts.id', '=', 'clients.company_id')
|
|
||||||
// ->where('accounts.id', '!=', 20432)
|
|
||||||
// ->where('clients.is_deleted', '=', 0)
|
|
||||||
// ->where('invoices.is_deleted', '=', 0)
|
|
||||||
// ->where('invoices.is_public', '=', 1)
|
|
||||||
// ->where('invoices.invoice_type_id', '=', INVOICE_TYPE_STANDARD)
|
|
||||||
// ->where('invoices.is_recurring', '=', 0)
|
|
||||||
// ->havingRaw('abs(clients.balance - sum(invoices.balance)) > .01 and clients.balance != 999999999.9999');
|
|
||||||
|
|
||||||
// if ($this->option('client_id')) {
|
$wrong_balances = 0;
|
||||||
// $clients->where('clients.id', '=', $this->option('client_id'));
|
$wrong_paid_to_dates = 0;
|
||||||
// }
|
|
||||||
|
|
||||||
// $clients = $clients->groupBy('clients.id', 'clients.balance')
|
foreach(Client::cursor() as $client)
|
||||||
// ->orderBy('accounts.company_id', 'DESC')
|
{
|
||||||
// ->get(['accounts.company_id', 'clients.company_id', 'clients.id', 'clients.balance', 'clients.paid_to_date', DB::raw('sum(invoices.balance) actual_balance')]);
|
$invoice_balance = $client->invoices->where('is_deleted', false)->sum('balance');
|
||||||
// $this->logMessage($clients->count() . ' clients with incorrect balance/activities');
|
$invoice_amounts = $client->invoices->where('is_deleted', false)->sum('amount') - $invoice_balance;
|
||||||
|
|
||||||
// if ($clients->count() > 0) {
|
$ledger = CompanyLedger::where('client_id', $client->id)->orderBy('id', 'DESC')->first();
|
||||||
// $this->isValid = false;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// foreach ($clients as $client) {
|
if($ledger && (string)$invoice_amounts != rtrim($client->paid_to_date, "0"))
|
||||||
// $this->logMessage("=== Company: {$client->company_id} Account:{$client->company_id} Client:{$client->id} Balance:{$client->balance} Actual Balance:{$client->actual_balance} ===");
|
{
|
||||||
|
|
||||||
|
$wrong_paid_to_dates++;
|
||||||
|
$this->logMessage($client->present()->name . " - " . $client->id . " - client paid to dates do not match {$invoice_amounts} - " .rtrim($client->paid_to_date, "0"));
|
||||||
|
|
||||||
|
$this->isValid = false;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->logMessage("{$wrong_paid_to_dates} clients with incorrect paid_to_dates");
|
||||||
|
|
||||||
//}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private function checkLogoFiles()
|
private function checkLogoFiles()
|
||||||
|
@ -135,28 +135,44 @@ class CreateTestData extends Command
|
|||||||
$this->createClient($company, $user);
|
$this->createClient($company, $user);
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach ($company->clients as $client) {
|
for($x=0; $x<$this->count; $x++)
|
||||||
|
{
|
||||||
|
$client = $company->clients->random();
|
||||||
|
|
||||||
$this->info('creating invoice for client #'.$client->id);
|
$this->info('creating invoice for client #'.$client->id);
|
||||||
$this->createInvoice($client);
|
$this->createInvoice($client);
|
||||||
|
|
||||||
|
$client = $company->clients->random();
|
||||||
|
|
||||||
$this->info('creating credit for client #'.$client->id);
|
$this->info('creating credit for client #'.$client->id);
|
||||||
$this->createCredit($client);
|
$this->createCredit($client);
|
||||||
|
|
||||||
|
$client = $company->clients->random();
|
||||||
|
|
||||||
$this->info('creating quote for client #'.$client->id);
|
$this->info('creating quote for client #'.$client->id);
|
||||||
$this->createQuote($client);
|
$this->createQuote($client);
|
||||||
|
|
||||||
|
$client = $company->clients->random();
|
||||||
|
|
||||||
$this->info('creating expense for client #'.$client->id);
|
$this->info('creating expense for client #'.$client->id);
|
||||||
$this->createExpense($client);
|
$this->createExpense($client);
|
||||||
|
|
||||||
|
$client = $company->clients->random();
|
||||||
|
|
||||||
$this->info('creating vendor for client #'.$client->id);
|
$this->info('creating vendor for client #'.$client->id);
|
||||||
$this->createVendor($client);
|
$this->createVendor($client);
|
||||||
|
|
||||||
|
$client = $company->clients->random();
|
||||||
|
|
||||||
$this->info('creating task for client #'.$client->id);
|
$this->info('creating task for client #'.$client->id);
|
||||||
$this->createTask($client);
|
$this->createTask($client);
|
||||||
|
|
||||||
|
$client = $company->clients->random();
|
||||||
|
|
||||||
$this->info('creating project for client #'.$client->id);
|
$this->info('creating project for client #'.$client->id);
|
||||||
$this->createProject($client);
|
$this->createProject($client);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private function createMediumAccount()
|
private function createMediumAccount()
|
||||||
@ -217,49 +233,42 @@ class CreateTestData extends Command
|
|||||||
$this->createClient($company, $user);
|
$this->createClient($company, $user);
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach ($company->clients as $client) {
|
for($x=0; $x<$this->count; $x++)
|
||||||
$this->info('creating invoice for client #'.$client->id);
|
{
|
||||||
|
$client = $company->clients->random();
|
||||||
|
|
||||||
for ($i=0; $i<$this->count; $i++) {
|
$this->info('creating invoice for client #'.$client->id);
|
||||||
$this->createInvoice($client);
|
$this->createInvoice($client);
|
||||||
}
|
|
||||||
|
$client = $company->clients->random();
|
||||||
|
|
||||||
$this->info('creating credit for client #'.$client->id);
|
$this->info('creating credit for client #'.$client->id);
|
||||||
|
$this->createCredit($client);
|
||||||
|
|
||||||
for ($i=0; $i<$this->count; $i++) {
|
$client = $company->clients->random();
|
||||||
$this->createCredit($client);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
$this->info('creating quote for client #'.$client->id);
|
$this->info('creating quote for client #'.$client->id);
|
||||||
|
$this->createQuote($client);
|
||||||
|
|
||||||
for ($i=0; $i<$this->count; $i++) {
|
$client = $company->clients->random();
|
||||||
$this->createQuote($client);
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->info('creating expense for client #'.$client->id);
|
$this->info('creating expense for client #'.$client->id);
|
||||||
|
$this->createExpense($client);
|
||||||
for ($i=0; $i<$this->count; $i++) {
|
|
||||||
$this->createExpense($client);
|
$client = $company->clients->random();
|
||||||
}
|
|
||||||
|
|
||||||
$this->info('creating vendor for client #'.$client->id);
|
$this->info('creating vendor for client #'.$client->id);
|
||||||
|
$this->createVendor($client);
|
||||||
for ($i=0; $i<$this->count; $i++) {
|
|
||||||
$this->createVendor($client);
|
$client = $company->clients->random();
|
||||||
}
|
|
||||||
|
|
||||||
$this->info('creating task for client #'.$client->id);
|
$this->info('creating task for client #'.$client->id);
|
||||||
|
$this->createTask($client);
|
||||||
for ($i=0; $i<$this->count; $i++) {
|
|
||||||
$this->createTask($client);
|
$client = $company->clients->random();
|
||||||
}
|
|
||||||
|
|
||||||
$this->info('creating project for client #'.$client->id);
|
$this->info('creating project for client #'.$client->id);
|
||||||
|
$this->createProject($client);
|
||||||
for ($i=0; $i<$this->count; $i++) {
|
|
||||||
$this->createProject($client);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -322,25 +331,40 @@ class CreateTestData extends Command
|
|||||||
$this->createClient($company, $user);
|
$this->createClient($company, $user);
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach ($company->clients as $client) {
|
for($x=0; $x<$this->count; $x++)
|
||||||
|
{
|
||||||
|
$client = $company->clients->random();
|
||||||
|
|
||||||
$this->info('creating invoice for client #'.$client->id);
|
$this->info('creating invoice for client #'.$client->id);
|
||||||
$this->createInvoice($client);
|
$this->createInvoice($client);
|
||||||
|
|
||||||
|
$client = $company->clients->random();
|
||||||
|
|
||||||
$this->info('creating credit for client #'.$client->id);
|
$this->info('creating credit for client #'.$client->id);
|
||||||
$this->createCredit($client);
|
$this->createCredit($client);
|
||||||
|
|
||||||
|
$client = $company->clients->random();
|
||||||
|
|
||||||
$this->info('creating quote for client #'.$client->id);
|
$this->info('creating quote for client #'.$client->id);
|
||||||
$this->createQuote($client);
|
$this->createQuote($client);
|
||||||
|
|
||||||
|
$client = $company->clients->random();
|
||||||
|
|
||||||
$this->info('creating expense for client #'.$client->id);
|
$this->info('creating expense for client #'.$client->id);
|
||||||
$this->createExpense($client);
|
$this->createExpense($client);
|
||||||
|
|
||||||
|
$client = $company->clients->random();
|
||||||
|
|
||||||
$this->info('creating vendor for client #'.$client->id);
|
$this->info('creating vendor for client #'.$client->id);
|
||||||
$this->createVendor($client);
|
$this->createVendor($client);
|
||||||
|
|
||||||
|
$client = $company->clients->random();
|
||||||
|
|
||||||
$this->info('creating task for client #'.$client->id);
|
$this->info('creating task for client #'.$client->id);
|
||||||
$this->createTask($client);
|
$this->createTask($client);
|
||||||
|
|
||||||
|
$client = $company->clients->random();
|
||||||
|
|
||||||
$this->info('creating project for client #'.$client->id);
|
$this->info('creating project for client #'.$client->id);
|
||||||
$this->createProject($client);
|
$this->createProject($client);
|
||||||
}
|
}
|
||||||
|
@ -38,6 +38,8 @@ class PostUpdate extends Command
|
|||||||
{
|
{
|
||||||
set_time_limit(0);
|
set_time_limit(0);
|
||||||
|
|
||||||
|
info("running post update");
|
||||||
|
|
||||||
try {
|
try {
|
||||||
Artisan::call('migrate');
|
Artisan::call('migrate');
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
@ -85,12 +87,14 @@ class PostUpdate extends Command
|
|||||||
$output = $factory->createOutput();
|
$output = $factory->createOutput();
|
||||||
|
|
||||||
$input = new \Symfony\Component\Console\Input\ArrayInput(array(
|
$input = new \Symfony\Component\Console\Input\ArrayInput(array(
|
||||||
'command' => 'update',
|
'command' => 'install',
|
||||||
));
|
));
|
||||||
$input->setInteractive(false);
|
$input->setInteractive(false);
|
||||||
echo "<pre>";
|
echo "<pre>";
|
||||||
$cmdret = $app->doRun($input,$output);
|
$cmdret = $app->doRun($input,$output);
|
||||||
echo "end!";
|
echo "end!";
|
||||||
|
|
||||||
|
\Log::error(print_r($cmdret,1));
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -29,8 +29,8 @@ class CompanySettings extends BaseSettings
|
|||||||
|
|
||||||
public $enable_client_portal_tasks = false;
|
public $enable_client_portal_tasks = false;
|
||||||
public $enable_client_portal_password = false;
|
public $enable_client_portal_password = false;
|
||||||
public $enable_client_portal = true;//implemented
|
public $enable_client_portal = true; //implemented
|
||||||
public $enable_client_portal_dashboard = true;//implemented
|
public $enable_client_portal_dashboard = true; //implemented
|
||||||
public $signature_on_pdf = false;
|
public $signature_on_pdf = false;
|
||||||
public $document_email_attachment = false;
|
public $document_email_attachment = false;
|
||||||
public $send_portal_password = false;
|
public $send_portal_password = false;
|
||||||
@ -55,7 +55,7 @@ class CompanySettings extends BaseSettings
|
|||||||
|
|
||||||
public $default_task_rate = 0;
|
public $default_task_rate = 0;
|
||||||
|
|
||||||
public $payment_terms = -1;
|
public $payment_terms = "";
|
||||||
public $send_reminders = false;
|
public $send_reminders = false;
|
||||||
|
|
||||||
public $custom_message_dashboard = '';
|
public $custom_message_dashboard = '';
|
||||||
@ -231,7 +231,10 @@ class CompanySettings extends BaseSettings
|
|||||||
public $portal_custom_footer = '';
|
public $portal_custom_footer = '';
|
||||||
public $portal_custom_js = '';
|
public $portal_custom_js = '';
|
||||||
|
|
||||||
|
public $client_can_register = false;
|
||||||
|
|
||||||
public static $casts = [
|
public static $casts = [
|
||||||
|
'client_can_register' => 'bool',
|
||||||
'portal_design_id' => 'string',
|
'portal_design_id' => 'string',
|
||||||
'late_fee_endless_percent' => 'float',
|
'late_fee_endless_percent' => 'float',
|
||||||
'late_fee_endless_amount' => 'float',
|
'late_fee_endless_amount' => 'float',
|
||||||
@ -348,7 +351,7 @@ class CompanySettings extends BaseSettings
|
|||||||
'credit_footer' => 'string',
|
'credit_footer' => 'string',
|
||||||
'credit_terms' => 'string',
|
'credit_terms' => 'string',
|
||||||
'name' => 'string',
|
'name' => 'string',
|
||||||
'payment_terms' => 'integer',
|
'payment_terms' => 'string',
|
||||||
'payment_type_id' => 'string',
|
'payment_type_id' => 'string',
|
||||||
'phone' => 'string',
|
'phone' => 'string',
|
||||||
'postal_code' => 'string',
|
'postal_code' => 'string',
|
||||||
@ -411,7 +414,7 @@ class CompanySettings extends BaseSettings
|
|||||||
'custom_value4' => 'string',
|
'custom_value4' => 'string',
|
||||||
'inclusive_taxes' => 'bool',
|
'inclusive_taxes' => 'bool',
|
||||||
'name' => 'string',
|
'name' => 'string',
|
||||||
'payment_terms' => 'integer',
|
'payment_terms' => 'string',
|
||||||
'payment_type_id' => 'string',
|
'payment_type_id' => 'string',
|
||||||
'phone' => 'string',
|
'phone' => 'string',
|
||||||
'postal_code' => 'string',
|
'postal_code' => 'string',
|
||||||
@ -479,7 +482,7 @@ class CompanySettings extends BaseSettings
|
|||||||
$data->timezone_id = (string) config('ninja.i18n.timezone_id');
|
$data->timezone_id = (string) config('ninja.i18n.timezone_id');
|
||||||
$data->currency_id = (string) config('ninja.i18n.currency_id');
|
$data->currency_id = (string) config('ninja.i18n.currency_id');
|
||||||
$data->language_id = (string) config('ninja.i18n.language_id');
|
$data->language_id = (string) config('ninja.i18n.language_id');
|
||||||
$data->payment_terms = (int) config('ninja.i18n.payment_terms');
|
$data->payment_terms = (string) config('ninja.i18n.payment_terms');
|
||||||
$data->military_time = (bool) config('ninja.i18n.military_time');
|
$data->military_time = (bool) config('ninja.i18n.military_time');
|
||||||
$data->date_format_id = (string) config('ninja.i18n.date_format_id');
|
$data->date_format_id = (string) config('ninja.i18n.date_format_id');
|
||||||
$data->country_id = (string) config('ninja.i18n.country_id');
|
$data->country_id = (string) config('ninja.i18n.country_id');
|
||||||
|
@ -15,15 +15,16 @@ use Exception;
|
|||||||
use Illuminate\Auth\Access\AuthorizationException;
|
use Illuminate\Auth\Access\AuthorizationException;
|
||||||
use Illuminate\Auth\AuthenticationException;
|
use Illuminate\Auth\AuthenticationException;
|
||||||
use Illuminate\Database\Eloquent\ModelNotFoundException as ModelNotFoundException;
|
use Illuminate\Database\Eloquent\ModelNotFoundException as ModelNotFoundException;
|
||||||
|
use Illuminate\Database\Eloquent\RelationNotFoundException;
|
||||||
use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
|
use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
|
||||||
use Illuminate\Http\Exceptions\ThrottleRequestsException;
|
use Illuminate\Http\Exceptions\ThrottleRequestsException;
|
||||||
use Illuminate\Support\Arr;
|
use Illuminate\Support\Arr;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
use Illuminate\Validation\ValidationException;
|
use Illuminate\Validation\ValidationException;
|
||||||
|
use Sentry\State\Scope;
|
||||||
use Symfony\Component\Debug\Exception\FatalThrowableError;
|
use Symfony\Component\Debug\Exception\FatalThrowableError;
|
||||||
use Symfony\Component\HttpKernel\Exception\MethodNotAllowedHttpException;
|
use Symfony\Component\HttpKernel\Exception\MethodNotAllowedHttpException;
|
||||||
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
||||||
use Illuminate\Database\Eloquent\RelationNotFoundException;
|
|
||||||
use Sentry\State\Scope;
|
|
||||||
use function Sentry\configureScope;
|
use function Sentry\configureScope;
|
||||||
|
|
||||||
class Handler extends ExceptionHandler
|
class Handler extends ExceptionHandler
|
||||||
@ -55,9 +56,12 @@ class Handler extends ExceptionHandler
|
|||||||
*/
|
*/
|
||||||
public function report(Exception $exception)
|
public function report(Exception $exception)
|
||||||
{
|
{
|
||||||
|
if(!Schema::hasTable('accounts'))
|
||||||
|
return;
|
||||||
|
|
||||||
if (app()->bound('sentry') && $this->shouldReport($exception)) {
|
if (app()->bound('sentry') && $this->shouldReport($exception)) {
|
||||||
app('sentry')->configureScope(function (Scope $scope): void {
|
app('sentry')->configureScope(function (Scope $scope): void {
|
||||||
if (auth()->guard('contact')->user() && auth()->guard('contact')->user()->company->account->report_errors) {
|
if (auth()->guard('contact') && auth()->guard('contact')->user() && auth()->guard('contact')->user()->company->account->report_errors) {
|
||||||
$scope->setUser([
|
$scope->setUser([
|
||||||
'id' => auth()->guard('contact')->user()->company->account->key,
|
'id' => auth()->guard('contact')->user()->company->account->key,
|
||||||
'email' => "anonymous@example.com",
|
'email' => "anonymous@example.com",
|
||||||
|
@ -26,15 +26,16 @@ class CloneQuoteToInvoiceFactory
|
|||||||
unset($quote_array['client']);
|
unset($quote_array['client']);
|
||||||
unset($quote_array['company']);
|
unset($quote_array['company']);
|
||||||
unset($quote_array['hashed_id']);
|
unset($quote_array['hashed_id']);
|
||||||
|
unset($quote_array['invoice_id']);
|
||||||
unset($quote_array['id']);
|
unset($quote_array['id']);
|
||||||
|
|
||||||
foreach($quote_array as $key => $value)
|
foreach($quote_array as $key => $value)
|
||||||
$invoice->{$key} = $value;
|
$invoice->{$key} = $value;
|
||||||
|
|
||||||
|
$invoice->status_id = Invoice::STATUS_DRAFT;
|
||||||
$invoice->due_date = null;
|
$invoice->due_date = null;
|
||||||
$invoice->partial_due_date = null;
|
$invoice->partial_due_date = null;
|
||||||
$invoice->number = null;
|
$invoice->number = null;
|
||||||
$invoice->status_id = null;
|
|
||||||
|
|
||||||
return $invoice;
|
return $invoice;
|
||||||
|
|
||||||
|
26
app/Factory/PaymentTermFactory.php
Normal file
26
app/Factory/PaymentTermFactory.php
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Invoice Ninja (https://invoiceninja.com)
|
||||||
|
*
|
||||||
|
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||||
|
*
|
||||||
|
* @copyright Copyright (c) 2020. Invoice Ninja LLC (https://invoiceninja.com)
|
||||||
|
*
|
||||||
|
* @license https://opensource.org/licenses/AAL
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace App\Factory;
|
||||||
|
|
||||||
|
use App\Models\PaymentTerm;
|
||||||
|
|
||||||
|
class PaymentTermFactory
|
||||||
|
{
|
||||||
|
public static function create(int $company_id, int $user_id) :PaymentTerm
|
||||||
|
{
|
||||||
|
$payment_term = new PaymentTerm;
|
||||||
|
$payment_term->user_id = $user_id;
|
||||||
|
$payment_term->company_id = $company_id;
|
||||||
|
|
||||||
|
return $payment_term;
|
||||||
|
}
|
||||||
|
}
|
@ -82,6 +82,11 @@ class QuoteFilters extends QueryFilters
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function number($number = '')
|
||||||
|
{
|
||||||
|
return $this->builder->where('number', 'like', '%'.$number.'%');
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sorts the list based on $sort
|
* Sorts the list based on $sort
|
||||||
*
|
*
|
||||||
|
@ -62,8 +62,14 @@ class GmailTransport extends Transport
|
|||||||
$this->gmail->cc($message->getCc());
|
$this->gmail->cc($message->getCc());
|
||||||
$this->gmail->bcc($message->getBcc());
|
$this->gmail->bcc($message->getBcc());
|
||||||
|
|
||||||
|
\Log::error(print_r($message->getChildren(),1));
|
||||||
|
|
||||||
|
foreach($message->getChildren() as $child)
|
||||||
|
$this->gmail->attach($child); //todo this should 'just work'
|
||||||
|
|
||||||
$this->gmail->send();
|
$this->gmail->send();
|
||||||
|
|
||||||
|
|
||||||
$this->sendPerformed($message);
|
$this->sendPerformed($message);
|
||||||
|
|
||||||
return $this->numberOfRecipients($message);
|
return $this->numberOfRecipients($message);
|
||||||
|
@ -23,6 +23,7 @@ use App\Utils\Traits\AppSetup;
|
|||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Illuminate\Support\Facades\Log;
|
use Illuminate\Support\Facades\Log;
|
||||||
use Illuminate\Support\Facades\Request as Input;
|
use Illuminate\Support\Facades\Request as Input;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
use League\Fractal\Manager;
|
use League\Fractal\Manager;
|
||||||
use League\Fractal\Pagination\IlluminatePaginatorAdapter;
|
use League\Fractal\Pagination\IlluminatePaginatorAdapter;
|
||||||
use League\Fractal\Resource\Collection;
|
use League\Fractal\Resource\Collection;
|
||||||
@ -265,6 +266,7 @@ class BaseController extends Controller
|
|||||||
'company.quotes.invitations.contact',
|
'company.quotes.invitations.contact',
|
||||||
'company.quotes.invitations.company',
|
'company.quotes.invitations.company',
|
||||||
'company.credits',
|
'company.credits',
|
||||||
|
'company.payment_terms',
|
||||||
//'company.credits.invitations.contact',
|
//'company.credits.invitations.contact',
|
||||||
//'company.credits.invitations.company',
|
//'company.credits.invitations.company',
|
||||||
'company.vendors.contacts',
|
'company.vendors.contacts',
|
||||||
@ -282,6 +284,7 @@ class BaseController extends Controller
|
|||||||
'company.users.company_user',
|
'company.users.company_user',
|
||||||
'company.tax_rates',
|
'company.tax_rates',
|
||||||
'company.groups',
|
'company.groups',
|
||||||
|
'company.payment_terms',
|
||||||
];
|
];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -311,10 +314,16 @@ class BaseController extends Controller
|
|||||||
|
|
||||||
public function flutterRoute()
|
public function flutterRoute()
|
||||||
{
|
{
|
||||||
if ((bool)$this->checkAppSetup() !== false) {
|
|
||||||
|
// // Ensure all request are over HTTPS in production
|
||||||
|
// if (! request()->secure()) {
|
||||||
|
// return redirect()->secure(request()->path());
|
||||||
|
// }
|
||||||
|
|
||||||
|
if ((bool)$this->checkAppSetup() !== false && Schema::hasTable('accounts') && $account = Account::all()->first()) {
|
||||||
$data = [];
|
$data = [];
|
||||||
|
|
||||||
if (Ninja::isSelfHost() && $account = Account::all()->first()) {
|
if (Ninja::isSelfHost()) {
|
||||||
$data['report_errors'] = $account->report_errors;
|
$data['report_errors'] = $account->report_errors;
|
||||||
} else {
|
} else {
|
||||||
$data['report_errors'] = true;
|
$data['report_errors'] = true;
|
||||||
|
@ -41,7 +41,7 @@ class InvitationController extends Controller
|
|||||||
if ((bool)$invitation->contact->client->getSetting('enable_client_portal_password') !== false) {
|
if ((bool)$invitation->contact->client->getSetting('enable_client_portal_password') !== false) {
|
||||||
$this->middleware('auth:contact');
|
$this->middleware('auth:contact');
|
||||||
} else {
|
} else {
|
||||||
auth()->guard('contact')->login($invitation->contact, false);
|
auth()->guard('contact')->login($invitation->contact, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!request()->has('silent')) {
|
if (!request()->has('silent')) {
|
||||||
|
@ -23,13 +23,13 @@ class SwitchCompanyController extends Controller
|
|||||||
|
|
||||||
public function __invoke(string $contact)
|
public function __invoke(string $contact)
|
||||||
{
|
{
|
||||||
$client_contact = ClientContact::query()
|
|
||||||
->where('user_id', auth()->user()->id)
|
$client_contact = ClientContact::where('email', auth()->user()->email)
|
||||||
->where('id', $this->transformKeys($contact))
|
->where('id', $this->transformKeys($contact))
|
||||||
->first();
|
->first();
|
||||||
|
|
||||||
Auth::guard('contact')->login($client_contact, true);
|
Auth::guard('contact')->login($client_contact, true);
|
||||||
|
|
||||||
return back();
|
return redirect('/client/dashboard');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -20,6 +20,7 @@ use App\Http\Requests\Company\StoreCompanyRequest;
|
|||||||
use App\Http\Requests\Company\UpdateCompanyRequest;
|
use App\Http\Requests\Company\UpdateCompanyRequest;
|
||||||
use App\Http\Requests\SignupRequest;
|
use App\Http\Requests\SignupRequest;
|
||||||
use App\Jobs\Company\CreateCompany;
|
use App\Jobs\Company\CreateCompany;
|
||||||
|
use App\Jobs\Company\CreateCompanyPaymentTerms;
|
||||||
use App\Jobs\Company\CreateCompanyToken;
|
use App\Jobs\Company\CreateCompanyToken;
|
||||||
use App\Jobs\Ninja\RefundCancelledAccount;
|
use App\Jobs\Ninja\RefundCancelledAccount;
|
||||||
use App\Jobs\RegisterNewAccount;
|
use App\Jobs\RegisterNewAccount;
|
||||||
@ -204,6 +205,8 @@ class CompanyController extends BaseController
|
|||||||
|
|
||||||
$company = CreateCompany::dispatchNow($request->all(), auth()->user()->company()->account);
|
$company = CreateCompany::dispatchNow($request->all(), auth()->user()->company()->account);
|
||||||
|
|
||||||
|
CreateCompanyPaymentTerms::dispatchNow($company, auth()->user());
|
||||||
|
|
||||||
$company = $this->company_repo->save($request->all(), $company);
|
$company = $this->company_repo->save($request->all(), $company);
|
||||||
|
|
||||||
$this->uploadLogo($request->file('company_logo'), $company, $company);
|
$this->uploadLogo($request->file('company_logo'), $company, $company);
|
||||||
|
@ -14,7 +14,7 @@ namespace App\Http\Controllers;
|
|||||||
use App\Helpers\Email\InvoiceEmail;
|
use App\Helpers\Email\InvoiceEmail;
|
||||||
use App\Http\Requests\Email\SendEmailRequest;
|
use App\Http\Requests\Email\SendEmailRequest;
|
||||||
use App\Jobs\Invoice\EmailInvoice;
|
use App\Jobs\Invoice\EmailInvoice;
|
||||||
use App\Jobs\Mail\EntitySentEmail;
|
use App\Jobs\Mail\EntitySentMailer;
|
||||||
use App\Models\Credit;
|
use App\Models\Credit;
|
||||||
use App\Models\Invoice;
|
use App\Models\Invoice;
|
||||||
use App\Models\Quote;
|
use App\Models\Quote;
|
||||||
@ -115,14 +115,17 @@ class EmailController extends BaseController
|
|||||||
$entity_string = strtolower(class_basename($entity_obj));
|
$entity_string = strtolower(class_basename($entity_obj));
|
||||||
|
|
||||||
$entity_obj->invitations->each(function ($invitation) use ($subject, $body, $entity_string, $entity_obj) {
|
$entity_obj->invitations->each(function ($invitation) use ($subject, $body, $entity_string, $entity_obj) {
|
||||||
|
|
||||||
if ($invitation->contact->send_email && $invitation->contact->email) {
|
if ($invitation->contact->send_email && $invitation->contact->email) {
|
||||||
|
|
||||||
$when = now()->addSeconds(1);
|
$when = now()->addSeconds(1);
|
||||||
|
|
||||||
$invitation->contact->notify((new SendGenericNotification($invitation, $entity_string, $subject, $body))->delay($when));
|
$invitation->contact->notify((new SendGenericNotification($invitation, $entity_string, $subject, $body))->delay($when));
|
||||||
|
|
||||||
EntitySentEmail::dispatch($invitation, $entity_string, $entity_obj->user, $invitation->company);
|
EntitySentMailer::dispatch($invitation, $entity_string, $entity_obj->user, $invitation->company);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
if ($this instanceof Invoice) {
|
if ($this instanceof Invoice) {
|
||||||
|
@ -670,6 +670,9 @@ class InvoiceController extends BaseController
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'delete':
|
case 'delete':
|
||||||
|
//need to make sure the invoice is cancelled first!!
|
||||||
|
$invoice->service()->handleCancellation()->save();
|
||||||
|
|
||||||
$this->invoice_repo->delete($invoice);
|
$this->invoice_repo->delete($invoice);
|
||||||
|
|
||||||
if (!$bulk) {
|
if (!$bulk) {
|
||||||
|
@ -366,7 +366,7 @@ class MigrationController extends BaseController
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
StartMigration::dispatch(base_path("storage/app/public/$migration_file"), $user, $company);
|
StartMigration::dispatch(base_path("storage/app/public/$migration_file"), $user, $company)->delay(now()->addSeconds(60));
|
||||||
|
|
||||||
return response()->json([
|
return response()->json([
|
||||||
'_id' => Str::uuid(),
|
'_id' => Str::uuid(),
|
||||||
|
12
app/Http/Controllers/OpenAPI/PaymentTermSchema.php
Normal file
12
app/Http/Controllers/OpenAPI/PaymentTermSchema.php
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* @OA\Schema(
|
||||||
|
* schema="PaymentTerm",
|
||||||
|
* type="object",
|
||||||
|
* @OA\Property(property="num_days", type="integer", example="1", description="The payment term length in days"),
|
||||||
|
* @OA\Property(property="name", type="string", example="NET 1", description="The payment term length in string format"),
|
||||||
|
* @OA\Property(property="created_at", type="number", format="integer", example="134341234234", description="Timestamp"),
|
||||||
|
* @OA\Property(property="updated_at", type="number", format="integer", example="134341234234", description="Timestamp"),
|
||||||
|
* @OA\Property(property="archived_at", type="number", format="integer", example="134341234234", description="Timestamp"),
|
||||||
|
* )
|
||||||
|
*/
|
477
app/Http/Controllers/PaymentTermController.php
Normal file
477
app/Http/Controllers/PaymentTermController.php
Normal file
@ -0,0 +1,477 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
|
use App\Factory\PaymentTermFactory;
|
||||||
|
use App\Http\Requests\PaymentTerm\CreatePaymentTermRequest;
|
||||||
|
use App\Http\Requests\PaymentTerm\DestroyPaymentTermRequest;
|
||||||
|
use App\Http\Requests\PaymentTerm\ShowPaymentTermRequest;
|
||||||
|
use App\Http\Requests\PaymentTerm\StorePaymentTermRequest;
|
||||||
|
use App\Http\Requests\PaymentTerm\UpdatePaymentTermRequest;
|
||||||
|
use App\Models\PaymentTerm;
|
||||||
|
use App\Repositories\PaymentTermRepository;
|
||||||
|
use App\Transformers\PaymentTermTransformer;
|
||||||
|
use App\Utils\Traits\MakesHash;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
|
||||||
|
class PaymentTermController extends BaseController
|
||||||
|
{
|
||||||
|
use MakesHash;
|
||||||
|
|
||||||
|
protected $entity_type = PaymentTerm::class;
|
||||||
|
|
||||||
|
protected $entity_transformer = PaymentTermTransformer::class;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var PaymentRepository
|
||||||
|
*/
|
||||||
|
protected $payment_term_repo;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* PaymentTermController constructor.
|
||||||
|
*
|
||||||
|
* @param \App\Repositories\PaymentTermRepository $payment_term_repo The payment term repo
|
||||||
|
*/
|
||||||
|
public function __construct(PaymentTermRepository $payment_term_repo)
|
||||||
|
{
|
||||||
|
parent::__construct();
|
||||||
|
|
||||||
|
$this->payment_term_repo = $payment_term_repo;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @OA\Get(
|
||||||
|
* path="/api/v1/payment_terms",
|
||||||
|
* operationId="getPaymentTerms",
|
||||||
|
* tags={"payment_terms"},
|
||||||
|
* summary="Gets a list of payment terms",
|
||||||
|
* description="Lists payment terms",
|
||||||
|
* @OA\Parameter(ref="#/components/parameters/X-Api-Secret"),
|
||||||
|
* @OA\Parameter(ref="#/components/parameters/X-Api-Token"),
|
||||||
|
* @OA\Parameter(ref="#/components/parameters/X-Requested-With"),
|
||||||
|
* @OA\Parameter(ref="#/components/parameters/include"),
|
||||||
|
* @OA\Parameter(ref="#/components/parameters/index"),
|
||||||
|
* @OA\Response(
|
||||||
|
* response=200,
|
||||||
|
* description="A list of payment terms",
|
||||||
|
* @OA\Header(header="X-API-Version", ref="#/components/headers/X-API-Version"),
|
||||||
|
* @OA\Header(header="X-RateLimit-Remaining", ref="#/components/headers/X-RateLimit-Remaining"),
|
||||||
|
* @OA\Header(header="X-RateLimit-Limit", ref="#/components/headers/X-RateLimit-Limit"),
|
||||||
|
* @OA\JsonContent(ref="#/components/schemas/PaymentTerm"),
|
||||||
|
* ),
|
||||||
|
* @OA\Response(
|
||||||
|
* response=422,
|
||||||
|
* description="Validation error",
|
||||||
|
* @OA\JsonContent(ref="#/components/schemas/ValidationError"),
|
||||||
|
|
||||||
|
* ),
|
||||||
|
* @OA\Response(
|
||||||
|
* response="default",
|
||||||
|
* description="Unexpected Error",
|
||||||
|
* @OA\JsonContent(ref="#/components/schemas/Error"),
|
||||||
|
* ),
|
||||||
|
* )
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public function index()
|
||||||
|
{
|
||||||
|
$payment_terms = PaymentTerm::whereCompanyId(auth()->user()->company()->id)->orWhere('company_id', null);
|
||||||
|
|
||||||
|
return $this->listResponse($payment_terms);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show the form for creating a new resource.
|
||||||
|
*
|
||||||
|
* @param \App\Http\Requests\Payment\CreatePaymentTermRequest $request The request
|
||||||
|
*
|
||||||
|
* @return \Illuminate\Http\Response
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @OA\Get(
|
||||||
|
* path="/api/v1/payment_terms/create",
|
||||||
|
* operationId="getPaymentTermsCreate",
|
||||||
|
* tags={"payment_terms"},
|
||||||
|
* summary="Gets a new blank PaymentTerm object",
|
||||||
|
* description="Returns a blank object with default values",
|
||||||
|
* @OA\Parameter(ref="#/components/parameters/X-Api-Secret"),
|
||||||
|
* @OA\Parameter(ref="#/components/parameters/X-Api-Token"),
|
||||||
|
* @OA\Parameter(ref="#/components/parameters/X-Requested-With"),
|
||||||
|
* @OA\Parameter(ref="#/components/parameters/include"),
|
||||||
|
* @OA\Response(
|
||||||
|
* response=200,
|
||||||
|
* description="A blank PaymentTerm object",
|
||||||
|
* @OA\Header(header="X-API-Version", ref="#/components/headers/X-API-Version"),
|
||||||
|
* @OA\Header(header="X-RateLimit-Remaining", ref="#/components/headers/X-RateLimit-Remaining"),
|
||||||
|
* @OA\Header(header="X-RateLimit-Limit", ref="#/components/headers/X-RateLimit-Limit"),
|
||||||
|
* @OA\JsonContent(ref="#/components/schemas/Payment"),
|
||||||
|
* ),
|
||||||
|
* @OA\Response(
|
||||||
|
* response=422,
|
||||||
|
* description="Validation error",
|
||||||
|
* @OA\JsonContent(ref="#/components/schemas/ValidationError"),
|
||||||
|
*
|
||||||
|
* ),
|
||||||
|
* @OA\Response(
|
||||||
|
* response="default",
|
||||||
|
* description="Unexpected Error",
|
||||||
|
* @OA\JsonContent(ref="#/components/schemas/Error"),
|
||||||
|
* ),
|
||||||
|
* )
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public function create(CreatePaymentTermRequest $request)
|
||||||
|
{
|
||||||
|
$payment_term = PaymentTermFactory::create(auth()->user()->company()->id, auth()->user()->id);
|
||||||
|
|
||||||
|
return $this->itemResponse($payment_term);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Store a newly created resource in storage.
|
||||||
|
*
|
||||||
|
* @param \App\Http\Requests\Payment\StorePaymentRequest $request The request
|
||||||
|
*
|
||||||
|
* @return \Illuminate\Http\Response
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @OA\Post(
|
||||||
|
* path="/api/v1/payment_terms",
|
||||||
|
* operationId="storePaymentTerm",
|
||||||
|
* tags={"payment_terms"},
|
||||||
|
* summary="Adds a Payment",
|
||||||
|
* description="Adds a Payment Term to the system",
|
||||||
|
* @OA\Parameter(ref="#/components/parameters/X-Api-Secret"),
|
||||||
|
* @OA\Parameter(ref="#/components/parameters/X-Api-Token"),
|
||||||
|
* @OA\Parameter(ref="#/components/parameters/X-Requested-With"),
|
||||||
|
* @OA\Parameter(ref="#/components/parameters/include"),
|
||||||
|
* @OA\RequestBody(
|
||||||
|
* description="The payment_terms request",
|
||||||
|
* required=true,
|
||||||
|
* @OA\JsonContent(ref="#/components/schemas/PaymentTerm"),
|
||||||
|
* ),
|
||||||
|
* @OA\Response(
|
||||||
|
* response=200,
|
||||||
|
* description="Returns the saved Payment object",
|
||||||
|
* @OA\Header(header="X-API-Version", ref="#/components/headers/X-API-Version"),
|
||||||
|
* @OA\Header(header="X-RateLimit-Remaining", ref="#/components/headers/X-RateLimit-Remaining"),
|
||||||
|
* @OA\Header(header="X-RateLimit-Limit", ref="#/components/headers/X-RateLimit-Limit"),
|
||||||
|
* @OA\JsonContent(ref="#/components/schemas/PaymentTerm"),
|
||||||
|
* ),
|
||||||
|
* @OA\Response(
|
||||||
|
* response=422,
|
||||||
|
* description="Validation error",
|
||||||
|
* @OA\JsonContent(ref="#/components/schemas/ValidationError"),
|
||||||
|
*
|
||||||
|
* ),
|
||||||
|
* @OA\Response(
|
||||||
|
* response="default",
|
||||||
|
* description="Unexpected Error",
|
||||||
|
* @OA\JsonContent(ref="#/components/schemas/Error"),
|
||||||
|
* ),
|
||||||
|
* )
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public function store(StorePaymentTermRequest $request)
|
||||||
|
{
|
||||||
|
$payment_term = PaymentTermFactory::create(auth()->user()->company()->id, auth()->user()->id);
|
||||||
|
$payment_term->fill($request->all());
|
||||||
|
$payment_term->save();
|
||||||
|
|
||||||
|
return $this->itemResponse($payment_term->fresh());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @OA\Get(
|
||||||
|
* path="/api/v1/payment_terms/{id}",
|
||||||
|
* operationId="showPaymentTerm",
|
||||||
|
* tags={"payment_terms"},
|
||||||
|
* summary="Shows a Payment Term",
|
||||||
|
* description="Displays an Payment Term by id",
|
||||||
|
* @OA\Parameter(ref="#/components/parameters/X-Api-Secret"),
|
||||||
|
* @OA\Parameter(ref="#/components/parameters/X-Api-Token"),
|
||||||
|
* @OA\Parameter(ref="#/components/parameters/X-Requested-With"),
|
||||||
|
* @OA\Parameter(ref="#/components/parameters/include"),
|
||||||
|
* @OA\Parameter(
|
||||||
|
* name="id",
|
||||||
|
* in="path",
|
||||||
|
* description="The Payment Term Hashed ID",
|
||||||
|
* example="D2J234DFA",
|
||||||
|
* required=true,
|
||||||
|
* @OA\Schema(
|
||||||
|
* type="string",
|
||||||
|
* format="string",
|
||||||
|
* ),
|
||||||
|
* ),
|
||||||
|
* @OA\Response(
|
||||||
|
* response=200,
|
||||||
|
* description="Returns the Payment Term object",
|
||||||
|
* @OA\Header(header="X-API-Version", ref="#/components/headers/X-API-Version"),
|
||||||
|
* @OA\Header(header="X-RateLimit-Remaining", ref="#/components/headers/X-RateLimit-Remaining"),
|
||||||
|
* @OA\Header(header="X-RateLimit-Limit", ref="#/components/headers/X-RateLimit-Limit"),
|
||||||
|
* @OA\JsonContent(ref="#/components/schemas/PaymentTerm"),
|
||||||
|
* ),
|
||||||
|
* @OA\Response(
|
||||||
|
* response=422,
|
||||||
|
* description="Validation error",
|
||||||
|
* @OA\JsonContent(ref="#/components/schemas/ValidationError"),
|
||||||
|
*
|
||||||
|
* ),
|
||||||
|
* @OA\Response(
|
||||||
|
* response="default",
|
||||||
|
* description="Unexpected Error",
|
||||||
|
* @OA\JsonContent(ref="#/components/schemas/Error"),
|
||||||
|
* ),
|
||||||
|
* )
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public function show(ShowPaymentTermRequest $request, PaymentTerm $payment_term)
|
||||||
|
{
|
||||||
|
return $this->itemResponse($payment_term);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @OA\Get(
|
||||||
|
* path="/api/v1/payment_terms/{id}/edit",
|
||||||
|
* operationId="editPaymentTerms",
|
||||||
|
* tags={"payment_terms"},
|
||||||
|
* summary="Shows an Payment Term for editting",
|
||||||
|
* description="Displays an Payment Term by id",
|
||||||
|
* @OA\Parameter(ref="#/components/parameters/X-Api-Secret"),
|
||||||
|
* @OA\Parameter(ref="#/components/parameters/X-Api-Token"),
|
||||||
|
* @OA\Parameter(ref="#/components/parameters/X-Requested-With"),
|
||||||
|
* @OA\Parameter(ref="#/components/parameters/include"),
|
||||||
|
* @OA\Parameter(
|
||||||
|
* name="id",
|
||||||
|
* in="path",
|
||||||
|
* description="The Payment Term Hashed ID",
|
||||||
|
* example="D2J234DFA",
|
||||||
|
* required=true,
|
||||||
|
* @OA\Schema(
|
||||||
|
* type="string",
|
||||||
|
* format="string",
|
||||||
|
* ),
|
||||||
|
* ),
|
||||||
|
* @OA\Response(
|
||||||
|
* response=200,
|
||||||
|
* description="Returns the Payment object",
|
||||||
|
* @OA\Header(header="X-API-Version", ref="#/components/headers/X-API-Version"),
|
||||||
|
* @OA\Header(header="X-RateLimit-Remaining", ref="#/components/headers/X-RateLimit-Remaining"),
|
||||||
|
* @OA\Header(header="X-RateLimit-Limit", ref="#/components/headers/X-RateLimit-Limit"),
|
||||||
|
* @OA\JsonContent(ref="#/components/schemas/PaymentTerm"),
|
||||||
|
* ),
|
||||||
|
* @OA\Response(
|
||||||
|
* response=422,
|
||||||
|
* description="Validation error",
|
||||||
|
* @OA\JsonContent(ref="#/components/schemas/ValidationError"),
|
||||||
|
*
|
||||||
|
* ),
|
||||||
|
* @OA\Response(
|
||||||
|
* response="default",
|
||||||
|
* description="Unexpected Error",
|
||||||
|
* @OA\JsonContent(ref="#/components/schemas/Error"),
|
||||||
|
* ),
|
||||||
|
* )
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public function edit(EditPaymentRequest $request, Payment $payment)
|
||||||
|
{
|
||||||
|
return $this->itemResponse($payment);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update the specified resource in storage.
|
||||||
|
*
|
||||||
|
* @param \App\Http\Requests\PaymentTerm\UpdatePaymentTermRequest $request The request
|
||||||
|
* @param \App\Models\PaymentTerm $payment_term The payment term
|
||||||
|
*
|
||||||
|
* @return \Illuminate\Http\Response
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @OA\Put(
|
||||||
|
* path="/api/v1/payment_terms/{id}",
|
||||||
|
* operationId="updatePaymentTerm",
|
||||||
|
* tags={"payment_terms"},
|
||||||
|
* summary="Updates a Payment Term",
|
||||||
|
* description="Handles the updating of an Payment Termby id",
|
||||||
|
* @OA\Parameter(ref="#/components/parameters/X-Api-Secret"),
|
||||||
|
* @OA\Parameter(ref="#/components/parameters/X-Api-Token"),
|
||||||
|
* @OA\Parameter(ref="#/components/parameters/X-Requested-With"),
|
||||||
|
* @OA\Parameter(ref="#/components/parameters/include"),
|
||||||
|
* @OA\Parameter(
|
||||||
|
* name="id",
|
||||||
|
* in="path",
|
||||||
|
* description="The Payment Term Hashed ID",
|
||||||
|
* example="D2J234DFA",
|
||||||
|
* required=true,
|
||||||
|
* @OA\Schema(
|
||||||
|
* type="string",
|
||||||
|
* format="string",
|
||||||
|
* ),
|
||||||
|
* ),
|
||||||
|
* @OA\Response(
|
||||||
|
* response=200,
|
||||||
|
* description="Returns the Payment Term object",
|
||||||
|
* @OA\Header(header="X-API-Version", ref="#/components/headers/X-API-Version"),
|
||||||
|
* @OA\Header(header="X-RateLimit-Remaining", ref="#/components/headers/X-RateLimit-Remaining"),
|
||||||
|
* @OA\Header(header="X-RateLimit-Limit", ref="#/components/headers/X-RateLimit-Limit"),
|
||||||
|
* @OA\JsonContent(ref="#/components/schemas/PaymentTerm"),
|
||||||
|
* ),
|
||||||
|
* @OA\Response(
|
||||||
|
* response=422,
|
||||||
|
* description="Validation error",
|
||||||
|
* @OA\JsonContent(ref="#/components/schemas/ValidationError"),
|
||||||
|
*
|
||||||
|
* ),
|
||||||
|
* @OA\Response(
|
||||||
|
* response="default",
|
||||||
|
* description="Unexpected Error",
|
||||||
|
* @OA\JsonContent(ref="#/components/schemas/Error"),
|
||||||
|
* ),
|
||||||
|
* )
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public function update(UpdatePaymentTermRequest $request, PaymentTerm $payment_term)
|
||||||
|
{
|
||||||
|
$payment_term->fill($request->all());
|
||||||
|
$payment_term->save();
|
||||||
|
|
||||||
|
return $this->itemResponse($payment_term->fresh());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove the specified resource from storage.
|
||||||
|
*
|
||||||
|
* @param \App\Http\Requests\PaymentTerm\DestroyPaymentTermRequest $request
|
||||||
|
* @param \App\Models\PaymentTerm $payment_term
|
||||||
|
*
|
||||||
|
* @return \Illuminate\Http\Response
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @OA\Delete(
|
||||||
|
* path="/api/v1/payment_terms/{id}",
|
||||||
|
* operationId="deletePaymentTerm",
|
||||||
|
* tags={"payment_termss"},
|
||||||
|
* summary="Deletes a Payment Term",
|
||||||
|
* description="Handles the deletion of an PaymentTerm by id",
|
||||||
|
* @OA\Parameter(ref="#/components/parameters/X-Api-Secret"),
|
||||||
|
* @OA\Parameter(ref="#/components/parameters/X-Api-Token"),
|
||||||
|
* @OA\Parameter(ref="#/components/parameters/X-Requested-With"),
|
||||||
|
* @OA\Parameter(ref="#/components/parameters/include"),
|
||||||
|
* @OA\Parameter(
|
||||||
|
* name="id",
|
||||||
|
* in="path",
|
||||||
|
* description="The Payment Term Hashed ID",
|
||||||
|
* example="D2J234DFA",
|
||||||
|
* required=true,
|
||||||
|
* @OA\Schema(
|
||||||
|
* type="string",
|
||||||
|
* format="string",
|
||||||
|
* ),
|
||||||
|
* ),
|
||||||
|
* @OA\Response(
|
||||||
|
* response=200,
|
||||||
|
* description="Returns a HTTP status",
|
||||||
|
* @OA\Header(header="X-API-Version", ref="#/components/headers/X-API-Version"),
|
||||||
|
* @OA\Header(header="X-RateLimit-Remaining", ref="#/components/headers/X-RateLimit-Remaining"),
|
||||||
|
* @OA\Header(header="X-RateLimit-Limit", ref="#/components/headers/X-RateLimit-Limit"),
|
||||||
|
* ),
|
||||||
|
* @OA\Response(
|
||||||
|
* response=422,
|
||||||
|
* description="Validation error",
|
||||||
|
* @OA\JsonContent(ref="#/components/schemas/ValidationError"),
|
||||||
|
*
|
||||||
|
* ),
|
||||||
|
* @OA\Response(
|
||||||
|
* response="default",
|
||||||
|
* description="Unexpected Error",
|
||||||
|
* @OA\JsonContent(ref="#/components/schemas/Error"),
|
||||||
|
* ),
|
||||||
|
* )
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public function destroy(DestroyPaymentTermRequest $request, PaymentTerm $payment_term)
|
||||||
|
{
|
||||||
|
|
||||||
|
$payment_term->delete();
|
||||||
|
|
||||||
|
return response()->json([], 200);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Perform bulk actions on the list view
|
||||||
|
*
|
||||||
|
* @return Collection
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @OA\Post(
|
||||||
|
* path="/api/v1/payment_terms/bulk",
|
||||||
|
* operationId="bulkPaymentTerms",
|
||||||
|
* tags={"payment_terms"},
|
||||||
|
* summary="Performs bulk actions on an array of payment terms",
|
||||||
|
* description="",
|
||||||
|
* @OA\Parameter(ref="#/components/parameters/X-Api-Secret"),
|
||||||
|
* @OA\Parameter(ref="#/components/parameters/X-Api-Token"),
|
||||||
|
* @OA\Parameter(ref="#/components/parameters/X-Requested-With"),
|
||||||
|
* @OA\Parameter(ref="#/components/parameters/index"),
|
||||||
|
* @OA\RequestBody(
|
||||||
|
* description="Payment Ter,s",
|
||||||
|
* required=true,
|
||||||
|
* @OA\MediaType(
|
||||||
|
* mediaType="application/json",
|
||||||
|
* @OA\Schema(
|
||||||
|
* type="array",
|
||||||
|
* @OA\Items(
|
||||||
|
* type="integer",
|
||||||
|
* description="Array of hashed IDs to be bulk 'actioned",
|
||||||
|
* example="[0,1,2,3]",
|
||||||
|
* ),
|
||||||
|
* )
|
||||||
|
* )
|
||||||
|
* ),
|
||||||
|
* @OA\Response(
|
||||||
|
* response=200,
|
||||||
|
* description="The Payment Terms response",
|
||||||
|
* @OA\Header(header="X-API-Version", ref="#/components/headers/X-API-Version"),
|
||||||
|
* @OA\Header(header="X-RateLimit-Remaining", ref="#/components/headers/X-RateLimit-Remaining"),
|
||||||
|
* @OA\Header(header="X-RateLimit-Limit", ref="#/components/headers/X-RateLimit-Limit"),
|
||||||
|
* @OA\JsonContent(ref="#/components/schemas/PaymentTerm"),
|
||||||
|
* ),
|
||||||
|
* @OA\Response(
|
||||||
|
* response=422,
|
||||||
|
* description="Validation error",
|
||||||
|
* @OA\JsonContent(ref="#/components/schemas/ValidationError"),
|
||||||
|
|
||||||
|
* ),
|
||||||
|
* @OA\Response(
|
||||||
|
* response="default",
|
||||||
|
* description="Unexpected Error",
|
||||||
|
* @OA\JsonContent(ref="#/components/schemas/Error"),
|
||||||
|
* ),
|
||||||
|
* )
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public function bulk()
|
||||||
|
{
|
||||||
|
$action = request()->input('action');
|
||||||
|
|
||||||
|
$ids = request()->input('ids');
|
||||||
|
|
||||||
|
$payment_terms = PaymentTerm::withTrashed()->company()->find($this->transformKeys($ids));
|
||||||
|
|
||||||
|
$payment_terms->each(function ($payment_term, $key) use ($action) {
|
||||||
|
if (auth()->user()->can('edit', $payment_term)) {
|
||||||
|
$this->payment_term_repo->{$action}($payment_term);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return $this->listResponse(PaymentTerm::withTrashed()->whereIn('id', $this->transformKeys($ids)));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@ -528,6 +528,20 @@ class QuoteController extends BaseController
|
|||||||
return response()->json(['message' => 'Email Sent!'], 200);
|
return response()->json(['message' => 'Email Sent!'], 200);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if($action == 'convert') {
|
||||||
|
|
||||||
|
$this->entity_type = Quote::class;
|
||||||
|
$this->entity_transformer = QuoteTransformer::class;
|
||||||
|
|
||||||
|
$quotes->each(function ($quote, $key) use ($action) {
|
||||||
|
if (auth()->user()->can('edit', $quote) && $quote->service()->isConvertable()) {
|
||||||
|
$quote->service()->convertToInvoice();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return $this->listResponse(Quote::withTrashed()->whereIn('id', $this->transformKeys($ids))->company());
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Send the other actions to the switch
|
* Send the other actions to the switch
|
||||||
*/
|
*/
|
||||||
@ -642,14 +656,6 @@ class QuoteController extends BaseController
|
|||||||
}
|
}
|
||||||
|
|
||||||
return $this->itemResponse($quote->service()->approve()->save());
|
return $this->itemResponse($quote->service()->approve()->save());
|
||||||
break;
|
|
||||||
case 'convert':
|
|
||||||
|
|
||||||
$this->entity_type = Invoice::class;
|
|
||||||
$this->entity_transformer = InvoiceTransformer::class;
|
|
||||||
|
|
||||||
return $this->itemResponse($quote->service()->convertToInvoice());
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case 'history':
|
case 'history':
|
||||||
# code...
|
# code...
|
||||||
|
@ -16,6 +16,7 @@ use Codedge\Updater\UpdaterManager;
|
|||||||
use Composer\Factory;
|
use Composer\Factory;
|
||||||
use Composer\IO\NullIO;
|
use Composer\IO\NullIO;
|
||||||
use Composer\Installer;
|
use Composer\Installer;
|
||||||
|
use Cz\Git\GitRepository;
|
||||||
use Illuminate\Foundation\Bus\DispatchesJobs;
|
use Illuminate\Foundation\Bus\DispatchesJobs;
|
||||||
use Illuminate\Support\Facades\Artisan;
|
use Illuminate\Support\Facades\Artisan;
|
||||||
use Illuminate\Support\Facades\Storage;
|
use Illuminate\Support\Facades\Storage;
|
||||||
@ -66,22 +67,16 @@ class SelfUpdateController extends BaseController
|
|||||||
return response()->json(['message' => 'Self update not available on this system.'], 403);
|
return response()->json(['message' => 'Self update not available on this system.'], 403);
|
||||||
}
|
}
|
||||||
|
|
||||||
info("is new version available = ". $updater->source()->isNewVersionAvailable());
|
/* .git MUST be owned/writable by the webserver user */
|
||||||
|
$repo = new GitRepository(base_path());
|
||||||
|
|
||||||
// Get the new version available
|
info("Are there changes to pull? " . $repo->hasChanges());
|
||||||
$versionAvailable = $updater->source()->getVersionAvailable();
|
|
||||||
|
|
||||||
info($versionAvailable);
|
$res = $repo->pull();
|
||||||
|
|
||||||
|
info("Are there any changes to pull? " . $repo->hasChanges());
|
||||||
|
|
||||||
// Create a release
|
Artisan::call('ninja:post-update');
|
||||||
$release = $updater->source()->fetch($versionAvailable);
|
|
||||||
|
|
||||||
info(print_r($release,1));
|
|
||||||
|
|
||||||
// Run the update process
|
|
||||||
$res = $updater->source()->update($release);
|
|
||||||
|
|
||||||
info(print_r($res,1));
|
|
||||||
|
|
||||||
return response()->json(['message'=>$res], 200);
|
return response()->json(['message'=>$res], 200);
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Invoice Ninja (https://invoiceninja.com)
|
* Invoice Ninja (https://invoiceninja.com)
|
||||||
*
|
*
|
||||||
@ -34,9 +35,15 @@ trait VerifiesUserEmail
|
|||||||
$user->confirmation_code = null;
|
$user->confirmation_code = null;
|
||||||
$user->save();
|
$user->save();
|
||||||
|
|
||||||
return response()->json(['message' => ctrans('texts.security_confirmation')]);
|
return $this->render('auth.confirmed', [
|
||||||
|
'root' => 'themes',
|
||||||
|
'message' => ctrans('texts.security_confirmation'),
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
return response()->json(['message' => ctrans('texts.wrong_confirmation')]);
|
return $this->render('auth.confirmed', [
|
||||||
|
'root' => 'themes',
|
||||||
|
'message' => ctrans('texts.wrong_confirmation'),
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -45,6 +45,8 @@ class StartupCheck
|
|||||||
Session::flash('message', 'Cache cleared');
|
Session::flash('message', 'Cache cleared');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* Make sure our cache is built */
|
/* Make sure our cache is built */
|
||||||
$cached_tables = config('ninja.cached_tables');
|
$cached_tables = config('ninja.cached_tables');
|
||||||
|
|
||||||
|
@ -36,8 +36,8 @@ class CreateAccountRequest extends Request
|
|||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
//'email' => 'required|string|email|max:100',
|
//'email' => 'required|string|email|max:100',
|
||||||
'first_name' => 'required|string|max:100',
|
'first_name' => 'string|max:100',
|
||||||
'last_name' => 'required|string:max:100',
|
'last_name' => 'string:max:100',
|
||||||
'password' => 'required|string|min:6',
|
'password' => 'required|string|min:6',
|
||||||
'email' => 'bail|required|email',
|
'email' => 'bail|required|email',
|
||||||
'email' => new NewUniqueUserRule(),
|
'email' => new NewUniqueUserRule(),
|
||||||
|
@ -49,6 +49,9 @@ class StoreInvoiceRequest extends Request
|
|||||||
|
|
||||||
$rules['client_id'] = 'required|exists:clients,id,company_id,'.auth()->user()->company()->id;
|
$rules['client_id'] = 'required|exists:clients,id,company_id,'.auth()->user()->company()->id;
|
||||||
|
|
||||||
|
$rules['invitations.*.client_contact_id'] = 'distinct';
|
||||||
|
|
||||||
|
|
||||||
return $rules;
|
return $rules;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
29
app/Http/Requests/PaymentTerm/ActionPaymentTermRequest.php
Normal file
29
app/Http/Requests/PaymentTerm/ActionPaymentTermRequest.php
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Invoice Ninja (https://invoiceninja.com)
|
||||||
|
*
|
||||||
|
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||||
|
*
|
||||||
|
* @copyright Copyright (c) 2020. Invoice Ninja LLC (https://invoiceninja.com)
|
||||||
|
*
|
||||||
|
* @license https://opensource.org/licenses/AAL
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace App\Http\Requests\PaymentTerm;
|
||||||
|
|
||||||
|
use App\Http\Requests\Request;
|
||||||
|
use App\Models\Payment;
|
||||||
|
|
||||||
|
class ActionPaymentTermRequest extends Request
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Determine if the user is authorized to make this request.
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
|
||||||
|
public function authorize() : bool
|
||||||
|
{
|
||||||
|
return auth()->user()->isAdmin();
|
||||||
|
}
|
||||||
|
}
|
29
app/Http/Requests/PaymentTerm/CreatePaymentTermRequest.php
Normal file
29
app/Http/Requests/PaymentTerm/CreatePaymentTermRequest.php
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Invoice Ninja (https://invoiceninja.com)
|
||||||
|
*
|
||||||
|
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||||
|
*
|
||||||
|
* @copyright Copyright (c) 2020. Invoice Ninja LLC (https://invoiceninja.com)
|
||||||
|
*
|
||||||
|
* @license https://opensource.org/licenses/AAL
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace App\Http\Requests\PaymentTerm;
|
||||||
|
|
||||||
|
use App\Http\Requests\Request;
|
||||||
|
use App\Models\PaymentTerm;
|
||||||
|
|
||||||
|
class CreatePaymentTermRequest extends Request
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Determine if the user is authorized to make this request.
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
|
||||||
|
public function authorize() : bool
|
||||||
|
{
|
||||||
|
return auth()->user()->isAdmin();
|
||||||
|
}
|
||||||
|
}
|
29
app/Http/Requests/PaymentTerm/DestroyPaymentTermRequest.php
Normal file
29
app/Http/Requests/PaymentTerm/DestroyPaymentTermRequest.php
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Invoice Ninja (https://invoiceninja.com)
|
||||||
|
*
|
||||||
|
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||||
|
*
|
||||||
|
* @copyright Copyright (c) 2020. Invoice Ninja LLC (https://invoiceninja.com)
|
||||||
|
*
|
||||||
|
* @license https://opensource.org/licenses/AAL
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace App\Http\Requests\PaymentTerm;
|
||||||
|
|
||||||
|
use App\Http\Requests\Request;
|
||||||
|
use App\Models\PaymentTerm;
|
||||||
|
|
||||||
|
class DestroyPaymentTermRequest extends Request
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Determine if the user is authorized to make this request.
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
|
||||||
|
public function authorize() : bool
|
||||||
|
{
|
||||||
|
return auth()->user()->isAdmin();
|
||||||
|
}
|
||||||
|
}
|
46
app/Http/Requests/PaymentTerm/EditPaymentTermRequest.php
Normal file
46
app/Http/Requests/PaymentTerm/EditPaymentTermRequest.php
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Invoice Ninja (https://invoiceninja.com)
|
||||||
|
*
|
||||||
|
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||||
|
*
|
||||||
|
* @copyright Copyright (c) 2020. Invoice Ninja LLC (https://invoiceninja.com)
|
||||||
|
*
|
||||||
|
* @license https://opensource.org/licenses/AAL
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace App\Http\Requests\PaymentTerm;
|
||||||
|
|
||||||
|
use App\Http\Requests\Request;
|
||||||
|
use App\Models\PaymentTerm;
|
||||||
|
|
||||||
|
class EditPaymentTermRequest extends Request
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Determine if the user is authorized to make this request.
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
|
||||||
|
public function authorize()
|
||||||
|
{
|
||||||
|
return auth()->user()->isAdmin();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function rules()
|
||||||
|
{
|
||||||
|
$rules = [];
|
||||||
|
|
||||||
|
return $rules;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
protected function prepareForValidation()
|
||||||
|
{
|
||||||
|
$input = $this->all();
|
||||||
|
|
||||||
|
//$input['id'] = $this->encodePrimaryKey($input['id']);
|
||||||
|
|
||||||
|
$this->replace($input);
|
||||||
|
}
|
||||||
|
}
|
29
app/Http/Requests/PaymentTerm/ShowPaymentTermRequest.php
Normal file
29
app/Http/Requests/PaymentTerm/ShowPaymentTermRequest.php
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Invoice Ninja (https://invoiceninja.com)
|
||||||
|
*
|
||||||
|
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||||
|
*
|
||||||
|
* @copyright Copyright (c) 2020. Invoice Ninja LLC (https://invoiceninja.com)
|
||||||
|
*
|
||||||
|
* @license https://opensource.org/licenses/AAL
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace App\Http\Requests\PaymentTerm;
|
||||||
|
|
||||||
|
use App\Http\Requests\Request;
|
||||||
|
use App\Models\PaymentTerm;
|
||||||
|
|
||||||
|
class ShowPaymentTermRequest extends Request
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Determine if the user is authorized to make this request.
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
|
||||||
|
public function authorize() : bool
|
||||||
|
{
|
||||||
|
return auth()->user()->isAdmin();
|
||||||
|
}
|
||||||
|
}
|
48
app/Http/Requests/PaymentTerm/StorePaymentTermRequest.php
Normal file
48
app/Http/Requests/PaymentTerm/StorePaymentTermRequest.php
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Invoice Ninja (https://invoiceninja.com)
|
||||||
|
*
|
||||||
|
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||||
|
*
|
||||||
|
* @copyright Copyright (c) 2020. Invoice Ninja LLC (https://invoiceninja.com)
|
||||||
|
*
|
||||||
|
* @license https://opensource.org/licenses/AAL
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace App\Http\Requests\PaymentTerm;
|
||||||
|
|
||||||
|
use App\Http\Requests\Request;
|
||||||
|
use App\Models\PaymentTerm;
|
||||||
|
use App\Utils\Traits\MakesHash;
|
||||||
|
|
||||||
|
class StorePaymentTermRequest extends Request
|
||||||
|
{
|
||||||
|
use MakesHash;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine if the user is authorized to make this request.
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
|
||||||
|
public function authorize() : bool
|
||||||
|
{
|
||||||
|
return auth()->user()->isAdmin();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function prepareForValidation()
|
||||||
|
{
|
||||||
|
$input = $this->all();
|
||||||
|
|
||||||
|
$this->replace($input);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function rules()
|
||||||
|
{
|
||||||
|
$rules = [
|
||||||
|
|
||||||
|
];
|
||||||
|
|
||||||
|
return $rules;
|
||||||
|
}
|
||||||
|
}
|
46
app/Http/Requests/PaymentTerm/UpdatePaymentTermRequest.php
Normal file
46
app/Http/Requests/PaymentTerm/UpdatePaymentTermRequest.php
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Invoice Ninja (https://invoiceninja.com)
|
||||||
|
*
|
||||||
|
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||||
|
*
|
||||||
|
* @copyright Copyright (c) 2020. Invoice Ninja LLC (https://invoiceninja.com)
|
||||||
|
*
|
||||||
|
* @license https://opensource.org/licenses/AAL
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace App\Http\Requests\PaymentTerm;
|
||||||
|
|
||||||
|
use App\Http\Requests\Request;
|
||||||
|
use App\Utils\Traits\MakesHash;
|
||||||
|
use Illuminate\Validation\Rule;
|
||||||
|
|
||||||
|
class UpdatePaymentTermRequest extends Request
|
||||||
|
{
|
||||||
|
use MakesHash;
|
||||||
|
/**
|
||||||
|
* Determine if the user is authorized to make this request.
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
|
||||||
|
public function authorize() : bool
|
||||||
|
{
|
||||||
|
return auth()->user()->isAdmin();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public function rules()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'num_days' => 'required',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function prepareForValidation()
|
||||||
|
{
|
||||||
|
$input = $this->all();
|
||||||
|
|
||||||
|
$this->replace($input);
|
||||||
|
}
|
||||||
|
}
|
@ -49,7 +49,8 @@ class PortalComposer
|
|||||||
$data['company'] = auth()->user()->company;
|
$data['company'] = auth()->user()->company;
|
||||||
$data['client'] = auth()->user()->client;
|
$data['client'] = auth()->user()->client;
|
||||||
$data['settings'] = auth()->user()->client->getMergedSettings();
|
$data['settings'] = auth()->user()->client->getMergedSettings();
|
||||||
$data['multiple_contacts'] = ClientContact::where('email', auth('contact')->user()->email)->get();
|
|
||||||
|
$data['multiple_contacts'] = ClientContact::where('email', auth('contact')->user()->email)->whereNotNull('email')->distinct('company_id')->get();
|
||||||
|
|
||||||
return $data;
|
return $data;
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@ namespace App\Jobs\Account;
|
|||||||
|
|
||||||
use App\Events\Account\AccountCreated;
|
use App\Events\Account\AccountCreated;
|
||||||
use App\Jobs\Company\CreateCompany;
|
use App\Jobs\Company\CreateCompany;
|
||||||
|
use App\Jobs\Company\CreateCompanyPaymentTerms;
|
||||||
use App\Jobs\Company\CreateCompanyToken;
|
use App\Jobs\Company\CreateCompanyToken;
|
||||||
use App\Jobs\User\CreateUser;
|
use App\Jobs\User\CreateUser;
|
||||||
use App\Models\Account;
|
use App\Models\Account;
|
||||||
@ -60,6 +61,8 @@ class CreateAccount
|
|||||||
|
|
||||||
$spaa9f78 = CreateUser::dispatchNow($this->request, $sp794f3f, $sp035a66, true);
|
$spaa9f78 = CreateUser::dispatchNow($this->request, $sp794f3f, $sp035a66, true);
|
||||||
|
|
||||||
|
CreateCompanyPaymentTerms::dispatchNow($sp035a66, $spaa9f78);
|
||||||
|
|
||||||
if ($spaa9f78) {
|
if ($spaa9f78) {
|
||||||
auth()->login($spaa9f78, false);
|
auth()->login($spaa9f78, false);
|
||||||
}
|
}
|
||||||
|
@ -57,10 +57,10 @@ class CreateCompany
|
|||||||
$company->ip = request()->ip();
|
$company->ip = request()->ip();
|
||||||
$company->settings = $settings;
|
$company->settings = $settings;
|
||||||
$company->db = config('database.default');
|
$company->db = config('database.default');
|
||||||
|
$company->enabled_modules = config('ninja.enabled_modules');
|
||||||
$company->subdomain = isset($this->request['subdomain']) ? $this->request['subdomain'] : '';
|
$company->subdomain = isset($this->request['subdomain']) ? $this->request['subdomain'] : '';
|
||||||
$company->save();
|
$company->save();
|
||||||
|
|
||||||
|
|
||||||
return $company;
|
return $company;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
66
app/Jobs/Company/CreateCompanyPaymentTerms.php
Normal file
66
app/Jobs/Company/CreateCompanyPaymentTerms.php
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Invoice Ninja (https://invoiceninja.com)
|
||||||
|
*
|
||||||
|
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||||
|
*
|
||||||
|
* @copyright Copyright (c) 2020. Invoice Ninja LLC (https://invoiceninja.com)
|
||||||
|
*
|
||||||
|
* @license https://opensource.org/licenses/AAL
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace App\Jobs\Company;
|
||||||
|
|
||||||
|
use App\DataMapper\CompanySettings;
|
||||||
|
use App\Events\UserSignedUp;
|
||||||
|
use App\Models\Company;
|
||||||
|
use App\Models\PaymentTerm;
|
||||||
|
use App\Utils\Traits\MakesHash;
|
||||||
|
use Illuminate\Foundation\Bus\Dispatchable;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
|
||||||
|
class CreateCompanyPaymentTerms
|
||||||
|
{
|
||||||
|
use MakesHash;
|
||||||
|
use Dispatchable;
|
||||||
|
|
||||||
|
protected $company;
|
||||||
|
|
||||||
|
protected $user;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new job instance.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
|
||||||
|
public function __construct($company, $user)
|
||||||
|
{
|
||||||
|
$this->company = $company;
|
||||||
|
|
||||||
|
$this->user = $user;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute the job.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function handle()
|
||||||
|
{
|
||||||
|
|
||||||
|
$paymentTerms = [
|
||||||
|
['num_days' => 0, 'name' => 'Net 0', 'company_id' => $this->company->id, 'user_id' => $this->user->id],
|
||||||
|
['num_days' => 7, 'name' => '', 'company_id' => $this->company->id, 'user_id' => $this->user->id],
|
||||||
|
['num_days' => 10, 'name' => '', 'company_id' => $this->company->id, 'user_id' => $this->user->id],
|
||||||
|
['num_days' => 14, 'name' => '', 'company_id' => $this->company->id, 'user_id' => $this->user->id],
|
||||||
|
['num_days' => 15, 'name' => '', 'company_id' => $this->company->id, 'user_id' => $this->user->id],
|
||||||
|
['num_days' => 30, 'name' => '', 'company_id' => $this->company->id, 'user_id' => $this->user->id],
|
||||||
|
['num_days' => 60, 'name' => '', 'company_id' => $this->company->id, 'user_id' => $this->user->id],
|
||||||
|
['num_days' => 90, 'name' => '', 'company_id' => $this->company->id, 'user_id' => $this->user->id],
|
||||||
|
];
|
||||||
|
|
||||||
|
PaymentTerm::insert($paymentTerms);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
93
app/Jobs/Mail/EntityPaidMailer.php
Normal file
93
app/Jobs/Mail/EntityPaidMailer.php
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Jobs\Mail;
|
||||||
|
|
||||||
|
use App\Jobs\Util\SystemLogger;
|
||||||
|
use App\Libraries\Google\Google;
|
||||||
|
use App\Libraries\MultiDB;
|
||||||
|
use App\Mail\Admin\EntityNotificationMailer;
|
||||||
|
use App\Mail\Admin\EntityPaidObject;
|
||||||
|
use App\Mail\Admin\EntitySentObject;
|
||||||
|
use App\Models\SystemLog;
|
||||||
|
use App\Models\User;
|
||||||
|
use App\Providers\MailServiceProvider;
|
||||||
|
use Illuminate\Bus\Queueable;
|
||||||
|
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||||
|
use Illuminate\Foundation\Bus\Dispatchable;
|
||||||
|
use Illuminate\Queue\InteractsWithQueue;
|
||||||
|
use Illuminate\Queue\SerializesModels;
|
||||||
|
use Illuminate\Support\Facades\Config;
|
||||||
|
use Illuminate\Support\Facades\Mail;
|
||||||
|
|
||||||
|
class EntityPaidMailer extends BaseMailerJob implements ShouldQueue
|
||||||
|
{
|
||||||
|
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
||||||
|
|
||||||
|
public $company;
|
||||||
|
|
||||||
|
public $user;
|
||||||
|
|
||||||
|
public $payment;
|
||||||
|
|
||||||
|
public $entity_type;
|
||||||
|
|
||||||
|
public $entity;
|
||||||
|
/**
|
||||||
|
* Create a new job instance.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function __construct($payment, $user, $company)
|
||||||
|
{
|
||||||
|
$this->company = $company;
|
||||||
|
|
||||||
|
$this->user = $user;
|
||||||
|
|
||||||
|
$this->payment = $payment;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute the job.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function handle()
|
||||||
|
{
|
||||||
|
info("entity paid mailer");
|
||||||
|
//Set DB
|
||||||
|
//
|
||||||
|
MultiDB::setDb($this->company->db);
|
||||||
|
|
||||||
|
if($this->company->company_users->first()->is_migrating)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
//if we need to set an email driver do it now
|
||||||
|
$this->setMailDriver($this->payment->client->getSetting('email_sending_method'));
|
||||||
|
|
||||||
|
$mail_obj = (new EntityPaidObject($this->payment))->build();
|
||||||
|
$mail_obj->from = [$this->payment->user->email, $this->payment->user->present()->name()];
|
||||||
|
|
||||||
|
//send email
|
||||||
|
Mail::to($this->user->email)
|
||||||
|
->send(new EntityNotificationMailer($mail_obj));
|
||||||
|
|
||||||
|
//catch errors
|
||||||
|
if (count(Mail::failures()) > 0) {
|
||||||
|
$this->logMailError(Mail::failures());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private function logMailError($errors)
|
||||||
|
{
|
||||||
|
SystemLogger::dispatch(
|
||||||
|
$errors,
|
||||||
|
SystemLog::CATEGORY_MAIL,
|
||||||
|
SystemLog::EVENT_MAIL_SEND,
|
||||||
|
SystemLog::TYPE_FAILURE,
|
||||||
|
$this->payment->client
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@ -5,7 +5,7 @@ namespace App\Jobs\Mail;
|
|||||||
use App\Jobs\Util\SystemLogger;
|
use App\Jobs\Util\SystemLogger;
|
||||||
use App\Libraries\Google\Google;
|
use App\Libraries\Google\Google;
|
||||||
use App\Libraries\MultiDB;
|
use App\Libraries\MultiDB;
|
||||||
use App\Mail\Admin\EntitySent;
|
use App\Mail\Admin\EntityNotificationMailer;
|
||||||
use App\Mail\Admin\EntitySentObject;
|
use App\Mail\Admin\EntitySentObject;
|
||||||
use App\Models\SystemLog;
|
use App\Models\SystemLog;
|
||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
@ -18,7 +18,7 @@ use Illuminate\Queue\SerializesModels;
|
|||||||
use Illuminate\Support\Facades\Config;
|
use Illuminate\Support\Facades\Config;
|
||||||
use Illuminate\Support\Facades\Mail;
|
use Illuminate\Support\Facades\Mail;
|
||||||
|
|
||||||
class EntitySentEmail extends BaseMailerJob implements ShouldQueue
|
class EntitySentMailer extends BaseMailerJob implements ShouldQueue
|
||||||
{
|
{
|
||||||
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
||||||
|
|
||||||
@ -56,19 +56,19 @@ class EntitySentEmail extends BaseMailerJob implements ShouldQueue
|
|||||||
*/
|
*/
|
||||||
public function handle()
|
public function handle()
|
||||||
{
|
{
|
||||||
//set DB
|
info("entity sent mailer");
|
||||||
|
//Set DB
|
||||||
MultiDB::setDb($this->company->db);
|
MultiDB::setDb($this->company->db);
|
||||||
|
|
||||||
//if we need to set an email driver do it now
|
//if we need to set an email driver do it now
|
||||||
$this->setMailDriver($this->entity->client->getSetting('email_sending_method'));
|
$this->setMailDriver($this->entity->client->getSetting('email_sending_method'));
|
||||||
|
|
||||||
$mail_obj = (new EntitySentObject($this->invitation, $this->entity_type))->build();
|
$mail_obj = (new EntitySentObject($this->invitation, $this->entity_type))->build();
|
||||||
$mail_obj->from = $this->entity->user->present()->name();
|
$mail_obj->from = [$this->entity->user->email, $this->entity->user->present()->name()];
|
||||||
|
|
||||||
//send email
|
//send email
|
||||||
// Mail::to($this->user->email)
|
Mail::to($this->user->email)
|
||||||
Mail::to('turbo124@gmail.com') //@todo
|
->send(new EntityNotificationMailer($mail_obj));
|
||||||
->send(new EntitySent($mail_obj));
|
|
||||||
|
|
||||||
//catch errors
|
//catch errors
|
||||||
if (count(Mail::failures()) > 0) {
|
if (count(Mail::failures()) > 0) {
|
||||||
@ -84,7 +84,7 @@ class EntitySentEmail extends BaseMailerJob implements ShouldQueue
|
|||||||
SystemLog::CATEGORY_MAIL,
|
SystemLog::CATEGORY_MAIL,
|
||||||
SystemLog::EVENT_MAIL_SEND,
|
SystemLog::EVENT_MAIL_SEND,
|
||||||
SystemLog::TYPE_FAILURE,
|
SystemLog::TYPE_FAILURE,
|
||||||
$this->invoice->client
|
$this->entity->client
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
94
app/Jobs/Mail/EntityViewedMailer.php
Normal file
94
app/Jobs/Mail/EntityViewedMailer.php
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Jobs\Mail;
|
||||||
|
|
||||||
|
use App\Jobs\Util\SystemLogger;
|
||||||
|
use App\Libraries\Google\Google;
|
||||||
|
use App\Libraries\MultiDB;
|
||||||
|
use App\Mail\Admin\EntityNotificationMailer;
|
||||||
|
use App\Mail\Admin\EntityViewedObject;
|
||||||
|
use App\Models\SystemLog;
|
||||||
|
use App\Models\User;
|
||||||
|
use App\Providers\MailServiceProvider;
|
||||||
|
use Illuminate\Bus\Queueable;
|
||||||
|
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||||
|
use Illuminate\Foundation\Bus\Dispatchable;
|
||||||
|
use Illuminate\Queue\InteractsWithQueue;
|
||||||
|
use Illuminate\Queue\SerializesModels;
|
||||||
|
use Illuminate\Support\Facades\Config;
|
||||||
|
use Illuminate\Support\Facades\Mail;
|
||||||
|
|
||||||
|
class EntityViewedMailer extends BaseMailerJob implements ShouldQueue
|
||||||
|
{
|
||||||
|
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
||||||
|
|
||||||
|
public $company;
|
||||||
|
|
||||||
|
public $user;
|
||||||
|
|
||||||
|
public $invitation;
|
||||||
|
|
||||||
|
public $entity_type;
|
||||||
|
|
||||||
|
public $entity;
|
||||||
|
/**
|
||||||
|
* Create a new job instance.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function __construct($invitation, $entity_type, $user, $company)
|
||||||
|
{
|
||||||
|
$this->company = $company;
|
||||||
|
|
||||||
|
$this->user = $user;
|
||||||
|
|
||||||
|
$this->invitation = $invitation;
|
||||||
|
|
||||||
|
$this->entity = $invitation->{$entity_type};
|
||||||
|
|
||||||
|
$this->entity_type = $entity_type;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute the job.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function handle()
|
||||||
|
{
|
||||||
|
|
||||||
|
info("entity viewed mailer");
|
||||||
|
|
||||||
|
//Set DB
|
||||||
|
MultiDB::setDb($this->company->db);
|
||||||
|
|
||||||
|
//if we need to set an email driver do it now
|
||||||
|
$this->setMailDriver($this->entity->client->getSetting('email_sending_method'));
|
||||||
|
|
||||||
|
$mail_obj = (new EntityViewedObject($this->invitation, $this->entity_type))->build();
|
||||||
|
$mail_obj->from = [$this->entity->user->email, $this->entity->user->present()->name()];
|
||||||
|
|
||||||
|
//send email
|
||||||
|
Mail::to($this->user->email)
|
||||||
|
->send(new EntityNotificationMailer($mail_obj));
|
||||||
|
|
||||||
|
//catch errors
|
||||||
|
if (count(Mail::failures()) > 0) {
|
||||||
|
$this->logMailError(Mail::failures());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private function logMailError($errors)
|
||||||
|
{
|
||||||
|
SystemLogger::dispatch(
|
||||||
|
$errors,
|
||||||
|
SystemLog::CATEGORY_MAIL,
|
||||||
|
SystemLog::EVENT_MAIL_SEND,
|
||||||
|
SystemLog::TYPE_FAILURE,
|
||||||
|
$this->invoice->client
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
106
app/Jobs/Mail/PaymentFailureMailer.php
Normal file
106
app/Jobs/Mail/PaymentFailureMailer.php
Normal file
@ -0,0 +1,106 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Jobs\Mail;
|
||||||
|
|
||||||
|
use App\Jobs\Util\SystemLogger;
|
||||||
|
use App\Libraries\Google\Google;
|
||||||
|
use App\Libraries\MultiDB;
|
||||||
|
use App\Mail\Admin\EntityNotificationMailer;
|
||||||
|
use App\Mail\Admin\EntityPaidObject;
|
||||||
|
use App\Mail\Admin\EntitySentObject;
|
||||||
|
use App\Mail\Admin\PaymentFailureObject;
|
||||||
|
use App\Models\SystemLog;
|
||||||
|
use App\Models\User;
|
||||||
|
use App\Providers\MailServiceProvider;
|
||||||
|
use App\Utils\Traits\Notifications\UserNotifies;
|
||||||
|
use Illuminate\Bus\Queueable;
|
||||||
|
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||||
|
use Illuminate\Foundation\Bus\Dispatchable;
|
||||||
|
use Illuminate\Queue\InteractsWithQueue;
|
||||||
|
use Illuminate\Queue\SerializesModels;
|
||||||
|
use Illuminate\Support\Facades\Config;
|
||||||
|
use Illuminate\Support\Facades\Mail;
|
||||||
|
|
||||||
|
class PaymentFailureMailer extends BaseMailerJob implements ShouldQueue
|
||||||
|
{
|
||||||
|
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels, UserNotifies;
|
||||||
|
|
||||||
|
public $client;
|
||||||
|
|
||||||
|
public $message;
|
||||||
|
|
||||||
|
public $company;
|
||||||
|
|
||||||
|
public $amount;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new job instance.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function __construct($client, $message, $company, $amount)
|
||||||
|
{
|
||||||
|
$this->company = $company;
|
||||||
|
|
||||||
|
$this->message = $message;
|
||||||
|
|
||||||
|
$this->client = $client;
|
||||||
|
|
||||||
|
$this->amount = $amount;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute the job.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function handle()
|
||||||
|
{
|
||||||
|
info("entity payment failure mailer");
|
||||||
|
//Set DB
|
||||||
|
MultiDB::setDb($this->company->db);
|
||||||
|
|
||||||
|
//if we need to set an email driver do it now
|
||||||
|
$this->setMailDriver($this->client->getSetting('email_sending_method'));
|
||||||
|
|
||||||
|
//iterate through company_users
|
||||||
|
$this->company->company_users->each(function ($company_user){
|
||||||
|
|
||||||
|
//determine if this user has the right permissions
|
||||||
|
$methods = $this->findCompanyUserNotificationType($company_user, ['payment_failure']);
|
||||||
|
|
||||||
|
//if mail is a method type -fire mail!!
|
||||||
|
if (($key = array_search('mail', $methods)) !== false) {
|
||||||
|
unset($methods[$key]);
|
||||||
|
|
||||||
|
$mail_obj = (new PaymentFailureObject($this->client, $this->message, $this->amount, $this->company))->build();
|
||||||
|
$mail_obj->from = [$this->company->owner()->email, $this->company->owner()->present()->name()];
|
||||||
|
|
||||||
|
//send email
|
||||||
|
Mail::to($company_user->user->email)
|
||||||
|
->send(new EntityNotificationMailer($mail_obj));
|
||||||
|
|
||||||
|
//catch errors
|
||||||
|
if (count(Mail::failures()) > 0) {
|
||||||
|
$this->logMailError(Mail::failures());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private function logMailError($errors)
|
||||||
|
{
|
||||||
|
SystemLogger::dispatch(
|
||||||
|
$errors,
|
||||||
|
SystemLog::CATEGORY_MAIL,
|
||||||
|
SystemLog::EVENT_MAIL_SEND,
|
||||||
|
SystemLog::TYPE_FAILURE,
|
||||||
|
$this->client
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@ -31,6 +31,7 @@ use App\Libraries\MultiDB;
|
|||||||
use App\Mail\MigrationCompleted;
|
use App\Mail\MigrationCompleted;
|
||||||
use App\Mail\MigrationFailed;
|
use App\Mail\MigrationFailed;
|
||||||
use App\Models\Client;
|
use App\Models\Client;
|
||||||
|
use App\Models\ClientContact;
|
||||||
use App\Models\ClientGatewayToken;
|
use App\Models\ClientGatewayToken;
|
||||||
use App\Models\Company;
|
use App\Models\Company;
|
||||||
use App\Models\CompanyGateway;
|
use App\Models\CompanyGateway;
|
||||||
@ -38,6 +39,7 @@ use App\Models\Credit;
|
|||||||
use App\Models\Document;
|
use App\Models\Document;
|
||||||
use App\Models\Invoice;
|
use App\Models\Invoice;
|
||||||
use App\Models\Payment;
|
use App\Models\Payment;
|
||||||
|
use App\Models\PaymentTerm;
|
||||||
use App\Models\Product;
|
use App\Models\Product;
|
||||||
use App\Models\Quote;
|
use App\Models\Quote;
|
||||||
use App\Models\TaxRate;
|
use App\Models\TaxRate;
|
||||||
@ -86,6 +88,7 @@ class Import implements ShouldQueue
|
|||||||
private $available_imports = [
|
private $available_imports = [
|
||||||
'company',
|
'company',
|
||||||
'users',
|
'users',
|
||||||
|
'payment_terms',
|
||||||
'tax_rates',
|
'tax_rates',
|
||||||
'clients',
|
'clients',
|
||||||
'products',
|
'products',
|
||||||
@ -145,7 +148,7 @@ class Import implements ShouldQueue
|
|||||||
* @return void
|
* @return void
|
||||||
* @throws \Exception
|
* @throws \Exception
|
||||||
*/
|
*/
|
||||||
public function handle()
|
public function handle() :bool
|
||||||
{
|
{
|
||||||
|
|
||||||
set_time_limit(0);
|
set_time_limit(0);
|
||||||
@ -154,7 +157,6 @@ class Import implements ShouldQueue
|
|||||||
if (! in_array($key, $this->available_imports)) {
|
if (! in_array($key, $this->available_imports)) {
|
||||||
//throw new ResourceNotAvailableForMigration("Resource {$key} is not available for migration.");
|
//throw new ResourceNotAvailableForMigration("Resource {$key} is not available for migration.");
|
||||||
info("Resource {$key} is not available for migration.");
|
info("Resource {$key} is not available for migration.");
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -168,6 +170,8 @@ class Import implements ShouldQueue
|
|||||||
Mail::to($this->user)->send(new MigrationCompleted());
|
Mail::to($this->user)->send(new MigrationCompleted());
|
||||||
|
|
||||||
info('Completed🚀🚀🚀🚀🚀 at '.now());
|
info('Completed🚀🚀🚀🚀🚀 at '.now());
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -366,7 +370,9 @@ class Import implements ShouldQueue
|
|||||||
unset($modified_contacts[$key]['id']);
|
unset($modified_contacts[$key]['id']);
|
||||||
}
|
}
|
||||||
|
|
||||||
$contact_repository->save($modified_contacts, $client);
|
$saveable_contacts['contacts'] = $modified_contacts;
|
||||||
|
|
||||||
|
$contact_repository->save($saveable_contacts, $client);
|
||||||
}
|
}
|
||||||
|
|
||||||
$key = "clients_{$resource['id']}";
|
$key = "clients_{$resource['id']}";
|
||||||
@ -695,6 +701,28 @@ class Import implements ShouldQueue
|
|||||||
$data = null;
|
$data = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function processPaymentTerms(array $data) :void
|
||||||
|
{
|
||||||
|
|
||||||
|
PaymentTerm::unguard();
|
||||||
|
|
||||||
|
$modified = collect($data)->map(function ($item){
|
||||||
|
|
||||||
|
$item['user_id'] = $this->user->id;
|
||||||
|
$item['company_id'] = $this->company->id;
|
||||||
|
|
||||||
|
return $item;
|
||||||
|
|
||||||
|
})->toArray();
|
||||||
|
|
||||||
|
PaymentTerm::insert($modified);
|
||||||
|
|
||||||
|
PaymentTerm::reguard();
|
||||||
|
|
||||||
|
/*Improve memory handling by setting everything to null when we have finished*/
|
||||||
|
$data = null;
|
||||||
|
}
|
||||||
|
|
||||||
private function processCompanyGateways(array $data) :void
|
private function processCompanyGateways(array $data) :void
|
||||||
{
|
{
|
||||||
CompanyGateway::unguard();
|
CompanyGateway::unguard();
|
||||||
|
@ -74,6 +74,9 @@ class StartMigration implements ShouldQueue
|
|||||||
*/
|
*/
|
||||||
public function handle()
|
public function handle()
|
||||||
{
|
{
|
||||||
|
|
||||||
|
set_time_limit(0);
|
||||||
|
|
||||||
MultiDB::setDb($this->company->db);
|
MultiDB::setDb($this->company->db);
|
||||||
|
|
||||||
auth()->login($this->user, false);
|
auth()->login($this->user, false);
|
||||||
@ -96,7 +99,7 @@ class StartMigration implements ShouldQueue
|
|||||||
$zip->close();
|
$zip->close();
|
||||||
|
|
||||||
if (app()->environment() == 'testing') {
|
if (app()->environment() == 'testing') {
|
||||||
return;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->company->setMigration(true);
|
$this->company->setMigration(true);
|
||||||
@ -110,6 +113,9 @@ class StartMigration implements ShouldQueue
|
|||||||
$data = json_decode(file_get_contents($file), 1);
|
$data = json_decode(file_get_contents($file), 1);
|
||||||
|
|
||||||
Import::dispatchNow($data, $this->company, $this->user);
|
Import::dispatchNow($data, $this->company, $this->user);
|
||||||
|
|
||||||
|
$this->company->setMigration(false);
|
||||||
|
|
||||||
} catch (NonExistingMigrationFile | ProcessingMigrationArchiveFailed | ResourceNotAvailableForMigration | MigrationValidatorFailed | ResourceDependencyMissing $e) {
|
} catch (NonExistingMigrationFile | ProcessingMigrationArchiveFailed | ResourceNotAvailableForMigration | MigrationValidatorFailed | ResourceDependencyMissing $e) {
|
||||||
$this->company->setMigration(false);
|
$this->company->setMigration(false);
|
||||||
|
|
||||||
@ -119,6 +125,11 @@ class StartMigration implements ShouldQueue
|
|||||||
info($e->getMessage());
|
info($e->getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//always make sure we unset the migration as running
|
||||||
|
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function failed($exception = null)
|
public function failed($exception = null)
|
||||||
|
@ -37,18 +37,27 @@ class SubscriptionHandler implements ShouldQueue
|
|||||||
*
|
*
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
public function handle()
|
public function handle() :bool
|
||||||
{
|
{
|
||||||
|
|
||||||
|
if(!$this->entity->company || $this->entity->company->company_users->first()->is_migrating)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
info("i got past the check");
|
||||||
|
|
||||||
$subscriptions = Subscription::where('company_id', $this->entity->company_id)
|
$subscriptions = Subscription::where('company_id', $this->entity->company_id)
|
||||||
->where('event_id', $this->event_id)
|
->where('event_id', $this->event_id)
|
||||||
->get();
|
->get();
|
||||||
|
|
||||||
if(!$subscriptions || $subscriptions->count() == 0)
|
if(!$subscriptions || $subscriptions->count() == 0)
|
||||||
return;
|
return true;
|
||||||
|
|
||||||
$subscriptions->each(function($subscription) {
|
$subscriptions->each(function($subscription) {
|
||||||
$this->process($subscription);
|
$this->process($subscription);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
return true;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private function process($subscription)
|
private function process($subscription)
|
||||||
|
@ -13,6 +13,7 @@ namespace App\Listeners\Credit;
|
|||||||
|
|
||||||
use App\Factory\CreditInvitationFactory;
|
use App\Factory\CreditInvitationFactory;
|
||||||
use App\Factory\InvoiceInvitationFactory;
|
use App\Factory\InvoiceInvitationFactory;
|
||||||
|
use App\Models\CreditInvitation;
|
||||||
use App\Models\InvoiceInvitation;
|
use App\Models\InvoiceInvitation;
|
||||||
use App\Utils\Traits\MakesHash;
|
use App\Utils\Traits\MakesHash;
|
||||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||||
@ -38,7 +39,7 @@ class CreateCreditInvitation implements ShouldQueue
|
|||||||
$contacts = $credit->client->contacts;
|
$contacts = $credit->client->contacts;
|
||||||
|
|
||||||
$contacts->each(function ($contact) use ($credit) {
|
$contacts->each(function ($contact) use ($credit) {
|
||||||
$invitation = InvoiceInvitation::whereCompanyId($credit->company_id)
|
$invitation = CreditInvitation::whereCompanyId($credit->company_id)
|
||||||
->whereClientContactId($contact->id)
|
->whereClientContactId($contact->id)
|
||||||
->whereCreditId($credit->id)
|
->whereCreditId($credit->id)
|
||||||
->first();
|
->first();
|
||||||
|
@ -11,6 +11,7 @@
|
|||||||
|
|
||||||
namespace App\Listeners\Invoice;
|
namespace App\Listeners\Invoice;
|
||||||
|
|
||||||
|
use App\Jobs\Mail\EntitySentMailer;
|
||||||
use App\Models\Activity;
|
use App\Models\Activity;
|
||||||
use App\Models\ClientContact;
|
use App\Models\ClientContact;
|
||||||
use App\Models\InvoiceInvitation;
|
use App\Models\InvoiceInvitation;
|
||||||
@ -57,7 +58,7 @@ class InvoiceEmailedNotification implements ShouldQueue
|
|||||||
//This allows us better control of how we
|
//This allows us better control of how we
|
||||||
//handle the mailer
|
//handle the mailer
|
||||||
|
|
||||||
EntitySentEmail::dispatch($invitation, 'invoice', $user, $invitation->company);
|
EntitySentMailer::dispatch($invitation, 'invoice', $user, $invitation->company);
|
||||||
}
|
}
|
||||||
|
|
||||||
$notification->method = $methods;
|
$notification->method = $methods;
|
||||||
|
@ -11,6 +11,7 @@
|
|||||||
|
|
||||||
namespace App\Listeners\Misc;
|
namespace App\Listeners\Misc;
|
||||||
|
|
||||||
|
use App\Jobs\Mail\EntityViewedMailer;
|
||||||
use App\Notifications\Admin\EntityViewedNotification;
|
use App\Notifications\Admin\EntityViewedNotification;
|
||||||
use App\Utils\Traits\Notifications\UserNotifies;
|
use App\Utils\Traits\Notifications\UserNotifies;
|
||||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||||
@ -44,11 +45,22 @@ class InvitationViewedListener implements ShouldQueue
|
|||||||
$notification = new EntityViewedNotification($invitation, $entity_name);
|
$notification = new EntityViewedNotification($invitation, $entity_name);
|
||||||
|
|
||||||
foreach ($invitation->company->company_users as $company_user) {
|
foreach ($invitation->company->company_users as $company_user) {
|
||||||
|
|
||||||
$entity_viewed = "{$entity_name}_viewed";
|
$entity_viewed = "{$entity_name}_viewed";
|
||||||
|
|
||||||
$notification->method = $this->findUserNotificationTypes($invitation, $company_user, $entity_name, ['all_notifications', $entity_viewed]);
|
$methods = $this->findUserNotificationTypes($invitation, $company_user, $entity_name, ['all_notifications', $entity_viewed]);
|
||||||
|
|
||||||
|
if (($key = array_search('mail', $methods)) !== false) {
|
||||||
|
unset($methods[$key]);
|
||||||
|
|
||||||
|
EntityViewedMailer::dispatch($invitation, $entity_name, $company_user->user, $invitation->company);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
$notification->method = $methods;
|
||||||
|
|
||||||
$company_user->user->notify($notification);
|
$company_user->user->notify($notification);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isset($invitation->company->slack_webhook_url)) {
|
if (isset($invitation->company->slack_webhook_url)) {
|
||||||
@ -57,14 +69,9 @@ class InvitationViewedListener implements ShouldQueue
|
|||||||
Notification::route('slack', $invitation->company->slack_webhook_url)
|
Notification::route('slack', $invitation->company->slack_webhook_url)
|
||||||
->notify($notification);
|
->notify($notification);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private function userNotificationArray($notifications)
|
|
||||||
{
|
|
||||||
$via_array = [];
|
|
||||||
|
|
||||||
if (stripos($this->company_user->permissions, ) !== false);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -11,6 +11,7 @@
|
|||||||
|
|
||||||
namespace App\Listeners\Payment;
|
namespace App\Listeners\Payment;
|
||||||
|
|
||||||
|
use App\Jobs\Mail\EntityPaidMailer;
|
||||||
use App\Models\Activity;
|
use App\Models\Activity;
|
||||||
use App\Models\Invoice;
|
use App\Models\Invoice;
|
||||||
use App\Models\Payment;
|
use App\Models\Payment;
|
||||||
@ -46,10 +47,26 @@ class PaymentNotification implements ShouldQueue
|
|||||||
|
|
||||||
/*User notifications*/
|
/*User notifications*/
|
||||||
foreach ($payment->company->company_users as $company_user) {
|
foreach ($payment->company->company_users as $company_user) {
|
||||||
|
|
||||||
|
if($company_user->is_migrating)
|
||||||
|
return true;
|
||||||
|
|
||||||
$user = $company_user->user;
|
$user = $company_user->user;
|
||||||
|
|
||||||
|
$methods = $this->findUserEntityNotificationType($payment, $company_user, ['all_notifications']);
|
||||||
|
|
||||||
|
if (($key = array_search('mail', $methods)) !== false) {
|
||||||
|
unset($methods[$key]);
|
||||||
|
|
||||||
|
//Fire mail notification here!!!
|
||||||
|
//This allows us better control of how we
|
||||||
|
//handle the mailer
|
||||||
|
|
||||||
|
EntityPaidMailer::dispatch($payment, $user, $payment->company);
|
||||||
|
}
|
||||||
|
|
||||||
$notification = new NewPaymentNotification($payment, $payment->company);
|
$notification = new NewPaymentNotification($payment, $payment->company);
|
||||||
$notification->method = $this->findUserEntityNotificationType($payment, $company_user, ['all_notifications']);
|
$notification->method = $methods;
|
||||||
|
|
||||||
if ($user) {
|
if ($user) {
|
||||||
$user->notify($notification);
|
$user->notify($notification);
|
||||||
|
58
app/Listeners/Quote/CreateQuoteInvitation.php
Normal file
58
app/Listeners/Quote/CreateQuoteInvitation.php
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Invoice Ninja (https://creditninja.com)
|
||||||
|
*
|
||||||
|
* @link https://github.com/creditninja/creditninja source repository
|
||||||
|
*
|
||||||
|
* @copyright Copyright (c) 2020. Invoice Ninja LLC (https://creditninja.com)
|
||||||
|
*
|
||||||
|
* @license https://opensource.org/licenses/AAL
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace App\Listeners\Quote;
|
||||||
|
|
||||||
|
use App\Factory\CreditInvitationFactory;
|
||||||
|
use App\Factory\InvoiceInvitationFactory;
|
||||||
|
use App\Factory\QuoteInvitationFactory;
|
||||||
|
use App\Models\InvoiceInvitation;
|
||||||
|
use App\Models\QuoteInvitation;
|
||||||
|
use App\Utils\Traits\MakesHash;
|
||||||
|
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||||
|
use Illuminate\Queue\InteractsWithQueue;
|
||||||
|
use Illuminate\Support\Facades\Blade;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
|
use Illuminate\Support\Facades\Storage;
|
||||||
|
use Spatie\Browsershot\Browsershot;
|
||||||
|
use Symfony\Component\Debug\Exception\FatalThrowableError;
|
||||||
|
|
||||||
|
class CreateQuoteInvitation implements ShouldQueue
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Handle the event.
|
||||||
|
*
|
||||||
|
* @param object $event
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function handle($event)
|
||||||
|
{
|
||||||
|
$quote = $event->credit;
|
||||||
|
|
||||||
|
$contacts = $quote->client->contacts;
|
||||||
|
|
||||||
|
$contacts->each(function ($contact) use ($quote) {
|
||||||
|
$invitation = QuoteInvitation::whereCompanyId($quote->company_id)
|
||||||
|
->whereClientContactId($contact->id)
|
||||||
|
->whereQuoteId($quote->id)
|
||||||
|
->first();
|
||||||
|
|
||||||
|
if (!$invitation && $contact->send_credit) {
|
||||||
|
$ii = QuoteInvitationFactory::create($quote->company_id, $quote->user_id);
|
||||||
|
$ii->quote_id = $quote->id;
|
||||||
|
$ii->client_contact_id = $contact->id;
|
||||||
|
$ii->save();
|
||||||
|
} elseif ($invitation && !$contact->send_credit) {
|
||||||
|
$invitation->delete();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@ -14,10 +14,11 @@ namespace App\Mail\Admin;
|
|||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
use Illuminate\Mail\Mailable;
|
use Illuminate\Mail\Mailable;
|
||||||
|
|
||||||
class EntitySent extends Mailable
|
class EntityNotificationMailer extends Mailable
|
||||||
{
|
{
|
||||||
|
|
||||||
public $mail_obj;
|
public $mail_obj;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new message instance.
|
* Create a new message instance.
|
||||||
*
|
*
|
||||||
@ -35,9 +36,9 @@ class EntitySent extends Mailable
|
|||||||
*/
|
*/
|
||||||
public function build()
|
public function build()
|
||||||
{
|
{
|
||||||
return $this->from($this->mail_obj->from) //todo
|
return $this->from($this->mail_obj->from[0], $this->mail_obj->from[1]) //todo
|
||||||
->subject($this->mail_obj->subject)
|
->subject($this->mail_obj->subject)
|
||||||
->markdown($this->mail_obj->markdown, ['data' => $this->mail_obj->data])
|
->markdown($this->mail_obj->markdown, $this->mail_obj->data)
|
||||||
->withSwiftMessage(function ($message) {
|
->withSwiftMessage(function ($message) {
|
||||||
$message->getHeaders()->addTextHeader('Tag', $this->mail_obj->tag);
|
$message->getHeaders()->addTextHeader('Tag', $this->mail_obj->tag);
|
||||||
});
|
});
|
96
app/Mail/Admin/EntityPaidObject.php
Normal file
96
app/Mail/Admin/EntityPaidObject.php
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Invoice Ninja (https://invoiceninja.com)
|
||||||
|
*
|
||||||
|
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||||
|
*
|
||||||
|
* @copyright Copyright (c) 2020. Invoice Ninja LLC (https://invoiceninja.com)
|
||||||
|
*
|
||||||
|
* @license https://opensource.org/licenses/AAL
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace App\Mail\Admin;
|
||||||
|
|
||||||
|
use App\Models\User;
|
||||||
|
use App\Utils\Number;
|
||||||
|
|
||||||
|
class EntityPaidObject
|
||||||
|
{
|
||||||
|
public $invitation;
|
||||||
|
|
||||||
|
public $entity;
|
||||||
|
|
||||||
|
public $contact;
|
||||||
|
|
||||||
|
public $company;
|
||||||
|
|
||||||
|
public $settings;
|
||||||
|
|
||||||
|
public function __construct($payment)
|
||||||
|
{
|
||||||
|
$this->payment = $payment;
|
||||||
|
$this->company = $payment->company;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function build()
|
||||||
|
{
|
||||||
|
$mail_obj = new \stdClass;
|
||||||
|
$mail_obj->amount = $this->getAmount();
|
||||||
|
$mail_obj->subject = $this->getSubject();
|
||||||
|
$mail_obj->data = $this->getData();
|
||||||
|
$mail_obj->markdown = 'email.admin.generic';
|
||||||
|
$mail_obj->tag = $this->company->company_key;
|
||||||
|
|
||||||
|
return $mail_obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getAmount()
|
||||||
|
{
|
||||||
|
return Number::formatMoney($this->payment->amount, $this->payment->client);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getSubject()
|
||||||
|
{
|
||||||
|
return
|
||||||
|
ctrans(
|
||||||
|
'texts.notification_payment_paid_subject',
|
||||||
|
['client' => $this->payment->client->present()->name()]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getData()
|
||||||
|
{
|
||||||
|
|
||||||
|
$settings = $this->payment->client->getMergedSettings();
|
||||||
|
|
||||||
|
$amount = Number::formatMoney($this->payment->amount, $this->payment->client);
|
||||||
|
|
||||||
|
$invoice_texts = ctrans('texts.invoice_number_short');
|
||||||
|
|
||||||
|
foreach ($this->payment->invoices as $invoice) {
|
||||||
|
$invoice_texts .= $invoice->number . ',';
|
||||||
|
}
|
||||||
|
|
||||||
|
$invoice_texts = substr($invoice_texts, 0, -1);
|
||||||
|
|
||||||
|
$data = [
|
||||||
|
'title' => ctrans(
|
||||||
|
'texts.notification_payment_paid_subject',
|
||||||
|
['client' => $this->payment->client->present()->name()]
|
||||||
|
),
|
||||||
|
'message' => ctrans(
|
||||||
|
'texts.notification_payment_paid',
|
||||||
|
['amount' => $amount,
|
||||||
|
'client' => $this->payment->client->present()->name(),
|
||||||
|
'invoice' => $invoice_texts,
|
||||||
|
]
|
||||||
|
),
|
||||||
|
'url' => config('ninja.app_url') . '/payments/' . $this->payment->hashed_id,
|
||||||
|
'button' => ctrans('texts.view_payment'),
|
||||||
|
'signature' => $settings->email_signature,
|
||||||
|
'logo' => $this->company->present()->logo(),
|
||||||
|
];
|
||||||
|
|
||||||
|
return $data;
|
||||||
|
}
|
||||||
|
}
|
@ -71,13 +71,12 @@ class EntitySentObject
|
|||||||
|
|
||||||
$settings = $this->entity->client->getMergedSettings();
|
$settings = $this->entity->client->getMergedSettings();
|
||||||
|
|
||||||
$data = [
|
return [
|
||||||
'title' => $this->getSubject(),
|
'title' => $this->getSubject(),
|
||||||
'message' => ctrans(
|
'message' => ctrans(
|
||||||
"texts.notification_{$this->entity_type}_sent",
|
"texts.notification_{$this->entity_type}_sent",
|
||||||
[
|
[
|
||||||
'amount' => $this->getAmount(),
|
'amount' => $this->getAmount(),
|
||||||
|
|
||||||
'client' => $this->contact->present()->name(),
|
'client' => $this->contact->present()->name(),
|
||||||
'invoice' => $this->entity->number,
|
'invoice' => $this->entity->number,
|
||||||
]
|
]
|
||||||
@ -88,6 +87,5 @@ class EntitySentObject
|
|||||||
'logo' => $this->company->present()->logo(),
|
'logo' => $this->company->present()->logo(),
|
||||||
];
|
];
|
||||||
|
|
||||||
return $data;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
92
app/Mail/Admin/EntityViewedObject.php
Normal file
92
app/Mail/Admin/EntityViewedObject.php
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Invoice Ninja (https://invoiceninja.com)
|
||||||
|
*
|
||||||
|
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||||
|
*
|
||||||
|
* @copyright Copyright (c) 2020. Invoice Ninja LLC (https://invoiceninja.com)
|
||||||
|
*
|
||||||
|
* @license https://opensource.org/licenses/AAL
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace App\Mail\Admin;
|
||||||
|
|
||||||
|
use App\Models\User;
|
||||||
|
use App\Utils\Number;
|
||||||
|
|
||||||
|
class EntityViewedObject
|
||||||
|
{
|
||||||
|
public $invitation;
|
||||||
|
|
||||||
|
public $entity_type;
|
||||||
|
|
||||||
|
public $entity;
|
||||||
|
|
||||||
|
public $contact;
|
||||||
|
|
||||||
|
public $company;
|
||||||
|
|
||||||
|
public $settings;
|
||||||
|
|
||||||
|
public function __construct($invitation, $entity_type)
|
||||||
|
{
|
||||||
|
$this->invitation = $invitation;
|
||||||
|
$this->entity_type = $entity_type;
|
||||||
|
$this->entity = $invitation->{$entity_type};
|
||||||
|
$this->contact = $invitation->contact;
|
||||||
|
$this->company = $invitation->company;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function build()
|
||||||
|
{
|
||||||
|
$mail_obj = new \stdClass;
|
||||||
|
$mail_obj->amount = $this->getAmount();
|
||||||
|
$mail_obj->subject = $this->getSubject();
|
||||||
|
$mail_obj->data = $this->getData();
|
||||||
|
$mail_obj->markdown = 'email.admin.generic';
|
||||||
|
$mail_obj->tag = $this->company->company_key;
|
||||||
|
|
||||||
|
return $mail_obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getAmount()
|
||||||
|
{
|
||||||
|
return Number::formatMoney($this->entity->amount, $this->entity->client);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getSubject()
|
||||||
|
{
|
||||||
|
return
|
||||||
|
ctrans(
|
||||||
|
"texts.notification_{$this->entity_type}_viewed_subject",
|
||||||
|
[
|
||||||
|
'client' => $this->contact->present()->name(),
|
||||||
|
'invoice' => $this->entity->number,
|
||||||
|
]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getData()
|
||||||
|
{
|
||||||
|
|
||||||
|
$settings = $this->entity->client->getMergedSettings();
|
||||||
|
|
||||||
|
$data = [
|
||||||
|
'title' => $this->getSubject(),
|
||||||
|
'message' => ctrans(
|
||||||
|
"texts.notification_{$this->entity_type}_viewed",
|
||||||
|
[
|
||||||
|
'amount' => $this->getAmount(),
|
||||||
|
'client' => $this->contact->present()->name(),
|
||||||
|
'invoice' => $this->entity->number,
|
||||||
|
]
|
||||||
|
),
|
||||||
|
'url' => $this->invitation->getAdminLink(),
|
||||||
|
'button' => ctrans("texts.view_{$this->entity_type}"),
|
||||||
|
'signature' => $settings->email_signature,
|
||||||
|
'logo' => $this->company->present()->logo(),
|
||||||
|
];
|
||||||
|
|
||||||
|
return $data;
|
||||||
|
}
|
||||||
|
}
|
83
app/Mail/Admin/PaymentFailureObject.php
Normal file
83
app/Mail/Admin/PaymentFailureObject.php
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Invoice Ninja (https://invoiceninja.com)
|
||||||
|
*
|
||||||
|
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||||
|
*
|
||||||
|
* @copyright Copyright (c) 2020. Invoice Ninja LLC (https://invoiceninja.com)
|
||||||
|
*
|
||||||
|
* @license https://opensource.org/licenses/AAL
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace App\Mail\Admin;
|
||||||
|
|
||||||
|
use App\Models\User;
|
||||||
|
use App\Utils\Number;
|
||||||
|
|
||||||
|
class PaymentFailureObject
|
||||||
|
{
|
||||||
|
public $client;
|
||||||
|
|
||||||
|
public $message;
|
||||||
|
|
||||||
|
public $company;
|
||||||
|
|
||||||
|
public $amount;
|
||||||
|
|
||||||
|
public function __construct($client, $message, $amount, $company)
|
||||||
|
{
|
||||||
|
$this->client = $client;
|
||||||
|
$this->message = $message;
|
||||||
|
$this->amount = $amount;
|
||||||
|
$this->company = $company;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function build()
|
||||||
|
{
|
||||||
|
$mail_obj = new \stdClass;
|
||||||
|
$mail_obj->amount = $this->getAmount();
|
||||||
|
$mail_obj->subject = $this->getSubject();
|
||||||
|
$mail_obj->data = $this->getData();
|
||||||
|
$mail_obj->markdown = 'email.admin.generic';
|
||||||
|
$mail_obj->tag = $this->company->company_key;
|
||||||
|
|
||||||
|
return $mail_obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getAmount()
|
||||||
|
{
|
||||||
|
return Number::formatMoney($this->amount, $this->client);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getSubject()
|
||||||
|
{
|
||||||
|
return
|
||||||
|
ctrans(
|
||||||
|
'texts.payment_failed_subject',
|
||||||
|
['client' => $this->payment->client->present()->name()]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getData()
|
||||||
|
{
|
||||||
|
$signature = $this->client->getSetting('email_signature');
|
||||||
|
|
||||||
|
$data = [
|
||||||
|
'title' => ctrans(
|
||||||
|
'texts.payment_failed_subject',
|
||||||
|
['client' => $this->client->present()->name()]
|
||||||
|
),
|
||||||
|
'message' => ctrans(
|
||||||
|
'texts.notification_payment_paid',
|
||||||
|
['amount' => $this->getAmount(),
|
||||||
|
'client' => $this->client->present()->name(),
|
||||||
|
'message' => $this->message,
|
||||||
|
]
|
||||||
|
),
|
||||||
|
'signature' => $signature,
|
||||||
|
'logo' => $this->company->present()->logo(),
|
||||||
|
];
|
||||||
|
|
||||||
|
return $data;
|
||||||
|
}
|
||||||
|
}
|
@ -182,6 +182,11 @@ class Client extends BaseModel implements HasLocalePreference
|
|||||||
return $this->belongsTo(Country::class);
|
return $this->belongsTo(Country::class);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function invoices()
|
||||||
|
{
|
||||||
|
return $this->hasMany(Invoice::class);
|
||||||
|
}
|
||||||
|
|
||||||
public function shipping_country()
|
public function shipping_country()
|
||||||
{
|
{
|
||||||
return $this->belongsTo(Country::class, 'shipping_country_id', 'id');
|
return $this->belongsTo(Country::class, 'shipping_country_id', 'id');
|
||||||
|
@ -284,6 +284,11 @@ class Company extends BaseModel
|
|||||||
return $this->hasMany(Design::class)->whereCompanyId($this->id)->orWhere('company_id', null);
|
return $this->hasMany(Design::class)->whereCompanyId($this->id)->orWhere('company_id', null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function payment_terms()
|
||||||
|
{
|
||||||
|
return $this->hasMany(PaymentTerm::class)->whereCompanyId($this->id)->orWhere('company_id', null);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
|
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
|
||||||
*/
|
*/
|
||||||
@ -401,9 +406,13 @@ class Company extends BaseModel
|
|||||||
|
|
||||||
public function setMigration($status)
|
public function setMigration($status)
|
||||||
{
|
{
|
||||||
$this->company_users->each(function ($cu) use ($status) {
|
$company_users = CompanyUser::where('company_id', $this->id)->get();
|
||||||
|
|
||||||
|
foreach($company_users as $cu)
|
||||||
|
{
|
||||||
$cu->is_migrating=$status;
|
$cu->is_migrating=$status;
|
||||||
$cu->save();
|
$cu->save();
|
||||||
});
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -94,6 +94,11 @@ class Payment extends BaseModel
|
|||||||
return $this->belongsTo(Company::class);
|
return $this->belongsTo(Company::class);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function contact()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(ClientContact::class);
|
||||||
|
}
|
||||||
|
|
||||||
public function user()
|
public function user()
|
||||||
{
|
{
|
||||||
return $this->belongsTo(User::class)->withTrashed();
|
return $this->belongsTo(User::class)->withTrashed();
|
||||||
|
@ -30,6 +30,8 @@ class PaymentTerm extends BaseModel
|
|||||||
*/
|
*/
|
||||||
protected $dates = ['deleted_at'];
|
protected $dates = ['deleted_at'];
|
||||||
|
|
||||||
|
protected $fillable = ['num_days'];
|
||||||
|
|
||||||
public function getNumDays()
|
public function getNumDays()
|
||||||
{
|
{
|
||||||
return $this->num_days == -1 ? 0 : $this->num_days;
|
return $this->num_days == -1 ? 0 : $this->num_days;
|
||||||
@ -39,7 +41,7 @@ class PaymentTerm extends BaseModel
|
|||||||
{
|
{
|
||||||
$default_terms = collect(config('ninja.payment_terms'));
|
$default_terms = collect(config('ninja.payment_terms'));
|
||||||
|
|
||||||
$terms = self::scope()->get();
|
$terms = self::whereCompanyId(auth()->user()->company()->id)->orWhere('company_id', null)->get();
|
||||||
|
|
||||||
$terms->map(function ($term) {
|
$terms->map(function ($term) {
|
||||||
return $term['num_days'];
|
return $term['num_days'];
|
||||||
|
@ -21,28 +21,28 @@ class PaymentType extends StaticModel
|
|||||||
public $timestamps = false;
|
public $timestamps = false;
|
||||||
|
|
||||||
const CREDIT = 1;
|
const CREDIT = 1;
|
||||||
const ACH = 5;
|
const ACH = 4;
|
||||||
const VISA = 6;
|
const VISA = 5;
|
||||||
const MASTERCARD = 7;
|
const MASTERCARD = 6;
|
||||||
const AMERICAN_EXPRESS = 8;
|
const AMERICAN_EXPRESS = 7;
|
||||||
const DISCOVER = 9;
|
const DISCOVER = 8;
|
||||||
const DINERS = 10;
|
const DINERS = 9;
|
||||||
const EUROCARD = 11;
|
const EUROCARD = 10;
|
||||||
const NOVA = 12;
|
const NOVA = 11;
|
||||||
const CREDIT_CARD_OTHER = 13;
|
const CREDIT_CARD_OTHER = 12;
|
||||||
const PAYPAL = 14;
|
const PAYPAL = 13;
|
||||||
const CARTE_BLANCHE = 17;
|
const CARTE_BLANCHE = 16;
|
||||||
const UNIONPAY = 18;
|
const UNIONPAY = 17;
|
||||||
const JCB = 19;
|
const JCB = 18;
|
||||||
const LASER = 20;
|
const LASER = 19;
|
||||||
const MAESTRO = 21;
|
const MAESTRO = 20;
|
||||||
const SOLO = 22;
|
const SOLO = 21;
|
||||||
const SWITCH = 23;
|
const SWITCH = 22;
|
||||||
const ALIPAY = 28;
|
const ALIPAY = 27;
|
||||||
const SOFORT = 29;
|
const SOFORT = 28;
|
||||||
const SEPA = 30;
|
const SEPA = 29;
|
||||||
const GOCARDLESS = 31;
|
const GOCARDLESS = 30;
|
||||||
const CRYPTO = 32;
|
const CRYPTO = 31;
|
||||||
|
|
||||||
public static function parseCardType($cardName)
|
public static function parseCardType($cardName)
|
||||||
{
|
{
|
||||||
|
@ -69,6 +69,7 @@ class EntitySentNotification extends Notification implements ShouldQueue
|
|||||||
*/
|
*/
|
||||||
public function toMail($notifiable)
|
public function toMail($notifiable)
|
||||||
{
|
{
|
||||||
|
//@TODO THESE ARE @DEPRECATED NOW we are now using app/Mail/Admin/*
|
||||||
$amount = Number::formatMoney($this->entity->amount, $this->entity->client);
|
$amount = Number::formatMoney($this->entity->amount, $this->entity->client);
|
||||||
$subject = ctrans(
|
$subject = ctrans(
|
||||||
"texts.notification_{$this->entity_name}_sent_subject",
|
"texts.notification_{$this->entity_name}_sent_subject",
|
||||||
|
@ -68,6 +68,8 @@ class EntityViewedNotification extends Notification implements ShouldQueue
|
|||||||
*/
|
*/
|
||||||
public function toMail($notifiable)
|
public function toMail($notifiable)
|
||||||
{
|
{
|
||||||
|
//@TODO THESE ARE @DEPRECATED NOW we are now using app/Mail/Admin/*
|
||||||
|
|
||||||
$data = $this->buildDataArray();
|
$data = $this->buildDataArray();
|
||||||
$subject = $this->buildSubject();
|
$subject = $this->buildSubject();
|
||||||
|
|
||||||
|
@ -63,6 +63,9 @@ class InvoiceSentNotification extends Notification implements ShouldQueue
|
|||||||
*/
|
*/
|
||||||
public function toMail($notifiable)
|
public function toMail($notifiable)
|
||||||
{
|
{
|
||||||
|
//@TODO THESE ARE @DEPRECATED NOW we are now using app/Mail/Admin/*
|
||||||
|
|
||||||
|
|
||||||
$amount = Number::formatMoney($this->invoice->amount, $this->invoice->client);
|
$amount = Number::formatMoney($this->invoice->amount, $this->invoice->client);
|
||||||
$subject = ctrans(
|
$subject = ctrans(
|
||||||
'texts.notification_invoice_sent_subject',
|
'texts.notification_invoice_sent_subject',
|
||||||
|
@ -62,6 +62,10 @@ class InvoiceViewedNotification extends Notification implements ShouldQueue
|
|||||||
*/
|
*/
|
||||||
public function toMail($notifiable)
|
public function toMail($notifiable)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
//@TODO THESE ARE @DEPRECATED NOW we are now using app/Mail/Admin/*
|
||||||
|
|
||||||
|
|
||||||
$amount = Number::formatMoney($this->invoice->amount, $this->invoice->client);
|
$amount = Number::formatMoney($this->invoice->amount, $this->invoice->client);
|
||||||
$subject = ctrans(
|
$subject = ctrans(
|
||||||
'texts.notification_invoice_viewed_subject',
|
'texts.notification_invoice_viewed_subject',
|
||||||
|
@ -58,6 +58,9 @@ class NewPartialPaymentNotification extends Notification implements ShouldQueue
|
|||||||
*/
|
*/
|
||||||
public function toMail($notifiable)
|
public function toMail($notifiable)
|
||||||
{
|
{
|
||||||
|
//@TODO THESE ARE @DEPRECATED NOW we are now using app/Mail/Admin/*
|
||||||
|
|
||||||
|
|
||||||
$amount = Number::formatMoney($this->payment->amount, $this->payment->client);
|
$amount = Number::formatMoney($this->payment->amount, $this->payment->client);
|
||||||
|
|
||||||
$invoice_texts = ctrans('texts.invoice_number_short');
|
$invoice_texts = ctrans('texts.invoice_number_short');
|
||||||
|
@ -61,6 +61,9 @@ class NewPaymentNotification extends Notification implements ShouldQueue
|
|||||||
*/
|
*/
|
||||||
public function toMail($notifiable)
|
public function toMail($notifiable)
|
||||||
{
|
{
|
||||||
|
//@TODO THESE ARE @DEPRECATED NOW we are now using app/Mail/Admin/*
|
||||||
|
|
||||||
|
|
||||||
$amount = Number::formatMoney($this->payment->amount, $this->payment->client);
|
$amount = Number::formatMoney($this->payment->amount, $this->payment->client);
|
||||||
|
|
||||||
$invoice_texts = ctrans('texts.invoice_number_short');
|
$invoice_texts = ctrans('texts.invoice_number_short');
|
||||||
|
@ -13,7 +13,7 @@
|
|||||||
namespace App\PaymentDrivers;
|
namespace App\PaymentDrivers;
|
||||||
|
|
||||||
use App\Events\Payment\PaymentWasCreated;
|
use App\Events\Payment\PaymentWasCreated;
|
||||||
//use App\Jobs\Invoice\UpdateInvoicePayment;
|
use App\Jobs\Mail\PaymentFailureMailer;
|
||||||
use App\Jobs\Util\SystemLogger;
|
use App\Jobs\Util\SystemLogger;
|
||||||
use App\Models\ClientGatewayToken;
|
use App\Models\ClientGatewayToken;
|
||||||
use App\Models\GatewayType;
|
use App\Models\GatewayType;
|
||||||
@ -140,6 +140,9 @@ class PayPalExpressPaymentDriver extends BasePaymentDriver
|
|||||||
$this->client
|
$this->client
|
||||||
);
|
);
|
||||||
} elseif (!$response->isSuccessful()) {
|
} elseif (!$response->isSuccessful()) {
|
||||||
|
|
||||||
|
PaymentFailureMailer::dispatch($this->client, $response->getMessage, $this->client->company, $response['PAYMENTINFO_0_AMT']);
|
||||||
|
|
||||||
SystemLogger::dispatch(
|
SystemLogger::dispatch(
|
||||||
[
|
[
|
||||||
'data' => $request->all(),
|
'data' => $request->all(),
|
||||||
@ -271,12 +274,12 @@ class PayPalExpressPaymentDriver extends BasePaymentDriver
|
|||||||
return $payment;
|
return $payment;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function refund(Payment $payment, $amount = null)
|
public function refund(Payment $payment, $amount)
|
||||||
{
|
{
|
||||||
$this->gateway();
|
$this->gateway();
|
||||||
|
|
||||||
$response = $this->gateway
|
$response = $this->gateway
|
||||||
->refund(['transactionReference' => $payment->transaction_reference, 'amount' => $amount ?? $payment->amount])
|
->refund(['transactionReference' => $payment->transaction_reference, 'amount' => $amount])
|
||||||
->send();
|
->send();
|
||||||
|
|
||||||
if ($response->isSuccessful()) {
|
if ($response->isSuccessful()) {
|
||||||
@ -305,6 +308,7 @@ class PayPalExpressPaymentDriver extends BasePaymentDriver
|
|||||||
$this->client
|
$this->client
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -13,6 +13,7 @@ namespace App\PaymentDrivers;
|
|||||||
|
|
||||||
use App\Events\Payment\PaymentWasCreated;
|
use App\Events\Payment\PaymentWasCreated;
|
||||||
use App\Factory\PaymentFactory;
|
use App\Factory\PaymentFactory;
|
||||||
|
use App\Jobs\Mail\PaymentFailureMailer;
|
||||||
use App\Jobs\Util\SystemLogger;
|
use App\Jobs\Util\SystemLogger;
|
||||||
use App\Models\ClientGatewayToken;
|
use App\Models\ClientGatewayToken;
|
||||||
use App\Models\GatewayType;
|
use App\Models\GatewayType;
|
||||||
@ -364,6 +365,9 @@ class StripePaymentDriver extends BasePaymentDriver
|
|||||||
|
|
||||||
return redirect()->route('client.payments.show', ['payment' => $this->encodePrimaryKey($payment->id)]);
|
return redirect()->route('client.payments.show', ['payment' => $this->encodePrimaryKey($payment->id)]);
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
|
PaymentFailureMailer::dispatch($this->client, $server_response->cancellation_reason, $this->client->company, $server_response->amount);
|
||||||
|
|
||||||
/*Fail and log*/
|
/*Fail and log*/
|
||||||
SystemLogger::dispatch(
|
SystemLogger::dispatch(
|
||||||
[
|
[
|
||||||
|
33
app/Policies/PaymentTermPolicy.php
Normal file
33
app/Policies/PaymentTermPolicy.php
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Invoice Ninja (https://invoiceninja.com)
|
||||||
|
*
|
||||||
|
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||||
|
*
|
||||||
|
* @copyright Copyright (c) 2020. Invoice Ninja LLC (https://invoiceninja.com)
|
||||||
|
*
|
||||||
|
* @license https://opensource.org/licenses/AAL
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace App\Policies;
|
||||||
|
|
||||||
|
use App\Models\Payment;
|
||||||
|
use App\Models\User;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class PaymentTermPolicy
|
||||||
|
* @package App\Policies
|
||||||
|
*/
|
||||||
|
class PaymentTermPolicy extends EntityPolicy
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Checks if the user has create permissions
|
||||||
|
*
|
||||||
|
* @param User $user
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function create(User $user) : bool
|
||||||
|
{
|
||||||
|
return $user->isAdmin() || $user->hasPermission('create_all');
|
||||||
|
}
|
||||||
|
}
|
@ -22,6 +22,7 @@ use App\Models\Expense;
|
|||||||
use App\Models\GroupSetting;
|
use App\Models\GroupSetting;
|
||||||
use App\Models\Invoice;
|
use App\Models\Invoice;
|
||||||
use App\Models\Payment;
|
use App\Models\Payment;
|
||||||
|
use App\Models\PaymentTerm;
|
||||||
use App\Models\Product;
|
use App\Models\Product;
|
||||||
use App\Models\Quote;
|
use App\Models\Quote;
|
||||||
use App\Models\RecurringInvoice;
|
use App\Models\RecurringInvoice;
|
||||||
@ -41,6 +42,7 @@ use App\Policies\ExpensePolicy;
|
|||||||
use App\Policies\GroupSettingPolicy;
|
use App\Policies\GroupSettingPolicy;
|
||||||
use App\Policies\InvoicePolicy;
|
use App\Policies\InvoicePolicy;
|
||||||
use App\Policies\PaymentPolicy;
|
use App\Policies\PaymentPolicy;
|
||||||
|
use App\Policies\PaymentTermPolicy;
|
||||||
use App\Policies\ProductPolicy;
|
use App\Policies\ProductPolicy;
|
||||||
use App\Policies\QuotePolicy;
|
use App\Policies\QuotePolicy;
|
||||||
use App\Policies\RecurringInvoicePolicy;
|
use App\Policies\RecurringInvoicePolicy;
|
||||||
@ -72,6 +74,7 @@ class AuthServiceProvider extends ServiceProvider
|
|||||||
GroupSetting::class => GroupSettingPolicy::class,
|
GroupSetting::class => GroupSettingPolicy::class,
|
||||||
Invoice::class => InvoicePolicy::class,
|
Invoice::class => InvoicePolicy::class,
|
||||||
Payment::class => PaymentPolicy::class,
|
Payment::class => PaymentPolicy::class,
|
||||||
|
PaymentTerm::class => PaymentTermPolicy::class,
|
||||||
Product::class => ProductPolicy::class,
|
Product::class => ProductPolicy::class,
|
||||||
Quote::class => QuotePolicy::class,
|
Quote::class => QuotePolicy::class,
|
||||||
RecurringInvoice::class => RecurringInvoicePolicy::class,
|
RecurringInvoice::class => RecurringInvoicePolicy::class,
|
||||||
|
@ -24,6 +24,7 @@ class ClientContactRepository extends BaseRepository
|
|||||||
{
|
{
|
||||||
public function save(array $data, Client $client) : void
|
public function save(array $data, Client $client) : void
|
||||||
{
|
{
|
||||||
|
|
||||||
if (isset($data['contacts'])) {
|
if (isset($data['contacts'])) {
|
||||||
$contacts = collect($data['contacts']);
|
$contacts = collect($data['contacts']);
|
||||||
} else {
|
} else {
|
||||||
@ -66,17 +67,20 @@ class ClientContactRepository extends BaseRepository
|
|||||||
}
|
}
|
||||||
|
|
||||||
$update_contact->save();
|
$update_contact->save();
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//always made sure we have one blank contact to maintain state
|
//always made sure we have one blank contact to maintain state
|
||||||
if ($contacts->count() == 0) {
|
if ($client->contacts->count() == 0) {
|
||||||
|
|
||||||
|
info("no contacts found");
|
||||||
|
|
||||||
$new_contact = ClientContactFactory::create($client->company_id, $client->user_id);
|
$new_contact = ClientContactFactory::create($client->company_id, $client->user_id);
|
||||||
$new_contact->client_id = $client->id;
|
$new_contact->client_id = $client->id;
|
||||||
$new_contact->contact_key = Str::random(40);
|
$new_contact->contact_key = Str::random(40);
|
||||||
$new_contact->is_primary = true;
|
$new_contact->is_primary = true;
|
||||||
$new_contact->save();
|
$new_contact->save();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
20
app/Repositories/PaymentTermRepository.php
Normal file
20
app/Repositories/PaymentTermRepository.php
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Invoice Ninja (https://invoiceninja.com)
|
||||||
|
*
|
||||||
|
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||||
|
*
|
||||||
|
* @copyright Copyright (c) 2020. Invoice Ninja LLC (https://invoiceninja.com)
|
||||||
|
*
|
||||||
|
* @license https://opensource.org/licenses/AAL
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace App\Repositories;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class for payment term repository.
|
||||||
|
*/
|
||||||
|
class PaymentTermRepository extends BaseRepository
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
@ -29,7 +29,11 @@ class MarkSent
|
|||||||
|
|
||||||
event(new CreditWasMarkedSent($this->credit, $this->credit->company));
|
event(new CreditWasMarkedSent($this->credit, $this->credit->company));
|
||||||
|
|
||||||
$this->credit->service()->setStatus(Credit::STATUS_SENT)->applyNumber()->save();
|
$this->credit
|
||||||
|
->service()
|
||||||
|
->setStatus(Credit::STATUS_SENT)
|
||||||
|
->applyNumber()
|
||||||
|
->save();
|
||||||
|
|
||||||
return $this->credit;
|
return $this->credit;
|
||||||
}
|
}
|
||||||
|
@ -62,6 +62,8 @@ class ApplyPayment extends AbstractService
|
|||||||
$this->invoice->service()->clearPartial()->setStatus(Invoice::STATUS_PARTIAL)->updateBalance($this->payment_amount*-1);
|
$this->invoice->service()->clearPartial()->setStatus(Invoice::STATUS_PARTIAL)->updateBalance($this->payment_amount*-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$this->invoice->service()->applyNumber()->save();
|
||||||
|
|
||||||
return $this->invoice;
|
return $this->invoice;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -139,8 +139,13 @@ class InvoiceService
|
|||||||
/* One liners */
|
/* One liners */
|
||||||
public function setDueDate()
|
public function setDueDate()
|
||||||
{
|
{
|
||||||
$this->invoice->due_date = Carbon::now()->addDays($this->invoice->client->getSetting('payment_terms'));
|
if($this->invoice->due_date != '')
|
||||||
|
return $this;
|
||||||
|
|
||||||
|
//$this->invoice->due_date = Carbon::now()->addDays($this->invoice->client->getSetting('payment_terms'));
|
||||||
|
|
||||||
|
$this->invoice->due_date = Carbon::parse($this->invoice->date)->addDays($this->invoice->client->getSetting('payment_terms'));
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -61,6 +61,7 @@ class MarkPaid extends AbstractService
|
|||||||
$this->invoice->service()
|
$this->invoice->service()
|
||||||
->updateBalance($payment->amount*-1)
|
->updateBalance($payment->amount*-1)
|
||||||
->setStatus(Invoice::STATUS_PAID)
|
->setStatus(Invoice::STATUS_PAID)
|
||||||
|
->applyNumber()
|
||||||
->save();
|
->save();
|
||||||
|
|
||||||
/* Update Invoice balance */
|
/* Update Invoice balance */
|
||||||
|
@ -45,6 +45,7 @@ class MarkSent extends AbstractService
|
|||||||
->service()
|
->service()
|
||||||
->setStatus(Invoice::STATUS_SENT)
|
->setStatus(Invoice::STATUS_SENT)
|
||||||
->applyNumber()
|
->applyNumber()
|
||||||
|
->setDueDate()
|
||||||
->save();
|
->save();
|
||||||
|
|
||||||
$this->client->service()->updateBalance($this->invoice->balance)->save();
|
$this->client->service()->updateBalance($this->invoice->balance)->save();
|
||||||
|
@ -10,10 +10,10 @@ class ConvertQuote
|
|||||||
private $client;
|
private $client;
|
||||||
private $invoice_repo;
|
private $invoice_repo;
|
||||||
|
|
||||||
public function __construct($client, InvoiceRepository $invoice_repo)
|
public function __construct($client)
|
||||||
{
|
{
|
||||||
$this->client = $client;
|
$this->client = $client;
|
||||||
$this->invoice_repo = $invoice_repo;
|
$this->invoice_repo = new InvoiceRepository();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -23,9 +23,19 @@ class ConvertQuote
|
|||||||
public function run($quote)
|
public function run($quote)
|
||||||
{
|
{
|
||||||
$invoice = CloneQuoteToInvoiceFactory::create($quote, $quote->user_id, $quote->company_id);
|
$invoice = CloneQuoteToInvoiceFactory::create($quote, $quote->user_id, $quote->company_id);
|
||||||
$this->invoice_repo->save([], $invoice);
|
$invoice = $this->invoice_repo->save([], $invoice);
|
||||||
|
|
||||||
|
$invoice->fresh();
|
||||||
|
|
||||||
|
$invoice->service()
|
||||||
|
->markSent()
|
||||||
|
->createInvitations()
|
||||||
|
->save();
|
||||||
|
|
||||||
|
$quote->invoice_id = $invoice->id;
|
||||||
|
$quote->save();
|
||||||
|
|
||||||
// maybe should return invoice here
|
// maybe should return invoice here
|
||||||
return $quote;
|
return $invoice;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -29,7 +29,11 @@ class MarkSent
|
|||||||
|
|
||||||
event(new QuoteWasMarkedSent($this->quote, $this->quote->company));
|
event(new QuoteWasMarkedSent($this->quote, $this->quote->company));
|
||||||
|
|
||||||
$this->quote->service()->setStatus(Quote::STATUS_SENT)->applyNumber()->save();
|
$this->quote
|
||||||
|
->service()
|
||||||
|
->setStatus(Quote::STATUS_SENT)
|
||||||
|
->applyNumber()
|
||||||
|
->save();
|
||||||
|
|
||||||
return $this->quote;
|
return $this->quote;
|
||||||
}
|
}
|
||||||
|
@ -21,6 +21,8 @@ class QuoteService
|
|||||||
{
|
{
|
||||||
protected $quote;
|
protected $quote;
|
||||||
|
|
||||||
|
public $invoice;
|
||||||
|
|
||||||
public function __construct($quote)
|
public function __construct($quote)
|
||||||
{
|
{
|
||||||
$this->quote = $quote;
|
$this->quote = $quote;
|
||||||
@ -38,17 +40,29 @@ class QuoteService
|
|||||||
public function markApproved()
|
public function markApproved()
|
||||||
{
|
{
|
||||||
$mark_approved = new MarkApproved($this->quote->client);
|
$mark_approved = new MarkApproved($this->quote->client);
|
||||||
|
|
||||||
$this->quote = $mark_approved->run($this->quote);
|
$this->quote = $mark_approved->run($this->quote);
|
||||||
|
|
||||||
if ($this->quote->client->getSetting('auto_convert_quote') === true) {
|
if ($this->quote->client->getSetting('auto_convert_quote') === true) {
|
||||||
$convert_quote = new ConvertQuote($this->quote->client);
|
$this->convert();
|
||||||
$this->quote = $convert_quote->run($this->quote);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function convert() :QuoteService
|
||||||
|
{
|
||||||
|
if($this->quote->invoice_id)
|
||||||
|
return $this;
|
||||||
|
|
||||||
|
$convert_quote = new ConvertQuote($this->quote->client);
|
||||||
|
|
||||||
|
$this->invoice = $convert_quote->run($this->quote);
|
||||||
|
|
||||||
|
$this->quote->fresh();
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
public function getQuotePdf($contact = null)
|
public function getQuotePdf($contact = null)
|
||||||
{
|
{
|
||||||
$get_invoice_pdf = new GetQuotePdf();
|
$get_invoice_pdf = new GetQuotePdf();
|
||||||
@ -101,8 +115,7 @@ class QuoteService
|
|||||||
$invoice = null;
|
$invoice = null;
|
||||||
|
|
||||||
if ($this->quote->client->getSetting('auto_convert_quote')) {
|
if ($this->quote->client->getSetting('auto_convert_quote')) {
|
||||||
$invoice = $this->convertToInvoice();
|
$this->convert();
|
||||||
$this->linkInvoiceToQuote($invoice)->save();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($this->quote->client->getSetting('auto_archive_quote')) {
|
if ($this->quote->client->getSetting('auto_archive_quote')) {
|
||||||
@ -113,33 +126,27 @@ class QuoteService
|
|||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public function convertToInvoice()
|
||||||
* Where we convert a quote to an invoice we link the two entities via the invoice_id parameter on the quote table
|
|
||||||
* @param object $invoice The Invoice object
|
|
||||||
* @return object QuoteService
|
|
||||||
*/
|
|
||||||
public function linkInvoiceToQuote($invoice) :QuoteService
|
|
||||||
{
|
{
|
||||||
$this->quote->invoice_id = $invoice->id;
|
|
||||||
|
|
||||||
return $this;
|
//to prevent circular references we need to explicit call this here.
|
||||||
|
$mark_approved = new MarkApproved($this->quote->client);
|
||||||
|
$this->quote = $mark_approved->run($this->quote);
|
||||||
|
|
||||||
|
$this->convert();
|
||||||
|
|
||||||
|
return $this->invoice;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function convertToInvoice() :Invoice
|
public function isConvertable() :bool
|
||||||
{
|
{
|
||||||
|
if($this->quote->invoice_id)
|
||||||
|
return false;
|
||||||
|
|
||||||
$invoice = CloneQuoteToInvoiceFactory::create($this->quote, $this->quote->user_id);
|
if($this->quote->status_id == Quote::STATUS_EXPIRED)
|
||||||
$invoice->status_id = Invoice::STATUS_SENT;
|
return false;
|
||||||
$invoice->due_date = null;
|
|
||||||
$invoice->number = null;
|
|
||||||
$invoice->save();
|
|
||||||
|
|
||||||
$invoice->service()
|
return true;
|
||||||
->markSent()
|
|
||||||
->createInvitations()
|
|
||||||
->save();
|
|
||||||
|
|
||||||
return $invoice;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -149,6 +156,7 @@ class QuoteService
|
|||||||
public function save() : ?Quote
|
public function save() : ?Quote
|
||||||
{
|
{
|
||||||
$this->quote->save();
|
$this->quote->save();
|
||||||
|
|
||||||
return $this->quote;
|
return $this->quote;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -23,6 +23,7 @@ use App\Models\Design;
|
|||||||
use App\Models\Expense;
|
use App\Models\Expense;
|
||||||
use App\Models\GroupSetting;
|
use App\Models\GroupSetting;
|
||||||
use App\Models\Payment;
|
use App\Models\Payment;
|
||||||
|
use App\Models\PaymentTerm;
|
||||||
use App\Models\Product;
|
use App\Models\Product;
|
||||||
use App\Models\Project;
|
use App\Models\Project;
|
||||||
use App\Models\Quote;
|
use App\Models\Quote;
|
||||||
@ -31,6 +32,7 @@ use App\Models\TaxRate;
|
|||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
use App\Transformers\CompanyLedgerTransformer;
|
use App\Transformers\CompanyLedgerTransformer;
|
||||||
use App\Transformers\CreditTransformer;
|
use App\Transformers\CreditTransformer;
|
||||||
|
use App\Transformers\PaymentTermTransformer;
|
||||||
use App\Transformers\TaskTransformer;
|
use App\Transformers\TaskTransformer;
|
||||||
use App\Utils\Traits\MakesHash;
|
use App\Utils\Traits\MakesHash;
|
||||||
|
|
||||||
@ -65,6 +67,7 @@ class CompanyTransformer extends EntityTransformer
|
|||||||
'expenses',
|
'expenses',
|
||||||
'vendors',
|
'vendors',
|
||||||
'payments',
|
'payments',
|
||||||
|
'payment_terms',
|
||||||
'company_user',
|
'company_user',
|
||||||
'groups',
|
'groups',
|
||||||
'company_gateways',
|
'company_gateways',
|
||||||
@ -253,4 +256,11 @@ class CompanyTransformer extends EntityTransformer
|
|||||||
|
|
||||||
return $this->includeCollection($company->ledger, $transformer, CompanyLedger::class);
|
return $this->includeCollection($company->ledger, $transformer, CompanyLedger::class);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function includePaymentTerms(Company $company)
|
||||||
|
{
|
||||||
|
$transformer = new PaymentTermTransformer($this->serializer);
|
||||||
|
|
||||||
|
return $this->includeCollection($company->payment_terms()->get(), $transformer, PaymentTerm::class);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
33
app/Transformers/PaymentTermTransformer.php
Normal file
33
app/Transformers/PaymentTermTransformer.php
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Invoice Ninja (https://invoiceninja.com)
|
||||||
|
*
|
||||||
|
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||||
|
*
|
||||||
|
* @copyright Copyright (c) 2020. Invoice Ninja LLC (https://invoiceninja.com)
|
||||||
|
*
|
||||||
|
* @license https://opensource.org/licenses/AAL
|
||||||
|
*/
|
||||||
|
namespace App\Transformers;
|
||||||
|
|
||||||
|
use App\Models\PaymentTerm;
|
||||||
|
use App\Utils\Traits\MakesHash;
|
||||||
|
|
||||||
|
class PaymentTermTransformer extends EntityTransformer
|
||||||
|
{
|
||||||
|
use MakesHash;
|
||||||
|
|
||||||
|
public function transform(PaymentTerm $payment_term)
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'id' => (string) $this->encodePrimaryKey($payment_term->id),
|
||||||
|
'num_days' => (int) $payment_term->num_days,
|
||||||
|
'name' => (string) ctrans('texts.payment_terms_net') . ' ' . $payment_term->getNumDays(),
|
||||||
|
'is_deleted' => (bool) $payment_term->is_deleted,
|
||||||
|
'created_at' => (int) $payment_term->created_at,
|
||||||
|
'updated_at' => (int) $payment_term->updated_at,
|
||||||
|
'archived_at' => (int) $payment_term->deleted_at,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -81,7 +81,7 @@ class QuoteTransformer extends EntityTransformer
|
|||||||
'client_id' => (string) $this->encodePrimaryKey($quote->client_id),
|
'client_id' => (string) $this->encodePrimaryKey($quote->client_id),
|
||||||
'status_id' => (string)$quote->status_id,
|
'status_id' => (string)$quote->status_id,
|
||||||
'design_id' => (string) $this->encodePrimaryKey($quote->design_id),
|
'design_id' => (string) $this->encodePrimaryKey($quote->design_id),
|
||||||
'invoice_id' => (string)$quote->invoice_id,
|
'invoice_id' => (string)$this->encodePrimaryKey($quote->invoice_id),
|
||||||
'updated_at' => (int)$quote->updated_at,
|
'updated_at' => (int)$quote->updated_at,
|
||||||
'archived_at' => (int)$quote->deleted_at,
|
'archived_at' => (int)$quote->deleted_at,
|
||||||
'created_at' => (int)$quote->created_at,
|
'created_at' => (int)$quote->created_at,
|
||||||
|
@ -64,6 +64,7 @@ class UserTransformer extends EntityTransformer
|
|||||||
'custom_value2' => $user->custom_value2 ?: '',
|
'custom_value2' => $user->custom_value2 ?: '',
|
||||||
'custom_value3' => $user->custom_value3 ?: '',
|
'custom_value3' => $user->custom_value3 ?: '',
|
||||||
'custom_value4' => $user->custom_value4 ?: '',
|
'custom_value4' => $user->custom_value4 ?: '',
|
||||||
|
'oauth_provider_id' => (string)$user->oauth_provider_id,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -17,7 +17,7 @@ trait ActionsInvoice
|
|||||||
{
|
{
|
||||||
public function invoiceDeletable($invoice) :bool
|
public function invoiceDeletable($invoice) :bool
|
||||||
{
|
{
|
||||||
if ($invoice->status_id <= Invoice::STATUS_SENT && $invoice->is_deleted == false && $invoice->deleted_at == null) {
|
if ($invoice->status_id <= Invoice::STATUS_SENT && $invoice->is_deleted == false && $invoice->deleted_at == null && $invoice->balance == 0) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -30,7 +30,7 @@ trait UserNotifies
|
|||||||
array_push($required_permissions, "all_user_notifications");
|
array_push($required_permissions, "all_user_notifications");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (count(array_intersect($required_permissions, $notifications->email)) >=1) {
|
if (count(array_intersect($required_permissions, $notifications->email)) >=1 || count(array_intersect($required_permissions, "all_user_notifications")) >=1 || count(array_intersect($required_permissions, "all_notifications")) >=1) {
|
||||||
array_push($notifiable_methods, 'mail');
|
array_push($notifiable_methods, 'mail');
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -54,13 +54,30 @@ trait UserNotifies
|
|||||||
array_push($required_permissions, "all_user_notifications");
|
array_push($required_permissions, "all_user_notifications");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (count(array_intersect($required_permissions, $notifications->email)) >=1) {
|
if (count(array_intersect($required_permissions, $notifications->email)) >=1 || count(array_intersect($required_permissions, "all_user_notifications")) >=1 || count(array_intersect($required_permissions, "all_notifications")) >=1) {
|
||||||
array_push($notifiable_methods, 'mail');
|
array_push($notifiable_methods, 'mail');
|
||||||
}
|
}
|
||||||
|
|
||||||
return $notifiable_methods;
|
return $notifiable_methods;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function findCompanyUserNotificationType($company_user, $required_permissions) :array
|
||||||
|
{
|
||||||
|
if ($this->migrationRunning($company_user)) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
$notifiable_methods = [];
|
||||||
|
$notifications = $company_user->notifications;
|
||||||
|
|
||||||
|
if (count(array_intersect($required_permissions, $notifications->email)) >=1 || count(array_intersect($required_permissions, "all_user_notifications")) >=1 || count(array_intersect($required_permissions, "all_notifications")) >=1) {
|
||||||
|
array_push($notifiable_methods, 'mail');
|
||||||
|
}
|
||||||
|
|
||||||
|
return $notifiable_methods;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
private function migrationRunning($company_user)
|
private function migrationRunning($company_user)
|
||||||
{
|
{
|
||||||
return $company_user->is_migrating;
|
return $company_user->is_migrating;
|
||||||
|
@ -23,10 +23,11 @@
|
|||||||
"asgrim/ofxparser": "^1.2",
|
"asgrim/ofxparser": "^1.2",
|
||||||
"beganovich/omnipay-checkout": "dev-master",
|
"beganovich/omnipay-checkout": "dev-master",
|
||||||
"cleverit/ubl_invoice": "^1.3",
|
"cleverit/ubl_invoice": "^1.3",
|
||||||
"codedge/laravel-selfupdater": "~3.0",
|
|
||||||
"composer/composer": "^1.10",
|
"composer/composer": "^1.10",
|
||||||
|
"czproject/git-php": "^3.17",
|
||||||
"dacastro4/laravel-gmail": "^3.2",
|
"dacastro4/laravel-gmail": "^3.2",
|
||||||
"doctrine/dbal": "^2.10",
|
"doctrine/dbal": "^2.10",
|
||||||
|
"fedeisas/laravel-mail-css-inliner": "2.3",
|
||||||
"fideloper/proxy": "^4.0",
|
"fideloper/proxy": "^4.0",
|
||||||
"fzaninotto/faker": "^1.4",
|
"fzaninotto/faker": "^1.4",
|
||||||
"google/apiclient": "^2.0",
|
"google/apiclient": "^2.0",
|
||||||
|
@ -178,7 +178,6 @@ return [
|
|||||||
App\Providers\EventServiceProvider::class,
|
App\Providers\EventServiceProvider::class,
|
||||||
App\Providers\RouteServiceProvider::class,
|
App\Providers\RouteServiceProvider::class,
|
||||||
App\Providers\ComposerServiceProvider::class,
|
App\Providers\ComposerServiceProvider::class,
|
||||||
Codedge\Updater\UpdaterServiceProvider::class,
|
|
||||||
App\Providers\MultiDBProvider::class,
|
App\Providers\MultiDBProvider::class,
|
||||||
App\Providers\ClientPortalServiceProvider::class,
|
App\Providers\ClientPortalServiceProvider::class,
|
||||||
],
|
],
|
||||||
|
20
config/css-inliner.php
Normal file
20
config/css-inliner.php
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
return [
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Css Files
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| Css file of your style for your emails
|
||||||
|
| The content of these files will be added directly into the inliner
|
||||||
|
| Use absolute paths, ie. public_path('css/main.css')
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'css-files' => [
|
||||||
|
public_path('css/app.css'),
|
||||||
|
],
|
||||||
|
|
||||||
|
];
|
@ -25,6 +25,7 @@ return [
|
|||||||
'company_id' => 0,
|
'company_id' => 0,
|
||||||
'hash_salt' => env('HASH_SALT', ''),
|
'hash_salt' => env('HASH_SALT', ''),
|
||||||
'currency_converter_api_key' => env('OPENEXCHANGE_APP_ID',''),
|
'currency_converter_api_key' => env('OPENEXCHANGE_APP_ID',''),
|
||||||
|
'enabled_modules' => 4095,
|
||||||
|
|
||||||
'environment' => env('NINJA_ENVIRONMENT', 'selfhost'), // 'hosted', 'development', 'selfhost', 'reseller'
|
'environment' => env('NINJA_ENVIRONMENT', 'selfhost'), // 'hosted', 'development', 'selfhost', 'reseller'
|
||||||
|
|
||||||
@ -54,7 +55,7 @@ return [
|
|||||||
'datetime_format_id' => env('DEFAULT_DATETIME_FORMAT_ID', '1'),
|
'datetime_format_id' => env('DEFAULT_DATETIME_FORMAT_ID', '1'),
|
||||||
'locale' => env('DEFAULT_LOCALE', 'en'),
|
'locale' => env('DEFAULT_LOCALE', 'en'),
|
||||||
'map_zoom' => env('DEFAULT_MAP_ZOOM', 10),
|
'map_zoom' => env('DEFAULT_MAP_ZOOM', 10),
|
||||||
'payment_terms' => env('DEFAULT_PAYMENT_TERMS', -1),
|
'payment_terms' => env('DEFAULT_PAYMENT_TERMS', "-1"),
|
||||||
'military_time' => env('MILITARY_TIME', 0),
|
'military_time' => env('MILITARY_TIME', 0),
|
||||||
'first_day_of_week' => env('FIRST_DATE_OF_WEEK', 0),
|
'first_day_of_week' => env('FIRST_DATE_OF_WEEK', 0),
|
||||||
'first_month_of_year' => env('FIRST_MONTH_OF_YEAR', '2000-01-01')
|
'first_month_of_year' => env('FIRST_MONTH_OF_YEAR', '2000-01-01')
|
||||||
@ -97,41 +98,6 @@ return [
|
|||||||
'slack' => env('SLACK_WEBHOOK_URL', ''),
|
'slack' => env('SLACK_WEBHOOK_URL', ''),
|
||||||
'mail' => env('HOSTED_EMAIL', ''),
|
'mail' => env('HOSTED_EMAIL', ''),
|
||||||
],
|
],
|
||||||
'payment_terms' => [
|
|
||||||
[
|
|
||||||
'num_days' => 0,
|
|
||||||
'name' => '',
|
|
||||||
],
|
|
||||||
[
|
|
||||||
'num_days' => 7,
|
|
||||||
'name' => '',
|
|
||||||
],
|
|
||||||
[
|
|
||||||
'num_days' => 10,
|
|
||||||
'name' => '',
|
|
||||||
],
|
|
||||||
[
|
|
||||||
'num_days' => 14,
|
|
||||||
'name' => '',
|
|
||||||
],
|
|
||||||
[
|
|
||||||
'num_days' => 15,
|
|
||||||
'name' => '',
|
|
||||||
],
|
|
||||||
[
|
|
||||||
'num_days' => 30,
|
|
||||||
'name' => '',
|
|
||||||
],
|
|
||||||
[
|
|
||||||
'num_days' => 60,
|
|
||||||
'name' => '',
|
|
||||||
],
|
|
||||||
[
|
|
||||||
'num_days' => 90,
|
|
||||||
'name' => '',
|
|
||||||
]
|
|
||||||
],
|
|
||||||
|
|
||||||
'themes' => [
|
'themes' => [
|
||||||
'global' => 'ninja2020',
|
'global' => 'ninja2020',
|
||||||
'portal' => 'ninja2020',
|
'portal' => 'ninja2020',
|
||||||
|
@ -1,152 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
return [
|
|
||||||
|
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| Default source repository type
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
|
|
|
||||||
| The default source repository type you want to pull your updates from.
|
|
||||||
|
|
|
||||||
*/
|
|
||||||
|
|
||||||
'default' => env('SELF_UPDATER_SOURCE', 'github'),
|
|
||||||
|
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| Version installed
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
|
|
|
||||||
| Set this to the version of your software installed on your system.
|
|
||||||
|
|
|
||||||
*/
|
|
||||||
|
|
||||||
'version_installed' => env('SELF_UPDATER_VERSION_INSTALLED', ''),
|
|
||||||
|
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| Repository types
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
|
|
|
||||||
| A repository can be of different types, which can be specified here.
|
|
||||||
| Current options:
|
|
||||||
| - github
|
|
||||||
| - http
|
|
||||||
|
|
|
||||||
*/
|
|
||||||
|
|
||||||
'repository_types' => [
|
|
||||||
'github' => [
|
|
||||||
'type' => 'github',
|
|
||||||
'repository_vendor' => env('SELF_UPDATER_REPO_VENDOR', ''),
|
|
||||||
'repository_name' => env('SELF_UPDATER_REPO_NAME', ''),
|
|
||||||
'repository_url' => '',
|
|
||||||
'download_path' => env('SELF_UPDATER_DOWNLOAD_PATH', '/tmp'),
|
|
||||||
'private_access_token' => env('SELF_UPDATER_GITHUB_PRIVATE_ACCESS_TOKEN', ''),
|
|
||||||
'use_branch' => env('SELF_UPDATER_BRANCH_NAME', 'v2'),
|
|
||||||
|
|
||||||
],
|
|
||||||
'http' => [
|
|
||||||
'type' => 'http',
|
|
||||||
'repository_url' => env('SELF_UPDATER_REPO_URL', ''),
|
|
||||||
'pkg_filename_format' => env('SELF_UPDATER_PKG_FILENAME_FORMAT', 'v_VERSION_'),
|
|
||||||
'download_path' => env('SELF_UPDATER_DOWNLOAD_PATH', '/tmp'),
|
|
||||||
'private_access_token' => env('SELF_UPDATER_HTTP_PRIVATE_ACCESS_TOKEN', ''),
|
|
||||||
],
|
|
||||||
],
|
|
||||||
|
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| Exclude folders from update
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
|
|
|
||||||
| Specifiy folders which should not be updated and will be skipped during the
|
|
||||||
| update process.
|
|
||||||
|
|
|
||||||
| Here's already a list of good examples to skip. You may want to keep those.
|
|
||||||
|
|
|
||||||
*/
|
|
||||||
|
|
||||||
'exclude_folders' => [
|
|
||||||
'node_modules',
|
|
||||||
'bootstrap/cache',
|
|
||||||
'bower',
|
|
||||||
'storage/app',
|
|
||||||
'storage/framework',
|
|
||||||
'storage/logs',
|
|
||||||
'storage/self-update',
|
|
||||||
'vendor',
|
|
||||||
],
|
|
||||||
|
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| Event Logging
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
|
|
|
||||||
| Configure if fired events should be logged
|
|
||||||
|
|
|
||||||
*/
|
|
||||||
|
|
||||||
'log_events' => env('SELF_UPDATER_LOG_EVENTS', true),
|
|
||||||
|
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| Mail To Settings
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
|
|
|
||||||
| Configure if fired events should be logged
|
|
||||||
|
|
|
||||||
*/
|
|
||||||
'notifications' => [
|
|
||||||
'notifications' => [
|
|
||||||
\Codedge\Updater\Notifications\Notifications\UpdateSucceeded::class => ['mail'],
|
|
||||||
\Codedge\Updater\Notifications\Notifications\UpdateFailed::class => ['mail'],
|
|
||||||
\Codedge\Updater\Notifications\Notifications\UpdateAvailable::class => ['mail'],
|
|
||||||
],
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Here you can specify the notifiable to which the notifications should be sent. The default
|
|
||||||
* notifiable will use the variables specified in this config file.
|
|
||||||
*/
|
|
||||||
'notifiable' => \Codedge\Updater\Notifications\Notifiable::class,
|
|
||||||
|
|
||||||
'mail' => [
|
|
||||||
'to' => [
|
|
||||||
'address' => env('SELF_UPDATER_MAILTO_ADDRESS', 'notifications@example.com'),
|
|
||||||
'name' => env('SELF_UPDATER_MAILTO_NAME', ''),
|
|
||||||
],
|
|
||||||
|
|
||||||
'from' => [
|
|
||||||
'address' => env('SELF_UPDATER_MAIL_FROM_ADDRESS', 'updater@example.com'),
|
|
||||||
'name' => env('SELF_UPDATER_MAIL_FROM_NAME', 'Update'),
|
|
||||||
],
|
|
||||||
],
|
|
||||||
],
|
|
||||||
|
|
||||||
/*
|
|
||||||
|---------------------------------------------------------------------------
|
|
||||||
| Register custom artisan commands
|
|
||||||
|---------------------------------------------------------------------------
|
|
||||||
*/
|
|
||||||
|
|
||||||
'artisan_commands' => [
|
|
||||||
'pre_update' => [
|
|
||||||
//'command:signature' => [
|
|
||||||
// 'class' => Command class
|
|
||||||
// 'params' => []
|
|
||||||
//]
|
|
||||||
],
|
|
||||||
'post_update' => [
|
|
||||||
'ninja:post-update' => [
|
|
||||||
'class' => \App\Console\Commands\PostUpdate::class,
|
|
||||||
'params' => [
|
|
||||||
'log' => 1,
|
|
||||||
'reset' => false,
|
|
||||||
// etc.
|
|
||||||
]
|
|
||||||
],
|
|
||||||
],
|
|
||||||
],
|
|
||||||
|
|
||||||
];
|
|
4
cypress.json
Normal file
4
cypress.json
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
"video": false,
|
||||||
|
"baseUrl": "http://ninja.test:8000/"
|
||||||
|
}
|
5
cypress/fixtures/example.json
Normal file
5
cypress/fixtures/example.json
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"name": "Using fixtures to represent data",
|
||||||
|
"email": "hello@cypress.io",
|
||||||
|
"body": "Fixtures are a great way to mock data for responses to routes"
|
||||||
|
}
|
37
cypress/integration/client_portal/credits.spec.js
vendored
Normal file
37
cypress/integration/client_portal/credits.spec.js
vendored
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
describe('Credits', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
cy.clientLogin();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should show credits page', () => {
|
||||||
|
cy.visit('/client/credits');
|
||||||
|
cy.location().should(location => {
|
||||||
|
expect(location.pathname).to.eq('/client/credits');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should show credits text', () => {
|
||||||
|
cy.visit('/client/credits');
|
||||||
|
|
||||||
|
cy.get('body')
|
||||||
|
.find('h3')
|
||||||
|
.first()
|
||||||
|
.should('contain.text', 'Credits');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have required table elements', () => {
|
||||||
|
cy.visit('/client/credits');
|
||||||
|
|
||||||
|
cy.get('body')
|
||||||
|
.find('table.credits-table > tbody > tr')
|
||||||
|
.first()
|
||||||
|
.find('a')
|
||||||
|
.first()
|
||||||
|
.should('contain.text', 'View')
|
||||||
|
.click()
|
||||||
|
.location()
|
||||||
|
.should(location => {
|
||||||
|
expect(location.pathname).to.eq('/client/credits/VolejRejNm');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
73
cypress/integration/client_portal/invoices.spec.js
vendored
Normal file
73
cypress/integration/client_portal/invoices.spec.js
vendored
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
context('Invoices', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
cy.clientLogin();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should show invoices page', () => {
|
||||||
|
cy.visit('/client/invoices');
|
||||||
|
cy.location().should(location => {
|
||||||
|
expect(location.pathname).to.eq('/client/invoices');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should show invoices text', () => {
|
||||||
|
cy.visit('/client/invoices');
|
||||||
|
|
||||||
|
cy.get('body')
|
||||||
|
.find('h3')
|
||||||
|
.first()
|
||||||
|
.should('contain.text', 'Invoices');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should show download and pay now buttons', () => {
|
||||||
|
cy.visit('/client/invoices');
|
||||||
|
|
||||||
|
cy.get('body')
|
||||||
|
.find('button[value="download"]')
|
||||||
|
.first()
|
||||||
|
.should('contain.text', 'Download');
|
||||||
|
|
||||||
|
cy.get('body')
|
||||||
|
.find('button[value="payment"]')
|
||||||
|
.first()
|
||||||
|
.should('contain.text', 'Pay Now');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have per page options dropdown', () => {
|
||||||
|
cy.visit('/client/invoices');
|
||||||
|
|
||||||
|
cy.get('body')
|
||||||
|
.find('select')
|
||||||
|
.first()
|
||||||
|
.should('have.value', '10');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have required table elements', () => {
|
||||||
|
cy.visit('/client/invoices');
|
||||||
|
|
||||||
|
cy.get('body')
|
||||||
|
.find('table.invoices-table > tbody > tr')
|
||||||
|
.first()
|
||||||
|
.find('.button-link')
|
||||||
|
.first()
|
||||||
|
.should('contain.text', 'View')
|
||||||
|
.click()
|
||||||
|
.location()
|
||||||
|
.should(location => {
|
||||||
|
expect(location.pathname).to.eq('/client/invoices/VolejRejNm');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should filter table content', () => {
|
||||||
|
cy.visit('/client/invoices');
|
||||||
|
|
||||||
|
cy.get('body')
|
||||||
|
.find('#paid-checkbox')
|
||||||
|
.check();
|
||||||
|
|
||||||
|
cy.get('body')
|
||||||
|
.find('table.invoices-table > tbody > tr')
|
||||||
|
.first()
|
||||||
|
.should('not.contain', 'Overdue');
|
||||||
|
});
|
||||||
|
});
|
48
cypress/integration/client_portal/login.spec.js
vendored
Normal file
48
cypress/integration/client_portal/login.spec.js
vendored
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
context('Login', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
cy.visit('/client/login');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should type into login form elements', () => {
|
||||||
|
cy.get('#test_email')
|
||||||
|
.invoke('val')
|
||||||
|
.then(emailValue => {
|
||||||
|
cy.get('#email')
|
||||||
|
.type(emailValue)
|
||||||
|
.should('have.value', emailValue);
|
||||||
|
});
|
||||||
|
|
||||||
|
cy.get('#test_password')
|
||||||
|
.invoke('val')
|
||||||
|
.then(passwordValue => {
|
||||||
|
cy.get('#password')
|
||||||
|
.type(passwordValue)
|
||||||
|
.should('have.value', passwordValue);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should login into client portal', () => {
|
||||||
|
cy.get('#test_email')
|
||||||
|
.invoke('val')
|
||||||
|
.then(emailValue => {
|
||||||
|
cy.get('#test_password')
|
||||||
|
.invoke('val')
|
||||||
|
.then(passwordValue => {
|
||||||
|
cy.get('#email')
|
||||||
|
.type(emailValue)
|
||||||
|
.should('have.value', emailValue);
|
||||||
|
cy.get('#password')
|
||||||
|
.type(passwordValue)
|
||||||
|
.should('have.value', passwordValue);
|
||||||
|
cy.get('#loginBtn')
|
||||||
|
.contains('Login')
|
||||||
|
.click();
|
||||||
|
cy.location().should(location => {
|
||||||
|
expect(location.pathname).to.eq(
|
||||||
|
'/client/dashboard'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
39
cypress/integration/client_portal/payment_methods.spec.js
vendored
Normal file
39
cypress/integration/client_portal/payment_methods.spec.js
vendored
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
context('Payment methods', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
cy.clientLogin();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should show payment methods page', () => {
|
||||||
|
cy.visit('/client/payment_methods');
|
||||||
|
cy.location().should(location => {
|
||||||
|
expect(location.pathname).to.eq('/client/payment_methods');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should show payment methods text', () => {
|
||||||
|
cy.visit('/client/payment_methods');
|
||||||
|
|
||||||
|
cy.get('body')
|
||||||
|
.find('h3')
|
||||||
|
.first()
|
||||||
|
.should('contain.text', 'Payment Method');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should show add payment method button', () => {
|
||||||
|
cy.visit('/client/payment_methods');
|
||||||
|
|
||||||
|
cy.get('body')
|
||||||
|
.find('a.button.button-primary')
|
||||||
|
.first()
|
||||||
|
.should('contain.text', 'Add Payment Method');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have per page options dropdown', () => {
|
||||||
|
cy.visit('/client/payment_methods');
|
||||||
|
|
||||||
|
cy.get('body')
|
||||||
|
.find('select')
|
||||||
|
.first()
|
||||||
|
.should('have.value', '10');
|
||||||
|
});
|
||||||
|
});
|
46
cypress/integration/client_portal/payments.spec.js
vendored
Normal file
46
cypress/integration/client_portal/payments.spec.js
vendored
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
context('Payments', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
cy.clientLogin();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should show payments page', () => {
|
||||||
|
cy.visit('/client/payments');
|
||||||
|
cy.location().should(location => {
|
||||||
|
expect(location.pathname).to.eq('/client/payments');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should show payments text', () => {
|
||||||
|
cy.visit('/client/payments');
|
||||||
|
|
||||||
|
cy.get('body')
|
||||||
|
.find('h3')
|
||||||
|
.first()
|
||||||
|
.should('contain.text', 'Payments');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have per page options dropdown', () => {
|
||||||
|
cy.visit('/client/payments');
|
||||||
|
|
||||||
|
cy.get('body')
|
||||||
|
.find('select')
|
||||||
|
.first()
|
||||||
|
.should('have.value', '10');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have required table elements', () => {
|
||||||
|
cy.visit('/client/payments');
|
||||||
|
|
||||||
|
cy.get('body')
|
||||||
|
.find('table.payments-table > tbody > tr')
|
||||||
|
.first()
|
||||||
|
.find('a')
|
||||||
|
.first()
|
||||||
|
.should('contain.text', 'View')
|
||||||
|
.click()
|
||||||
|
.location()
|
||||||
|
.should(location => {
|
||||||
|
expect(location.pathname).to.eq('/client/payments/VolejRejNm');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
})
|
73
cypress/integration/client_portal/quotes.spec.js
vendored
Normal file
73
cypress/integration/client_portal/quotes.spec.js
vendored
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
describe('Quotes', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
cy.clientLogin();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should show quotes page', () => {
|
||||||
|
cy.visit('/client/quotes');
|
||||||
|
cy.location().should(location => {
|
||||||
|
expect(location.pathname).to.eq('/client/quotes');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should show quotes text', () => {
|
||||||
|
cy.visit('/client/quotes');
|
||||||
|
|
||||||
|
cy.get('body')
|
||||||
|
.find('h3')
|
||||||
|
.first()
|
||||||
|
.should('contain.text', 'Quotes');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should show download and approve buttons', () => {
|
||||||
|
cy.visit('/client/quotes');
|
||||||
|
|
||||||
|
cy.get('body')
|
||||||
|
.find('button[value="download"]')
|
||||||
|
.first()
|
||||||
|
.should('contain.text', 'Download');
|
||||||
|
|
||||||
|
cy.get('body')
|
||||||
|
.find('button[value="approve"]')
|
||||||
|
.first()
|
||||||
|
.should('contain.text', 'Approve');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have per page options dropdown', () => {
|
||||||
|
cy.visit('/client/quotes');
|
||||||
|
|
||||||
|
cy.get('body')
|
||||||
|
.find('select')
|
||||||
|
.first()
|
||||||
|
.should('have.value', '10');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have required table elements', () => {
|
||||||
|
cy.visit('/client/quotes');
|
||||||
|
|
||||||
|
cy.get('body')
|
||||||
|
.find('table.quotes-table > tbody > tr')
|
||||||
|
.first()
|
||||||
|
.find('.button-link')
|
||||||
|
.first()
|
||||||
|
.should('contain.text', 'View')
|
||||||
|
.click()
|
||||||
|
.location()
|
||||||
|
.should(location => {
|
||||||
|
expect(location.pathname).to.eq('/client/quotes/VolejRejNm');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should filter table content', () => {
|
||||||
|
cy.visit('/client/quotes');
|
||||||
|
|
||||||
|
cy.get('body')
|
||||||
|
.find('#draft-checkbox')
|
||||||
|
.check();
|
||||||
|
|
||||||
|
cy.get('body')
|
||||||
|
.find('table.quotes-table > tbody > tr')
|
||||||
|
.first()
|
||||||
|
.should('not.contain', 'Sent');
|
||||||
|
});
|
||||||
|
});
|
48
cypress/integration/client_portal/recurring_invoices.spec.js
vendored
Normal file
48
cypress/integration/client_portal/recurring_invoices.spec.js
vendored
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
context('Recurring invoices', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
cy.clientLogin();
|
||||||
|
});
|
||||||
|
|
||||||
|
// test url
|
||||||
|
|
||||||
|
it('should show recurring invoices page', () => {
|
||||||
|
cy.visit('/client/recurring_invoices');
|
||||||
|
|
||||||
|
cy.location().should(location => {
|
||||||
|
expect(location.pathname).to.eq('/client/recurring_invoices');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should show reucrring invoices text', () => {
|
||||||
|
cy.visit('/client/recurring_invoices');
|
||||||
|
|
||||||
|
cy.get('h3')
|
||||||
|
.first()
|
||||||
|
.should('contain.text', 'Recurring Invoices');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have per page options dropdown', () => {
|
||||||
|
cy.visit('/client/recurring_invoices');
|
||||||
|
|
||||||
|
cy.get('body')
|
||||||
|
.find('select')
|
||||||
|
.first()
|
||||||
|
.should('have.value', '10');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have required table elements', () => {
|
||||||
|
cy.visit('/client/recurring_invoices');
|
||||||
|
|
||||||
|
cy.get('body')
|
||||||
|
.find('table.recurring-invoices-table > tbody > tr')
|
||||||
|
.first()
|
||||||
|
.find('a')
|
||||||
|
.first()
|
||||||
|
.should('contain.text', 'View')
|
||||||
|
.click()
|
||||||
|
.location()
|
||||||
|
.should(location => {
|
||||||
|
expect(location.pathname).to.eq('/client/recurring_invoices/VolejRejNm');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user