mirror of
https://github.com/invoiceninja/invoiceninja.git
synced 2025-05-24 02:14:21 -04:00
Merge branch 'v5-develop' into yodlee
This commit is contained in:
commit
c0cb157309
3
.github/workflows/phpunit.yml
vendored
3
.github/workflows/phpunit.yml
vendored
@ -12,7 +12,7 @@ jobs:
|
||||
runs-on: ${{ matrix.operating-system }}
|
||||
strategy:
|
||||
matrix:
|
||||
operating-system: ['ubuntu-18.04', 'ubuntu-20.04', 'ubuntu-22.04']
|
||||
operating-system: ['ubuntu-20.04', 'ubuntu-22.04']
|
||||
php-versions: ['8.1']
|
||||
phpunit-versions: ['latest']
|
||||
|
||||
@ -103,6 +103,7 @@ jobs:
|
||||
- name: Run Testsuite
|
||||
run: |
|
||||
cat .env
|
||||
vendor/bin/snappdf download
|
||||
vendor/bin/phpunit --testdox
|
||||
env:
|
||||
DB_PORT: ${{ job.services.mysql.ports[3306] }}
|
||||
|
@ -1 +1 @@
|
||||
5.5.8
|
||||
5.5.19
|
@ -29,6 +29,7 @@ use App\Models\Payment;
|
||||
use App\Models\Paymentable;
|
||||
use App\Models\QuoteInvitation;
|
||||
use App\Models\RecurringInvoiceInvitation;
|
||||
use App\Models\User;
|
||||
use App\Models\Vendor;
|
||||
use App\Utils\Ninja;
|
||||
use Exception;
|
||||
@ -75,7 +76,7 @@ class CheckData extends Command
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'ninja:check-data {--database=} {--fix=} {--client_id=} {--vendor_id=} {--paid_to_date=} {--client_balance=} {--ledger_balance=} {--balance_status=}';
|
||||
protected $signature = 'ninja:check-data {--database=} {--fix=} {--portal_url=} {--client_id=} {--vendor_id=} {--paid_to_date=} {--client_balance=} {--ledger_balance=} {--balance_status=}';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
@ -114,9 +115,13 @@ class CheckData extends Command
|
||||
$this->checkEntityInvitations();
|
||||
$this->checkCompanyData();
|
||||
$this->checkBalanceVsPaidStatus();
|
||||
$this->checkDuplicateRecurringInvoices();
|
||||
$this->checkOauthSanity();
|
||||
|
||||
if(Ninja::isHosted())
|
||||
if(Ninja::isHosted()){
|
||||
$this->checkAccountStatuses();
|
||||
$this->checkNinjaPortalUrls();
|
||||
}
|
||||
|
||||
if (! $this->option('client_id')) {
|
||||
$this->checkOAuth();
|
||||
@ -145,6 +150,32 @@ class CheckData extends Command
|
||||
$this->log .= $str."\n";
|
||||
}
|
||||
|
||||
private function checkOauthSanity()
|
||||
{
|
||||
User::where('oauth_provider_id', '1')->cursor()->each(function ($user){
|
||||
|
||||
$this->logMessage("Invalid provider ID for user id# {$user->id}");
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
private function checkDuplicateRecurringInvoices()
|
||||
{
|
||||
|
||||
if(Ninja::isHosted())
|
||||
{
|
||||
$c = Client::on('db-ninja-01')->where('company_id', config('ninja.ninja_default_company_id'))
|
||||
->with('recurring_invoices')
|
||||
->cursor()
|
||||
->each(function ($client){
|
||||
if($client->recurring_invoices()->where('is_deleted', 0)->where('deleted_at', null)->count() > 1)
|
||||
$this->logMessage("Duplicate Recurring Invoice => {$client->custom_value1}");
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
private function checkOAuth()
|
||||
{
|
||||
// check for duplicate oauth ids
|
||||
@ -476,12 +507,12 @@ class CheckData extends Command
|
||||
|
||||
$this->wrong_paid_to_dates++;
|
||||
|
||||
$this->logMessage($client->present()->name.' id = # '.$client->id." - Client Paid To Date = {$client->paid_to_date} != Invoice Payments = {$total_paid_to_date} - {$_client->payments_applied} + {$credits_used_for_payments[0]->credit_payment}");
|
||||
$this->logMessage($client->present()->name().' id = # '.$client->id." - Client Paid To Date = {$client->paid_to_date} != Invoice Payments = {$total_paid_to_date} - {$_client->payments_applied} + {$credits_used_for_payments[0]->credit_payment}");
|
||||
|
||||
$this->isValid = false;
|
||||
|
||||
if($this->option('paid_to_date')){
|
||||
$this->logMessage("# {$client->id} " . $client->present()->name.' - '.$client->number." Fixing {$client->paid_to_date} to {$total_paid_to_date}");
|
||||
$this->logMessage("# {$client->id} " . $client->present()->name().' - '.$client->number." Fixing {$client->paid_to_date} to {$total_paid_to_date}");
|
||||
$client->paid_to_date = $total_paid_to_date;
|
||||
$client->save();
|
||||
}
|
||||
@ -553,12 +584,12 @@ class CheckData extends Command
|
||||
if (round($total_invoice_payments, 2) != round($client->paid_to_date, 2)) {
|
||||
$this->wrong_paid_to_dates++;
|
||||
|
||||
$this->logMessage($client->present()->name.' id = # '.$client->id." - Paid to date does not match Client Paid To Date = {$client->paid_to_date} - Invoice Payments = {$total_invoice_payments}");
|
||||
$this->logMessage($client->present()->name().' id = # '.$client->id." - Paid to date does not match Client Paid To Date = {$client->paid_to_date} - Invoice Payments = {$total_invoice_payments}");
|
||||
|
||||
$this->isValid = false;
|
||||
|
||||
if($this->option('paid_to_date')){
|
||||
$this->logMessage("# {$client->id} " . $client->present()->name.' - '.$client->number." Fixing {$client->paid_to_date} to {$total_invoice_payments}");
|
||||
$this->logMessage("# {$client->id} " . $client->present()->name().' - '.$client->number." Fixing {$client->paid_to_date} to {$total_invoice_payments}");
|
||||
$client->paid_to_date = $total_invoice_payments;
|
||||
$client->save();
|
||||
}
|
||||
@ -589,7 +620,7 @@ class CheckData extends Command
|
||||
if ((string)$total_paid != (string)($invoice->amount - $invoice->balance - $total_credit)) {
|
||||
$this->wrong_balances++;
|
||||
|
||||
$this->logMessage($client->present()->name.' - '.$client->id." - Total Paid = {$total_paid} != Calculated Total = {$calculated_paid_amount}");
|
||||
$this->logMessage($client->present()->name().' - '.$client->id." - Total Paid = {$total_paid} != Calculated Total = {$calculated_paid_amount}");
|
||||
|
||||
$this->isValid = false;
|
||||
}
|
||||
@ -637,11 +668,11 @@ class CheckData extends Command
|
||||
|
||||
$client_object = Client::withTrashed()->find($client['client_id']);
|
||||
|
||||
$this->logMessage($client_object->present()->name.' - '.$client_object->id." - calculated client balances do not match Invoice Balances = ". $client['invoice_balance'] ." - Client Balance = ".rtrim($client['client_balance'], '0'));
|
||||
$this->logMessage($client_object->present()->name().' - '.$client_object->id." - calculated client balances do not match Invoice Balances = ". $client['invoice_balance'] ." - Client Balance = ".rtrim($client['client_balance'], '0'));
|
||||
|
||||
if($this->option('client_balance')){
|
||||
|
||||
$this->logMessage("# {$client_object->id} " . $client_object->present()->name.' - '.$client_object->number." Fixing {$client_object->balance} to " . $client['invoice_balance']);
|
||||
$this->logMessage("# {$client_object->id} " . $client_object->present()->name().' - '.$client_object->number." Fixing {$client_object->balance} to " . $client['invoice_balance']);
|
||||
$client_object->balance = $client['invoice_balance'];
|
||||
$client_object->save();
|
||||
|
||||
@ -675,7 +706,7 @@ class CheckData extends Command
|
||||
|
||||
if($this->option('client_balance')){
|
||||
|
||||
$this->logMessage("# {$client->id} " . $client->present()->name.' - '.$client->number." Fixing {$client->balance} to 0");
|
||||
$this->logMessage("# {$client->id} " . $client->present()->name().' - '.$client->number." Fixing {$client->balance} to 0");
|
||||
|
||||
$client->balance = 0;
|
||||
$client->save();
|
||||
@ -729,13 +760,13 @@ class CheckData extends Command
|
||||
$this->wrong_balances++;
|
||||
$ledger_balance = $ledger ? $ledger->balance : 0;
|
||||
|
||||
$this->logMessage("# {$client->id} " . $client->present()->name.' - '.$client->number." - Balance Failure - Invoice Balances = {$invoice_balance} Client Balance = {$client->balance} Ledger Balance = {$ledger_balance}");
|
||||
$this->logMessage("# {$client->id} " . $client->present()->name().' - '.$client->number." - Balance Failure - Invoice Balances = {$invoice_balance} Client Balance = {$client->balance} Ledger Balance = {$ledger_balance}");
|
||||
|
||||
$this->isValid = false;
|
||||
|
||||
if($this->option('client_balance')){
|
||||
|
||||
$this->logMessage("# {$client->id} " . $client->present()->name.' - '.$client->number." Fixing {$client->balance} to {$invoice_balance}");
|
||||
$this->logMessage("# {$client->id} " . $client->present()->name().' - '.$client->number." Fixing {$client->balance} to {$invoice_balance}");
|
||||
$client->balance = $invoice_balance;
|
||||
$client->save();
|
||||
|
||||
@ -767,14 +798,14 @@ class CheckData extends Command
|
||||
|
||||
if ($ledger && number_format($ledger->balance, 4) != number_format($client->balance, 4)) {
|
||||
$this->wrong_balances++;
|
||||
$this->logMessage("# {$client->id} " . $client->present()->name.' - '.$client->number." - Balance Failure - Client Balance = {$client->balance} Ledger Balance = {$ledger->balance}");
|
||||
$this->logMessage("# {$client->id} " . $client->present()->name().' - '.$client->number." - Balance Failure - Client Balance = {$client->balance} Ledger Balance = {$ledger->balance}");
|
||||
|
||||
$this->isValid = false;
|
||||
|
||||
|
||||
if($this->option('ledger_balance')){
|
||||
|
||||
$this->logMessage("# {$client->id} " . $client->present()->name.' - '.$client->number." Fixing {$client->balance} to {$invoice_balance}");
|
||||
$this->logMessage("# {$client->id} " . $client->present()->name().' - '.$client->number." Fixing {$client->balance} to {$invoice_balance}");
|
||||
$client->balance = $invoice_balance;
|
||||
$client->save();
|
||||
|
||||
@ -937,7 +968,7 @@ class CheckData extends Command
|
||||
{
|
||||
$this->wrong_paid_status = 0;
|
||||
|
||||
foreach(Invoice::with(['payments'])->whereHas('payments')->where('status_id', 4)->where('balance', '>', 0)->where('is_deleted',0)->cursor() as $invoice)
|
||||
foreach(Invoice::with(['payments'])->where('is_deleted',0)->where('balance', '>', 0)->whereHas('payments')->where('status_id', 4)->cursor() as $invoice)
|
||||
{
|
||||
$this->wrong_paid_status++;
|
||||
|
||||
@ -974,4 +1005,31 @@ class CheckData extends Command
|
||||
$this->logMessage($this->wrong_paid_status." wrong invoices with bad balance state");
|
||||
|
||||
}
|
||||
|
||||
public function checkNinjaPortalUrls()
|
||||
{
|
||||
|
||||
$wrong_count = CompanyUser::where('is_owner',1)->where('ninja_portal_url', '')->count();
|
||||
|
||||
$this->logMessage("Missing ninja portal Urls = {$wrong_count}");
|
||||
|
||||
if(!$this->option('portal_url'))
|
||||
return;
|
||||
|
||||
CompanyUser::where('is_owner',1)->where('ninja_portal_url', '')->cursor()->each(function ($cu){
|
||||
|
||||
$cc = ClientContact::on('db-ninja-01')->where('company_id', config('ninja.ninja_default_company_id'))->where('email', $cu->user->email)->first();
|
||||
|
||||
if($cc){
|
||||
$ninja_portal_url = "https://invoiceninja.invoicing.co/client/ninja/{$cc->contact_key}/{$cu->company->company_key}";
|
||||
|
||||
$cu->ninja_portal_url = $ninja_portal_url;
|
||||
$cu->save();
|
||||
|
||||
$this->logMessage("Fixing - {$ninja_portal_url}");
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
}
|
@ -189,7 +189,7 @@ class CreateSingleAccount extends Command
|
||||
$this->createClient($company, $user);
|
||||
}
|
||||
|
||||
CreateCompanyTaskStatuses::dispatchNow($company, $user);
|
||||
(new CreateCompanyTaskStatuses($company, $user))->handle();
|
||||
|
||||
for ($x = 0; $x < $this->count; $x++) {
|
||||
$client = $company->clients->random();
|
||||
|
@ -132,7 +132,8 @@ class DemoMode extends Command
|
||||
'enabled_modules' => 32767,
|
||||
'company_key' => 'KEY',
|
||||
'enable_shop_api' => true,
|
||||
'markdown_email_enabled' => false,
|
||||
'markdown_email_enabled' => true,
|
||||
'markdown_enabled' => false,
|
||||
]);
|
||||
|
||||
$settings = $company->settings;
|
||||
|
@ -97,10 +97,6 @@ class SendRemindersCron extends Command
|
||||
}
|
||||
});
|
||||
|
||||
// SendReminders::dispatchNow();
|
||||
|
||||
// $this->webHookOverdueInvoices();
|
||||
// $this->webHookExpiredQuotes();
|
||||
}
|
||||
|
||||
private function calcLateFee($invoice, $template) :Invoice
|
||||
@ -166,7 +162,7 @@ class SendRemindersCron extends Command
|
||||
|
||||
$invoice_item = new InvoiceItem;
|
||||
$invoice_item->type_id = '5';
|
||||
$invoice_item->product_key = trans('texts.fee');
|
||||
$invoice_item->product_key = ctrans('texts.fee');
|
||||
$invoice_item->notes = ctrans('texts.late_fee_added', ['date' => $this->translateDate(now()->startOfDay(), $invoice->client->date_format(), $invoice->client->locale())]);
|
||||
$invoice_item->quantity = 1;
|
||||
$invoice_item->cost = $fee;
|
||||
|
@ -436,9 +436,12 @@ class CompanySettings extends BaseSettings
|
||||
|
||||
public $auto_archive_invoice_cancelled = false;
|
||||
|
||||
public $vendor_portal_enable_uploads=false;
|
||||
public $vendor_portal_enable_uploads = false;
|
||||
|
||||
public $send_email_on_mark_paid = false;
|
||||
|
||||
public static $casts = [
|
||||
'send_email_on_mark_paid' => 'bool',
|
||||
'vendor_portal_enable_uploads' => 'bool',
|
||||
'besr_id' => 'string',
|
||||
'qr_iban' => 'string',
|
||||
@ -724,7 +727,6 @@ class CompanySettings extends BaseSettings
|
||||
*/
|
||||
public static function defaults(): stdClass
|
||||
{
|
||||
$config = json_decode(config('ninja.settings'));
|
||||
|
||||
$data = (object) get_class_vars(self::class);
|
||||
|
||||
|
40
app/Factory/CloneQuoteToProjectFactory.php
Normal file
40
app/Factory/CloneQuoteToProjectFactory.php
Normal file
@ -0,0 +1,40 @@
|
||||
<?php
|
||||
/**
|
||||
* Project Ninja (https://invoiceninja.com).
|
||||
*
|
||||
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||
*
|
||||
* @copyright Copyright (c) 2022. Project Ninja LLC (https://invoiceninja.com)
|
||||
*
|
||||
* @license https://www.elastic.co/licensing/elastic-license
|
||||
*/
|
||||
|
||||
namespace App\Factory;
|
||||
|
||||
use App\Models\Project;
|
||||
use App\Models\Quote;
|
||||
|
||||
class CloneQuoteToProjectFactory
|
||||
{
|
||||
public static function create(Quote $quote, $user_id) : ?Project
|
||||
{
|
||||
$project = new Project();
|
||||
|
||||
$project->company_id = $quote->company_id;
|
||||
$project->user_id = $user_id;
|
||||
$project->client_id = $quote->client_id;
|
||||
|
||||
$project->public_notes = $quote->public_notes;
|
||||
$project->private_notes = $quote->private_notes;
|
||||
$project->budgeted_hours = 0;
|
||||
$project->task_rate = 0;
|
||||
$project->name = ctrans('texts.quote_number_short') . " " . $quote->number;
|
||||
$project->custom_value1 = '';
|
||||
$project->custom_value2 = '';
|
||||
$project->custom_value3 = '';
|
||||
$project->custom_value4 = '';
|
||||
$project->is_deleted = 0;
|
||||
|
||||
return $project;
|
||||
}
|
||||
}
|
@ -46,7 +46,7 @@ class CompanyFactory
|
||||
|
||||
$company->enabled_modules = config('ninja.enabled_modules'); //32767;//8191; //4095
|
||||
$company->default_password_timeout = 1800000;
|
||||
$company->markdown_email_enabled = false;
|
||||
$company->markdown_email_enabled = true;
|
||||
$company->markdown_enabled = false;
|
||||
|
||||
return $company;
|
||||
|
@ -168,6 +168,9 @@ class ClientFilters extends QueryFilters
|
||||
{
|
||||
$sort_col = explode('|', $sort);
|
||||
|
||||
if($sort_col[0] == 'display_name')
|
||||
$sort_col[0] = 'name';
|
||||
|
||||
return $this->builder->orderBy($sort_col[0], $sort_col[1]);
|
||||
}
|
||||
|
||||
|
@ -107,6 +107,7 @@ class ActivityController extends BaseController
|
||||
'payment' => $activity->payment ? $activity->payment : '',
|
||||
'credit' => $activity->credit ? $activity->credit : '',
|
||||
'task' => $activity->task ? $activity->task : '',
|
||||
'vendor' => $activity->vendor ? $activity->vendor : '',
|
||||
];
|
||||
|
||||
return array_merge($arr, $activity->toArray());
|
||||
|
@ -46,7 +46,7 @@ class ContactRegisterController extends Controller
|
||||
$t = app('translator');
|
||||
$t->replace(Ninja::transformTranslations($company->settings));
|
||||
|
||||
return render('auth.register', ['register_company' => $company, 'account' => $company->account]);
|
||||
return render('auth.register', ['register_company' => $company, 'account' => $company->account, 'submitsForm' => false]);
|
||||
}
|
||||
|
||||
public function register(RegisterRequest $request)
|
||||
|
@ -351,7 +351,7 @@ class LoginController extends BaseController
|
||||
private function handleSocialiteLogin($provider, $token)
|
||||
{
|
||||
$user = $this->getSocialiteUser($provider, $token);
|
||||
nlog($user);
|
||||
|
||||
if ($user) {
|
||||
return $this->loginOrCreateFromSocialite($user, $provider);
|
||||
}
|
||||
@ -368,6 +368,7 @@ class LoginController extends BaseController
|
||||
'oauth_user_id' => $user->id,
|
||||
'oauth_provider_id' => $provider,
|
||||
];
|
||||
|
||||
if ($existing_user = MultiDB::hasUser($query)) {
|
||||
if (!$existing_user->account) {
|
||||
return response()->json(['message' => 'User exists, but not attached to any companies! Orphaned user!'], 400);
|
||||
@ -749,10 +750,6 @@ class LoginController extends BaseController
|
||||
public function handleMicrosoftProviderCallback($provider = 'microsoft')
|
||||
{
|
||||
$socialite_user = Socialite::driver($provider)->user();
|
||||
nlog($socialite_user);
|
||||
|
||||
nlog('refresh token ' . $socialite_user->accessTokenResponseBody['refresh_token']);
|
||||
nlog('access token ' . $socialite_user->accessTokenResponseBody['access_token']);
|
||||
|
||||
$oauth_user_token = $socialite_user->accessTokenResponseBody['access_token'];
|
||||
|
||||
|
@ -232,7 +232,12 @@ class BaseController extends Controller
|
||||
$query->where('clients.updated_at', '>=', $updated_at)->with('contacts.company', 'gateway_tokens', 'documents');
|
||||
|
||||
if (! $user->hasPermission('view_client')) {
|
||||
$query->where('clients.user_id', $user->id)->orWhere('clients.assigned_user_id', $user->id);
|
||||
// $query->where('clients.user_id', $user->id)->orWhere('clients.assigned_user_id', $user->id);
|
||||
|
||||
$query->whereNested(function($query) use ($user) {
|
||||
$query->where('clients.user_id', $user->id)->orWhere('clients.assigned_user_id', $user->id);
|
||||
});
|
||||
|
||||
}
|
||||
},
|
||||
'company.company_gateways' => function ($query) use ($user) {
|
||||
@ -246,7 +251,11 @@ class BaseController extends Controller
|
||||
$query->where('updated_at', '>=', $updated_at)->with('invitations', 'documents');
|
||||
|
||||
if (! $user->hasPermission('view_credit')) {
|
||||
$query->where('credits.user_id', $user->id)->orWhere('credits.assigned_user_id', $user->id);
|
||||
// $query->where('credits.user_id', $user->id)->orWhere('credits.assigned_user_id', $user->id);
|
||||
|
||||
$query->whereNested(function($query) use ($user) {
|
||||
$query->where('credits.user_id', $user->id)->orWhere('credits.assigned_user_id', $user->id);
|
||||
});
|
||||
}
|
||||
},
|
||||
'company.designs'=> function ($query) use ($updated_at, $user) {
|
||||
@ -263,7 +272,11 @@ class BaseController extends Controller
|
||||
$query->where('updated_at', '>=', $updated_at)->with('documents');
|
||||
|
||||
if (! $user->hasPermission('view_expense')) {
|
||||
$query->where('expenses.user_id', $user->id)->orWhere('expenses.assigned_user_id', $user->id);
|
||||
// $query->where('expenses.user_id', $user->id)->orWhere('expenses.assigned_user_id', $user->id);
|
||||
|
||||
$query->whereNested(function($query) use ($user) {
|
||||
$query->where('expenses.user_id', $user->id)->orWhere('expenses.assigned_user_id', $user->id);
|
||||
});
|
||||
}
|
||||
},
|
||||
'company.groups' => function ($query) use ($updated_at, $user) {
|
||||
@ -276,14 +289,25 @@ class BaseController extends Controller
|
||||
$query->where('updated_at', '>=', $updated_at)->with('invitations', 'documents');
|
||||
|
||||
if (! $user->hasPermission('view_invoice')) {
|
||||
$query->where('invoices.user_id', $user->id)->orWhere('invoices.assigned_user_id', $user->id);
|
||||
// $query->where('invoices.user_id', $user->id)->orWhere('invoices.assigned_user_id', $user->id);
|
||||
|
||||
|
||||
$query->whereNested(function($query) use ($user) {
|
||||
$query->where('invoices.user_id', $user->id)->orWhere('invoices.assigned_user_id', $user->id);
|
||||
});
|
||||
|
||||
}
|
||||
},
|
||||
'company.payments'=> function ($query) use ($updated_at, $user) {
|
||||
$query->where('updated_at', '>=', $updated_at)->with('paymentables', 'documents');
|
||||
|
||||
if (! $user->hasPermission('view_payment')) {
|
||||
$query->where('payments.user_id', $user->id)->orWhere('payments.assigned_user_id', $user->id);
|
||||
// $query->where('payments.user_id', $user->id)->orWhere('payments.assigned_user_id', $user->id);
|
||||
|
||||
$query->whereNested(function($query) use ($user) {
|
||||
$query->where('payments.user_id', $user->id)->orWhere('payments.assigned_user_id', $user->id);
|
||||
});
|
||||
|
||||
}
|
||||
},
|
||||
'company.payment_terms'=> function ($query) use ($updated_at, $user) {
|
||||
@ -297,49 +321,88 @@ class BaseController extends Controller
|
||||
$query->where('updated_at', '>=', $updated_at)->with('documents');
|
||||
|
||||
if (! $user->hasPermission('view_product')) {
|
||||
$query->where('products.user_id', $user->id)->orWhere('products.assigned_user_id', $user->id);
|
||||
// $query->where('products.user_id', $user->id)->orWhere('products.assigned_user_id', $user->id);
|
||||
|
||||
$query->whereNested(function($query) use ($user) {
|
||||
$query->where('products.user_id', $user->id)->orWhere('products.assigned_user_id', $user->id);
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
},
|
||||
'company.projects'=> function ($query) use ($updated_at, $user) {
|
||||
$query->where('updated_at', '>=', $updated_at)->with('documents');
|
||||
|
||||
if (! $user->hasPermission('view_project')) {
|
||||
$query->where('projects.user_id', $user->id)->orWhere('projects.assigned_user_id', $user->id);
|
||||
// $query->where('projects.user_id', $user->id)->orWhere('projects.assigned_user_id', $user->id);
|
||||
|
||||
$query->whereNested(function($query) use ($user) {
|
||||
$query->where('projects.user_id', $user->id)->orWhere('projects.assigned_user_id', $user->id);
|
||||
});
|
||||
|
||||
}
|
||||
},
|
||||
'company.purchase_orders'=> function ($query) use ($updated_at, $user) {
|
||||
$query->where('updated_at', '>=', $updated_at)->with('documents');
|
||||
|
||||
if (! $user->hasPermission('view_purchase_order')) {
|
||||
$query->where('purchase_orders.user_id', $user->id)->orWhere('purchase_orders.assigned_user_id', $user->id);
|
||||
// $query->where('purchase_orders.user_id', $user->id)->orWhere('purchase_orders.assigned_user_id', $user->id);
|
||||
|
||||
|
||||
$query->whereNested(function($query) use ($user) {
|
||||
$query->where('purchase_orders.user_id', $user->id)->orWhere('purchase_orders.assigned_user_id', $user->id);
|
||||
});
|
||||
|
||||
}
|
||||
},
|
||||
'company.quotes'=> function ($query) use ($updated_at, $user) {
|
||||
$query->where('updated_at', '>=', $updated_at)->with('invitations', 'documents');
|
||||
|
||||
if (! $user->hasPermission('view_quote')) {
|
||||
$query->where('quotes.user_id', $user->id)->orWhere('quotes.assigned_user_id', $user->id);
|
||||
// $query->where('quotes.user_id', $user->id)->orWhere('quotes.assigned_user_id', $user->id);
|
||||
|
||||
|
||||
$query->whereNested(function($query) use ($user) {
|
||||
$query->where('quotes.user_id', $user->id)->orWhere('quotes.assigned_user_id', $user->id);
|
||||
});
|
||||
|
||||
}
|
||||
},
|
||||
'company.recurring_invoices'=> function ($query) use ($updated_at, $user) {
|
||||
$query->where('updated_at', '>=', $updated_at)->with('invitations', 'documents', 'client.gateway_tokens', 'client.group_settings', 'client.company');
|
||||
|
||||
if (! $user->hasPermission('view_recurring_invoice')) {
|
||||
$query->where('recurring_invoices.user_id', $user->id)->orWhere('recurring_invoices.assigned_user_id', $user->id);
|
||||
// $query->where('recurring_invoices.user_id', $user->id)->orWhere('recurring_invoices.assigned_user_id', $user->id);
|
||||
|
||||
$query->whereNested(function($query) use ($user) {
|
||||
$query->where('recurring_invoices.user_id', $user->id)->orWhere('recurring_invoices.assigned_user_id', $user->id);
|
||||
});
|
||||
|
||||
}
|
||||
},
|
||||
'company.recurring_expenses'=> function ($query) use ($updated_at, $user) {
|
||||
$query->where('updated_at', '>=', $updated_at)->with('documents');
|
||||
|
||||
if (! $user->hasPermission('view_recurring_expense')) {
|
||||
$query->where('recurring_expenses.user_id', $user->id)->orWhere('recurring_expenses.assigned_user_id', $user->id);
|
||||
// $query->where('recurring_expenses.user_id', $user->id)->orWhere('recurring_expenses.assigned_user_id', $user->id);
|
||||
|
||||
$query->whereNested(function($query) use ($user) {
|
||||
$query->where('recurring_expenses.user_id', $user->id)->orWhere('recurring_expenses.assigned_user_id', $user->id);
|
||||
});
|
||||
|
||||
}
|
||||
},
|
||||
'company.tasks'=> function ($query) use ($updated_at, $user) {
|
||||
$query->where('updated_at', '>=', $updated_at)->with('documents');
|
||||
|
||||
if (! $user->hasPermission('view_task')) {
|
||||
$query->where('tasks.user_id', $user->id)->orWhere('tasks.assigned_user_id', $user->id);
|
||||
// $query->where('tasks.user_id', $user->id)->orWhere('tasks.assigned_user_id', $user->id);
|
||||
|
||||
$query->whereNested(function($query) use ($user) {
|
||||
$query->where('tasks.user_id', $user->id)->orWhere('tasks.assigned_user_id', $user->id);
|
||||
});
|
||||
|
||||
}
|
||||
},
|
||||
'company.tax_rates'=> function ($query) use ($updated_at, $user) {
|
||||
@ -349,7 +412,12 @@ class BaseController extends Controller
|
||||
$query->where('updated_at', '>=', $updated_at)->with('contacts', 'documents');
|
||||
|
||||
if (! $user->hasPermission('view_vendor')) {
|
||||
$query->where('vendors.user_id', $user->id)->orWhere('vendors.assigned_user_id', $user->id);
|
||||
// $query->where('vendors.user_id', $user->id)->orWhere('vendors.assigned_user_id', $user->id);
|
||||
|
||||
$query->whereNested(function($query) use ($user) {
|
||||
$query->where('vendors.user_id', $user->id)->orWhere('vendors.assigned_user_id', $user->id);
|
||||
});
|
||||
|
||||
}
|
||||
},
|
||||
'company.expense_categories'=> function ($query) use ($updated_at, $user) {
|
||||
@ -480,7 +548,12 @@ class BaseController extends Controller
|
||||
$query->where('clients.created_at', '>=', $created_at)->with('contacts.company', 'gateway_tokens', 'documents');
|
||||
|
||||
if (! $user->hasPermission('view_client')) {
|
||||
$query->where('clients.user_id', $user->id)->orWhere('clients.assigned_user_id', $user->id);
|
||||
// $query->where('clients.user_id', $user->id)->orWhere('clients.assigned_user_id', $user->id);
|
||||
|
||||
$query->whereNested(function($query) use ($user) {
|
||||
$query->where('clients.user_id', $user->id)->orWhere('clients.assigned_user_id', $user->id);
|
||||
});
|
||||
|
||||
}
|
||||
},
|
||||
'company.company_gateways' => function ($query) use ($user) {
|
||||
@ -494,7 +567,11 @@ class BaseController extends Controller
|
||||
$query->where('created_at', '>=', $created_at)->with('invitations', 'documents');
|
||||
|
||||
if (! $user->hasPermission('view_credit')) {
|
||||
$query->where('credits.user_id', $user->id)->orWhere('credits.assigned_user_id', $user->id);
|
||||
// $query->where('credits.user_id', $user->id)->orWhere('credits.assigned_user_id', $user->id);
|
||||
|
||||
$query->whereNested(function($query) use ($user) {
|
||||
$query->where('credits.user_id', $user->id)->orWhere('credits.assigned_user_id', $user->id);
|
||||
});
|
||||
}
|
||||
},
|
||||
'company.documents'=> function ($query) use ($created_at, $user) {
|
||||
@ -504,7 +581,13 @@ class BaseController extends Controller
|
||||
$query->where('created_at', '>=', $created_at)->with('documents');
|
||||
|
||||
if (! $user->hasPermission('view_expense')) {
|
||||
$query->where('expenses.user_id', $user->id)->orWhere('expenses.assigned_user_id', $user->id);
|
||||
// $query->where('expenses.user_id', $user->id)->orWhere('expenses.assigned_user_id', $user->id);
|
||||
|
||||
$query->whereNested(function($query) use ($user) {
|
||||
$query->where('expenses.user_id', $user->id)->orWhere('expenses.assigned_user_id', $user->id);
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
},
|
||||
'company.groups' => function ($query) use ($created_at, $user) {
|
||||
@ -514,14 +597,24 @@ class BaseController extends Controller
|
||||
$query->where('created_at', '>=', $created_at)->with('invitations', 'documents');
|
||||
|
||||
if (! $user->hasPermission('view_invoice')) {
|
||||
$query->where('invoices.user_id', $user->id)->orWhere('invoices.assigned_user_id', $user->id);
|
||||
// $query->where('invoices.user_id', $user->id)->orWhere('invoices.assigned_user_id', $user->id);
|
||||
|
||||
$query->whereNested(function($query) use ($user) {
|
||||
$query->where('invoices.user_id', $user->id)->orWhere('invoices.assigned_user_id', $user->id);
|
||||
});
|
||||
|
||||
}
|
||||
},
|
||||
'company.payments'=> function ($query) use ($created_at, $user) {
|
||||
$query->where('created_at', '>=', $created_at)->with('paymentables', 'documents');
|
||||
|
||||
if (! $user->hasPermission('view_payment')) {
|
||||
$query->where('payments.user_id', $user->id)->orWhere('payments.assigned_user_id', $user->id);
|
||||
// $query->where('payments.user_id', $user->id)->orWhere('payments.assigned_user_id', $user->id);
|
||||
|
||||
$query->whereNested(function($query) use ($user) {
|
||||
$query->where('payments.user_id', $user->id)->orWhere('payments.assigned_user_id', $user->id);
|
||||
});
|
||||
|
||||
}
|
||||
},
|
||||
'company.payment_terms'=> function ($query) use ($created_at, $user) {
|
||||
@ -531,42 +624,67 @@ class BaseController extends Controller
|
||||
$query->where('created_at', '>=', $created_at)->with('documents');
|
||||
|
||||
if (! $user->hasPermission('view_product')) {
|
||||
$query->where('products.user_id', $user->id)->orWhere('products.assigned_user_id', $user->id);
|
||||
// $query->where('products.user_id', $user->id)->orWhere('products.assigned_user_id', $user->id);
|
||||
$query->whereNested(function($query) use ($user) {
|
||||
$query->where('products.user_id', $user->id)->orWhere('products.assigned_user_id', $user->id);
|
||||
});
|
||||
}
|
||||
},
|
||||
'company.projects'=> function ($query) use ($created_at, $user) {
|
||||
$query->where('created_at', '>=', $created_at)->with('documents');
|
||||
|
||||
if (! $user->hasPermission('view_project')) {
|
||||
$query->where('projects.user_id', $user->id)->orWhere('projects.assigned_user_id', $user->id);
|
||||
// $query->where('projects.user_id', $user->id)->orWhere('projects.assigned_user_id', $user->id);
|
||||
$query->whereNested(function($query) use ($user) {
|
||||
$query->where('projects.user_id', $user->id)->orWhere('projects.assigned_user_id', $user->id);
|
||||
});
|
||||
}
|
||||
},
|
||||
'company.purchase_orders'=> function ($query) use ($created_at, $user) {
|
||||
$query->where('created_at', '>=', $created_at)->with('documents');
|
||||
|
||||
if (! $user->hasPermission('view_purchase_order')) {
|
||||
$query->where('purchase_orders.user_id', $user->id)->orWhere('purchase_orders.assigned_user_id', $user->id);
|
||||
// $query->where('purchase_orders.user_id', $user->id)->orWhere('purchase_orders.assigned_user_id', $user->id);
|
||||
$query->whereNested(function($query) use ($user) {
|
||||
$query->where('purchase_orders.user_id', $user->id)->orWhere('purchase_orders.assigned_user_id', $user->id);
|
||||
});
|
||||
|
||||
}
|
||||
},
|
||||
'company.quotes'=> function ($query) use ($created_at, $user) {
|
||||
$query->where('created_at', '>=', $created_at)->with('invitations', 'documents');
|
||||
|
||||
if (! $user->hasPermission('view_quote')) {
|
||||
$query->where('quotes.user_id', $user->id)->orWhere('quotes.assigned_user_id', $user->id);
|
||||
// $query->where('quotes.user_id', $user->id)->orWhere('quotes.assigned_user_id', $user->id);
|
||||
|
||||
$query->whereNested(function($query) use ($user) {
|
||||
$query->where('quotes.user_id', $user->id)->orWhere('quotes.assigned_user_id', $user->id);
|
||||
});
|
||||
|
||||
}
|
||||
},
|
||||
'company.recurring_invoices'=> function ($query) use ($created_at, $user) {
|
||||
$query->where('created_at', '>=', $created_at)->with('invitations', 'documents', 'client.gateway_tokens', 'client.group_settings', 'client.company');
|
||||
|
||||
if (! $user->hasPermission('view_recurring_invoice')) {
|
||||
$query->where('recurring_invoices.user_id', $user->id)->orWhere('recurring_invoices.assigned_user_id', $user->id);
|
||||
// $query->where('recurring_invoices.user_id', $user->id)->orWhere('recurring_invoices.assigned_user_id', $user->id);
|
||||
|
||||
$query->whereNested(function($query) use ($user) {
|
||||
$query->where('recurring_invoices.user_id', $user->id)->orWhere('recurring_invoices.assigned_user_id', $user->id);
|
||||
});
|
||||
|
||||
}
|
||||
},
|
||||
'company.tasks'=> function ($query) use ($created_at, $user) {
|
||||
$query->where('created_at', '>=', $created_at)->with('documents');
|
||||
|
||||
if (! $user->hasPermission('view_task')) {
|
||||
$query->where('tasks.user_id', $user->id)->orWhere('tasks.assigned_user_id', $user->id);
|
||||
// $query->where('tasks.user_id', $user->id)->orWhere('tasks.assigned_user_id', $user->id);
|
||||
|
||||
$query->whereNested(function($query) use ($user) {
|
||||
$query->where('tasks.user_id', $user->id)->orWhere('tasks.assigned_user_id', $user->id);
|
||||
});
|
||||
|
||||
}
|
||||
},
|
||||
'company.tax_rates' => function ($query) use ($created_at, $user) {
|
||||
@ -576,7 +694,12 @@ class BaseController extends Controller
|
||||
$query->where('created_at', '>=', $created_at)->with('contacts', 'documents');
|
||||
|
||||
if (! $user->hasPermission('view_vendor')) {
|
||||
$query->where('vendors.user_id', $user->id)->orWhere('vendors.assigned_user_id', $user->id);
|
||||
// $query->where('vendors.user_id', $user->id)->orWhere('vendors.assigned_user_id', $user->id);
|
||||
|
||||
$query->whereNested(function($query) use ($user) {
|
||||
$query->where('vendors.user_id', $user->id)->orWhere('vendors.assigned_user_id', $user->id);
|
||||
});
|
||||
|
||||
}
|
||||
},
|
||||
'company.expense_categories'=> function ($query) use ($created_at, $user) {
|
||||
@ -610,7 +733,12 @@ class BaseController extends Controller
|
||||
$query->where('created_at', '>=', $created_at)->with('documents');
|
||||
|
||||
if (! $user->hasPermission('view_recurring_expense')) {
|
||||
$query->where('recurring_expenses.user_id', $user->id)->orWhere('recurring_expenses.assigned_user_id', $user->id);
|
||||
// $query->where('recurring_expenses.user_id', $user->id)->orWhere('recurring_expenses.assigned_user_id', $user->id);
|
||||
|
||||
$query->whereNested(function($query) use ($user) {
|
||||
$query->where('recurring_expenses.user_id', $user->id)->orWhere('recurring_expenses.assigned_user_id', $user->id);
|
||||
});
|
||||
|
||||
}
|
||||
},
|
||||
]
|
||||
@ -645,7 +773,8 @@ class BaseController extends Controller
|
||||
// 10-01-2022 need to ensure we snake case properly here to ensure permissions work as expected
|
||||
// 28-03-2022 this is definitely correct here, do not append _ to the view, it resolved correctly when snake cased
|
||||
if (auth()->user() && ! auth()->user()->hasPermission('view'.lcfirst(class_basename(Str::snake($this->entity_type))))) {
|
||||
$query->where('user_id', '=', auth()->user()->id);
|
||||
//03-09-2022
|
||||
$query->where('user_id', '=', auth()->user()->id)->orWhere('assigned_user_id', auth()->user()->id);
|
||||
}
|
||||
|
||||
if (request()->has('updated_at') && request()->input('updated_at') > 0) {
|
||||
@ -772,6 +901,11 @@ class BaseController extends Controller
|
||||
return redirect('/')->with(['signup' => 'true']);
|
||||
}
|
||||
|
||||
// 06-09-2022 - parse the path if loaded in a subdirectory for canvaskit resolution
|
||||
$canvas_path_array = parse_url(config('ninja.app_url'));
|
||||
$canvas_path = (array_key_exists('path', $canvas_path_array)) ? $canvas_path_array['path'] : '';
|
||||
$canvas_path = rtrim(str_replace("index.php", "", $canvas_path),'/');
|
||||
|
||||
$data = [];
|
||||
|
||||
//pass report errors bool to front end
|
||||
@ -782,6 +916,7 @@ class BaseController extends Controller
|
||||
$data['build'] = request()->has('build') ? request()->input('build') : '';
|
||||
$data['login'] = request()->has('login') ? request()->input('login') : 'false';
|
||||
$data['signup'] = request()->has('signup') ? request()->input('signup') : 'false';
|
||||
$data['canvas_path'] = $canvas_path;
|
||||
|
||||
if (request()->session()->has('login')) {
|
||||
$data['login'] = 'true';
|
||||
|
@ -35,6 +35,7 @@ class CreditController extends Controller
|
||||
$data = [
|
||||
'credit' => $credit,
|
||||
'key' => $invitation ? $invitation->key : false,
|
||||
'invitation' => $invitation
|
||||
];
|
||||
|
||||
if ($invitation && auth()->guard('contact') && ! request()->has('silent') && ! $invitation->viewed_date) {
|
||||
|
@ -69,6 +69,7 @@ class InvoiceController extends Controller
|
||||
|
||||
$data = [
|
||||
'invoice' => $invoice,
|
||||
'invitation' => $invitation ?: $invoice->invitations->first(),
|
||||
'key' => $invitation ? $invitation->key : false,
|
||||
];
|
||||
|
||||
|
@ -98,6 +98,27 @@ class NinjaPlanController extends Controller
|
||||
$stripe_response = json_decode($request->input('gateway_response'));
|
||||
$customer = $gateway_driver->findOrCreateCustomer();
|
||||
|
||||
//27-08-2022 Ensure customer is updated appropriately
|
||||
$update_client_object['name'] = $client->present()->name();
|
||||
$update_client_object['phone'] = substr($client->present()->phone(), 0, 20);
|
||||
|
||||
$update_client_object['address']['line1'] = $client->address1 ?: '';
|
||||
$update_client_object['address']['line2'] = $client->address2 ?: '';
|
||||
$update_client_object['address']['city'] = $client->city ?: '';
|
||||
$update_client_object['address']['postal_code'] = $client->postal_code ?: '';
|
||||
$update_client_object['address']['state'] = $client->state ?: '';
|
||||
$update_client_object['address']['country'] = $client->country ? $client->country->iso_3166_2 : '';
|
||||
|
||||
$update_client_object['shipping']['name'] = $client->present()->name();
|
||||
$update_client_object['shipping']['address']['line1'] = $client->shipping_address1 ?: '';
|
||||
$update_client_object['shipping']['address']['line2'] = $client->shipping_address2 ?: '';
|
||||
$update_client_object['shipping']['address']['city'] = $client->shipping_city ?: '';
|
||||
$update_client_object['shipping']['address']['postal_code'] = $client->shipping_postal_code ?: '';
|
||||
$update_client_object['shipping']['address']['state'] = $client->shipping_state ?: '';
|
||||
$update_client_object['shipping']['address']['country'] = $client->shipping_country ? $client->shipping_country->iso_3166_2 : '';
|
||||
|
||||
\Stripe\Customer::update($customer->id, $update_client_object, $gateway_driver->stripe_connect_auth);
|
||||
|
||||
$gateway_driver->attach($stripe_response->payment_method, $customer);
|
||||
$method = $gateway_driver->getStripePaymentMethod($stripe_response->payment_method);
|
||||
|
||||
@ -174,6 +195,7 @@ class NinjaPlanController extends Controller
|
||||
|
||||
public function plan()
|
||||
{
|
||||
|
||||
// return $this->trial();
|
||||
//harvest the current plan
|
||||
$data = [];
|
||||
|
@ -101,7 +101,8 @@ class PaymentController extends Controller
|
||||
|
||||
$data = [
|
||||
'invoice' => $invoice,
|
||||
'key' => false
|
||||
'key' => false,
|
||||
'invitation' => $invoice->invitations->first()
|
||||
];
|
||||
|
||||
if ($request->query('mode') === 'fullscreen') {
|
||||
|
@ -61,6 +61,7 @@ class QuoteController extends Controller
|
||||
$data = [
|
||||
'quote' => $quote,
|
||||
'key' => $invitation ? $invitation->key : false,
|
||||
'invitation' => $invitation
|
||||
];
|
||||
|
||||
if ($invitation && auth()->guard('contact') && ! request()->has('silent') && ! $invitation->viewed_date) {
|
||||
@ -180,8 +181,7 @@ class QuoteController extends Controller
|
||||
if ($process) {
|
||||
foreach ($quotes as $quote) {
|
||||
$quote->service()->approve(auth()->user())->save();
|
||||
// event(new QuoteWasApproved(auth()->guard('contact')->user(), $quote, $quote->company, Ninja::eventVars()));
|
||||
|
||||
|
||||
if (request()->has('signature') && ! is_null(request()->signature) && ! empty(request()->signature)) {
|
||||
InjectSignature::dispatch($quote, request()->signature);
|
||||
}
|
||||
|
@ -587,21 +587,21 @@ class CreditController extends BaseController
|
||||
$this->credit_repository->archive($credit);
|
||||
|
||||
if (! $bulk) {
|
||||
return $this->listResponse($credit);
|
||||
return $this->itemResponse($credit);
|
||||
}
|
||||
break;
|
||||
case 'restore':
|
||||
$this->credit_repository->restore($credit);
|
||||
|
||||
if (! $bulk) {
|
||||
return $this->listResponse($credit);
|
||||
return $this->itemResponse($credit);
|
||||
}
|
||||
break;
|
||||
case 'delete':
|
||||
$this->credit_repository->delete($credit);
|
||||
|
||||
if (! $bulk) {
|
||||
return $this->listResponse($credit);
|
||||
return $this->itemResponse($credit);
|
||||
}
|
||||
break;
|
||||
case 'email':
|
||||
|
@ -131,7 +131,7 @@ class EmailController extends BaseController
|
||||
if(Ninja::isHosted() && !$entity_obj->company->account->account_sms_verified)
|
||||
return response(['message' => 'Please verify your account to send emails.'], 400);
|
||||
|
||||
if($entity == 'purchaseOrder' || $template == 'purchase_order'){
|
||||
if($entity == 'purchaseOrder' || $entity == 'purchase_order' || $template == 'purchase_order'){
|
||||
return $this->sendPurchaseOrder($entity_obj, $data);
|
||||
}
|
||||
|
||||
|
@ -722,14 +722,14 @@ class InvoiceController extends BaseController
|
||||
$this->invoice_repo->restore($invoice);
|
||||
|
||||
if (! $bulk) {
|
||||
return $this->listResponse($invoice);
|
||||
return $this->itemResponse($invoice);
|
||||
}
|
||||
break;
|
||||
case 'archive':
|
||||
$this->invoice_repo->archive($invoice);
|
||||
|
||||
if (! $bulk) {
|
||||
return $this->listResponse($invoice);
|
||||
return $this->itemResponse($invoice);
|
||||
}
|
||||
break;
|
||||
case 'delete':
|
||||
@ -737,7 +737,7 @@ class InvoiceController extends BaseController
|
||||
$this->invoice_repo->delete($invoice);
|
||||
|
||||
if (! $bulk) {
|
||||
return $this->listResponse($invoice);
|
||||
return $this->itemResponse($invoice);
|
||||
}
|
||||
break;
|
||||
case 'cancel':
|
||||
|
@ -173,7 +173,7 @@ class PreviewPurchaseOrderController extends BaseController
|
||||
}
|
||||
|
||||
//else
|
||||
$file_path = PreviewPdf::dispatchNow($maker->getCompiledHTML(true), auth()->user()->company());
|
||||
$file_path = (new PreviewPdf($maker->getCompiledHTML(true), auth()->user()->company()))->handle();
|
||||
|
||||
return response()->download($file_path, basename($file_path), ['Cache-Control:' => 'no-cache'])->deleteFileAfterSend(true);
|
||||
}
|
||||
@ -285,7 +285,7 @@ class PreviewPurchaseOrderController extends BaseController
|
||||
return $pdf;
|
||||
}
|
||||
|
||||
$file_path = PreviewPdf::dispatchNow($maker->getCompiledHTML(true), $company);
|
||||
$file_path = (new PreviewPdf($maker->getCompiledHTML(true), $company))->handle();
|
||||
|
||||
|
||||
if(Ninja::isHosted())
|
||||
@ -363,7 +363,7 @@ class PreviewPurchaseOrderController extends BaseController
|
||||
return $pdf;
|
||||
}
|
||||
|
||||
$file_path = PreviewPdf::dispatchNow($maker->getCompiledHTML(true), auth()->user()->company());
|
||||
$file_path = (new PreviewPdf($maker->getCompiledHTML(true), auth()->user()->company()))->handle();
|
||||
|
||||
$response = Response::make($file_path, 200);
|
||||
$response->header('Content-Type', 'application/pdf');
|
||||
@ -460,7 +460,7 @@ class PreviewPurchaseOrderController extends BaseController
|
||||
return $pdf;
|
||||
}
|
||||
|
||||
$file_path = PreviewPdf::dispatchNow($maker->getCompiledHTML(true), auth()->user()->company());
|
||||
$file_path = (new PreviewPdf($maker->getCompiledHTML(true), auth()->user()->company()))->handle();
|
||||
|
||||
$response = Response::make($file_path, 200);
|
||||
$response->header('Content-Type', 'application/pdf');
|
||||
|
@ -623,14 +623,14 @@ class PurchaseOrderController extends BaseController
|
||||
$this->purchase_order_repository->restore($purchase_order);
|
||||
|
||||
if (! $bulk) {
|
||||
return $this->listResponse($purchase_order);
|
||||
return $this->itemResponse($purchase_order);
|
||||
}
|
||||
break;
|
||||
case 'archive':
|
||||
$this->purchase_order_repository->archive($purchase_order);
|
||||
|
||||
if (! $bulk) {
|
||||
return $this->listResponse($purchase_order);
|
||||
return $this->itemResponse($purchase_order);
|
||||
}
|
||||
break;
|
||||
case 'delete':
|
||||
@ -638,7 +638,7 @@ class PurchaseOrderController extends BaseController
|
||||
$this->purchase_order_repository->delete($purchase_order);
|
||||
|
||||
if (! $bulk) {
|
||||
return $this->listResponse($purchase_order);
|
||||
return $this->itemResponse($purchase_order);
|
||||
}
|
||||
break;
|
||||
|
||||
@ -684,7 +684,7 @@ class PurchaseOrderController extends BaseController
|
||||
}
|
||||
|
||||
if (! $bulk) {
|
||||
return $this->listResponse($purchase_order);
|
||||
return $this->itemResponse($purchase_order);
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -15,6 +15,7 @@ use App\Events\Quote\QuoteWasCreated;
|
||||
use App\Events\Quote\QuoteWasUpdated;
|
||||
use App\Factory\CloneQuoteFactory;
|
||||
use App\Factory\CloneQuoteToInvoiceFactory;
|
||||
use App\Factory\CloneQuoteToProjectFactory;
|
||||
use App\Factory\QuoteFactory;
|
||||
use App\Filters\QuoteFilters;
|
||||
use App\Http\Requests\Quote\ActionQuoteRequest;
|
||||
@ -31,12 +32,15 @@ use App\Jobs\Quote\ZipQuotes;
|
||||
use App\Models\Account;
|
||||
use App\Models\Client;
|
||||
use App\Models\Invoice;
|
||||
use App\Models\Project;
|
||||
use App\Models\Quote;
|
||||
use App\Repositories\QuoteRepository;
|
||||
use App\Transformers\InvoiceTransformer;
|
||||
use App\Transformers\ProjectTransformer;
|
||||
use App\Transformers\QuoteTransformer;
|
||||
use App\Utils\Ninja;
|
||||
use App\Utils\TempFile;
|
||||
use App\Utils\Traits\GeneratesCounter;
|
||||
use App\Utils\Traits\MakesHash;
|
||||
use App\Utils\Traits\SavesDocuments;
|
||||
use Illuminate\Http\Request;
|
||||
@ -50,6 +54,7 @@ class QuoteController extends BaseController
|
||||
{
|
||||
use MakesHash;
|
||||
use SavesDocuments;
|
||||
use GeneratesCounter;
|
||||
|
||||
protected $entity_type = Quote::class;
|
||||
|
||||
@ -556,6 +561,28 @@ class QuoteController extends BaseController
|
||||
return $this->listResponse(Quote::withTrashed()->whereIn('id', $this->transformKeys($ids))->company());
|
||||
}
|
||||
|
||||
|
||||
if($action == 'convert_to_project')
|
||||
{
|
||||
|
||||
$quotes->each(function ($quote, $key) use ($action) {
|
||||
if (auth()->user()->can('edit', $quote))
|
||||
{
|
||||
$project = CloneQuoteToProjectFactory::create($quote, auth()->user()->id);
|
||||
|
||||
if (empty($project->number)) {
|
||||
$project->number = $this->getNextProjectNumber($project);
|
||||
|
||||
}
|
||||
$project->save();
|
||||
$quote->project_id = $project->id;
|
||||
$quote->save();
|
||||
}
|
||||
});
|
||||
|
||||
return $this->listResponse(Quote::withTrashed()->whereIn('id', $this->transformKeys($ids))->company());
|
||||
}
|
||||
|
||||
/*
|
||||
* Send the other actions to the switch
|
||||
*/
|
||||
@ -661,6 +688,7 @@ class QuoteController extends BaseController
|
||||
return $this->itemResponse($quote->service()->convertToInvoice());
|
||||
|
||||
break;
|
||||
|
||||
case 'clone_to_invoice':
|
||||
|
||||
$this->entity_type = Invoice::class;
|
||||
@ -700,7 +728,7 @@ class QuoteController extends BaseController
|
||||
$this->quote_repo->restore($quote);
|
||||
|
||||
if (! $bulk) {
|
||||
return $this->listResponse($quote);
|
||||
return $this->itemResponse($quote);
|
||||
}
|
||||
|
||||
break;
|
||||
@ -708,7 +736,7 @@ class QuoteController extends BaseController
|
||||
$this->quote_repo->archive($quote);
|
||||
|
||||
if (! $bulk) {
|
||||
return $this->listResponse($quote);
|
||||
return $this->itemResponse($quote);
|
||||
}
|
||||
|
||||
break;
|
||||
@ -716,7 +744,7 @@ class QuoteController extends BaseController
|
||||
$this->quote_repo->delete($quote);
|
||||
|
||||
if (! $bulk) {
|
||||
return $this->listResponse($quote);
|
||||
return $this->itemResponse($quote);
|
||||
}
|
||||
|
||||
break;
|
||||
|
@ -511,21 +511,21 @@ class RecurringExpenseController extends BaseController
|
||||
$this->recurring_expense_repo->archive($recurring_expense);
|
||||
|
||||
if (! $bulk) {
|
||||
return $this->listResponse($recurring_expense);
|
||||
return $this->itemResponse($recurring_expense);
|
||||
}
|
||||
break;
|
||||
case 'restore':
|
||||
$this->recurring_expense_repo->restore($recurring_expense);
|
||||
|
||||
if (! $bulk) {
|
||||
return $this->listResponse($recurring_expense);
|
||||
return $this->itemResponse($recurring_expense);
|
||||
}
|
||||
break;
|
||||
case 'delete':
|
||||
$this->recurring_expense_repo->delete($recurring_expense);
|
||||
|
||||
if (! $bulk) {
|
||||
return $this->listResponse($recurring_expense);
|
||||
return $this->itemResponse($recurring_expense);
|
||||
}
|
||||
break;
|
||||
case 'email':
|
||||
|
@ -662,21 +662,21 @@ class RecurringInvoiceController extends BaseController
|
||||
$this->recurring_invoice_repo->archive($recurring_invoice);
|
||||
|
||||
if (! $bulk) {
|
||||
return $this->listResponse($recurring_invoice);
|
||||
return $this->itemResponse($recurring_invoice);
|
||||
}
|
||||
break;
|
||||
case 'restore':
|
||||
$this->recurring_invoice_repo->restore($recurring_invoice);
|
||||
|
||||
if (! $bulk) {
|
||||
return $this->listResponse($recurring_invoice);
|
||||
return $this->itemResponse($recurring_invoice);
|
||||
}
|
||||
break;
|
||||
case 'delete':
|
||||
$this->recurring_invoice_repo->delete($recurring_invoice);
|
||||
|
||||
if (! $bulk) {
|
||||
return $this->listResponse($recurring_invoice);
|
||||
return $this->itemResponse($recurring_invoice);
|
||||
}
|
||||
break;
|
||||
case 'email':
|
||||
|
@ -17,6 +17,7 @@ use App\Utils\Traits\MakesHash;
|
||||
use App\Utils\Traits\UserSessionAttributes;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
use Illuminate\Support\Facades\Validator;
|
||||
|
||||
/**
|
||||
* Class VerifiesUserEmail.
|
||||
@ -33,14 +34,12 @@ trait VerifiesUserEmail
|
||||
{
|
||||
$user = User::where('confirmation_code', request()->confirmation_code)->first();
|
||||
|
||||
// if ($user = User::whereRaw("BINARY `confirmation_code`= ?", request()->input('confirmation_code'))->first()) {
|
||||
|
||||
if (! $user) {
|
||||
return $this->render('auth.confirmed', ['root' => 'themes', 'message' => ctrans('texts.wrong_confirmation')]);
|
||||
}
|
||||
|
||||
$user->email_verified_at = now();
|
||||
$user->confirmation_code = null;
|
||||
// $user->confirmation_code = null; //this prevented the form from showing validation errors.
|
||||
$user->save();
|
||||
|
||||
if (isset($user->oauth_user_id)) {
|
||||
@ -64,10 +63,18 @@ trait VerifiesUserEmail
|
||||
{
|
||||
$user = User::where('id', $this->decodePrimaryKey(request()->user_id))->firstOrFail();
|
||||
|
||||
request()->validate([
|
||||
'password' => ['required', 'min:6'],
|
||||
$validator = Validator::make(request()->all(), [
|
||||
//'password' => ['required', 'min:6'],
|
||||
'password' => 'min:6|required_with:password_confirmation|same:password_confirmation',
|
||||
'password_confirmation' => 'min:6'
|
||||
]);
|
||||
|
||||
if ($validator->fails()) {
|
||||
return back()
|
||||
->withErrors($validator)
|
||||
->withInput();
|
||||
}
|
||||
|
||||
$user->password = Hash::make(request()->password);
|
||||
|
||||
$user->email_verified_at = now();
|
||||
|
@ -210,7 +210,7 @@ class UserController extends BaseController
|
||||
|
||||
$user_agent = request()->input('token_name') ?: request()->server('HTTP_USER_AGENT');
|
||||
|
||||
$ct = CreateCompanyToken::dispatchNow($company, $user, $user_agent);
|
||||
$ct = (new CreateCompanyToken($company, $user, $user_agent))->handle();
|
||||
|
||||
event(new UserWasCreated($user, auth()->user(), $company, Ninja::eventVars(auth()->user() ? auth()->user()->id : null)));
|
||||
|
||||
|
@ -108,8 +108,6 @@ class InvitationController extends Controller
|
||||
|
||||
$file_name = $invitation->purchase_order->numberFormatter().'.pdf';
|
||||
|
||||
// $file = CreateRawPdf::dispatchNow($invitation, $invitation->company->db);
|
||||
|
||||
$file = (new CreatePurchaseOrderPdf($invitation))->rawPdf();
|
||||
|
||||
$headers = ['Content-Type' => 'application/pdf'];
|
||||
|
@ -99,6 +99,7 @@ class PurchaseOrderController extends Controller
|
||||
'settings' => $purchase_order->company->settings,
|
||||
'sidebar' => $this->sidebarMenu(),
|
||||
'company' => $purchase_order->company,
|
||||
'invitation' => $invitation
|
||||
];
|
||||
|
||||
if ($request->query('mode') === 'fullscreen') {
|
||||
|
@ -265,6 +265,9 @@ class BillingPortalPurchase extends Component
|
||||
}
|
||||
}
|
||||
|
||||
// nlog($this->subscription->group_settings->settings);
|
||||
// nlog($this->subscription->group_settings->settings->currency_id);
|
||||
|
||||
if(array_key_exists('currency_id', $this->request_data)) {
|
||||
|
||||
$currency = Cache::get('currencies')->filter(function ($item){
|
||||
@ -274,6 +277,16 @@ class BillingPortalPurchase extends Component
|
||||
if($currency)
|
||||
$data['settings']->currency_id = $currency->id;
|
||||
|
||||
}
|
||||
elseif($this->subscription->group_settings && property_exists($this->subscription->group_settings->settings, 'currency_id')) {
|
||||
|
||||
$currency = Cache::get('currencies')->filter(function ($item){
|
||||
return $item->id == $this->subscription->group_settings->settings->currency_id;
|
||||
})->first();
|
||||
|
||||
if($currency)
|
||||
$data['settings']->currency_id = $currency->id;
|
||||
|
||||
}
|
||||
|
||||
if (array_key_exists('locale', $this->request_data)) {
|
||||
@ -494,7 +507,7 @@ class BillingPortalPurchase extends Component
|
||||
$mailer->settings = $this->subscription->company->settings;
|
||||
$mailer->to_user = $contact;
|
||||
|
||||
NinjaMailerJob::dispatchNow($mailer);
|
||||
NinjaMailerJob::dispatch($mailer);
|
||||
|
||||
$this->steps['passwordless_login_sent'] = true;
|
||||
$this->passwordless_login_btn = false;
|
||||
|
@ -29,10 +29,10 @@ class NameWebsiteLogo extends Component
|
||||
{
|
||||
$this->fill([
|
||||
'profile' => auth()->guard('contact')->user()->client,
|
||||
'name' => auth()->guard('contact')->user()->client->present()->name,
|
||||
'vat_number' => auth()->guard('contact')->user()->client->present()->vat_number,
|
||||
'website' => auth()->guard('contact')->user()->client->present()->website,
|
||||
'phone' => auth()->guard('contact')->user()->client->present()->phone,
|
||||
'name' => auth()->guard('contact')->user()->client->present()->name(),
|
||||
'vat_number' => auth()->guard('contact')->user()->client->vat_number ?: '',
|
||||
'website' => auth()->guard('contact')->user()->client->website,
|
||||
'phone' => auth()->guard('contact')->user()->client->present()->phone(),
|
||||
'saved' => ctrans('texts.save'),
|
||||
]);
|
||||
}
|
||||
|
@ -20,7 +20,6 @@ use Livewire\WithPagination;
|
||||
|
||||
class QuotesTable extends Component
|
||||
{
|
||||
use WithSorting;
|
||||
use WithPagination;
|
||||
|
||||
public $per_page = 10;
|
||||
@ -29,6 +28,19 @@ class QuotesTable extends Component
|
||||
|
||||
public $company;
|
||||
|
||||
public $sort = 'status_id'; // Default sortBy. Feel free to change or pull from client/company settings.
|
||||
|
||||
public $sort_asc = true;
|
||||
|
||||
public function sortBy($field)
|
||||
{
|
||||
$this->sort === $field
|
||||
? $this->sort_asc = ! $this->sort_asc
|
||||
: $this->sort_asc = true;
|
||||
|
||||
$this->sort = $field;
|
||||
}
|
||||
|
||||
public function mount()
|
||||
{
|
||||
MultiDB::setDb($this->company->db);
|
||||
@ -36,15 +48,15 @@ class QuotesTable extends Component
|
||||
|
||||
public function render()
|
||||
{
|
||||
|
||||
$query = Quote::query()
|
||||
->with('client.gateway_tokens', 'company', 'client.contacts')
|
||||
->orderBy($this->sort_field, $this->sort_asc ? 'asc' : 'desc');
|
||||
->orderBy($this->sort, $this->sort_asc ? 'asc' : 'desc');
|
||||
|
||||
if (count($this->status) > 0) {
|
||||
|
||||
/* Special filter for expired*/
|
||||
if (in_array('-1', $this->status)) {
|
||||
// $query->whereDate('due_date', '<=', now()->startOfDay());
|
||||
|
||||
$query->where(function ($query) {
|
||||
$query->whereDate('due_date', '<=', now()->startOfDay())
|
||||
@ -69,10 +81,6 @@ class QuotesTable extends Component
|
||||
->where('company_id', $this->company->id)
|
||||
->where('client_id', auth()->guard('contact')->user()->client->id)
|
||||
->where('status_id', '<>', Quote::STATUS_DRAFT)
|
||||
// ->where(function ($query){
|
||||
// $query->whereDate('due_date', '>=', now())
|
||||
// ->orWhereNull('due_date');
|
||||
// })
|
||||
->where('is_deleted', 0)
|
||||
->withTrashed()
|
||||
->paginate($this->per_page);
|
||||
|
@ -56,6 +56,7 @@ class SubscriptionPlanSwitch extends Component
|
||||
*/
|
||||
public $total;
|
||||
|
||||
public $hide_button = false;
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
@ -139,12 +140,20 @@ class SubscriptionPlanSwitch extends Component
|
||||
|
||||
public function handlePaymentNotRequired()
|
||||
{
|
||||
return $this->target->service()->createChangePlanCredit([
|
||||
$this->hide_button = true;
|
||||
|
||||
$response = $this->target->service()->createChangePlanCredit([
|
||||
'recurring_invoice' => $this->recurring_invoice,
|
||||
'subscription' => $this->subscription,
|
||||
'target' => $this->target,
|
||||
'hash' => $this->hash,
|
||||
]);
|
||||
|
||||
$this->hide_button = true;
|
||||
|
||||
$this->dispatchBrowserEvent('redirectRoute', ['route' => $response]);
|
||||
|
||||
// return redirect($response);
|
||||
}
|
||||
|
||||
public function render()
|
||||
|
@ -21,6 +21,7 @@ class ContactRegister
|
||||
{
|
||||
$domain_name = $request->getHost();
|
||||
|
||||
/* Hosted */
|
||||
if (strpos($domain_name, 'invoicing.co') !== false) {
|
||||
$subdomain = explode('.', $domain_name)[0];
|
||||
|
||||
@ -42,6 +43,7 @@ class ContactRegister
|
||||
}
|
||||
}
|
||||
|
||||
/* Hosted */
|
||||
if (Ninja::isHosted()) {
|
||||
$query = [
|
||||
'portal_domain' => $request->getSchemeAndHttpHost(),
|
||||
|
@ -65,7 +65,7 @@ class StoreClientRequest extends Request
|
||||
/* Ensure we have a client name, and that all emails are unique*/
|
||||
//$rules['name'] = 'required|min:1';
|
||||
$rules['settings'] = new ValidClientGroupSettingsRule();
|
||||
$rules['contacts'] = 'array';
|
||||
$rules['contacts'] = 'bail|array';
|
||||
$rules['contacts.*.email'] = 'bail|nullable|distinct|sometimes|email';
|
||||
$rules['contacts.*.password'] = [
|
||||
'bail',
|
||||
|
@ -1,4 +1,13 @@
|
||||
<?php
|
||||
/**
|
||||
* Invoice Ninja (https://invoiceninja.com).
|
||||
*
|
||||
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||
*
|
||||
* @copyright Copyright (c) 2022. Invoice Ninja LLC (https://invoiceninja.com)
|
||||
*
|
||||
* @license https://www.elastic.co/licensing/elastic-license
|
||||
*/
|
||||
|
||||
namespace App\Http\Requests\ClientPortal;
|
||||
|
||||
@ -7,6 +16,7 @@ use App\Models\Account;
|
||||
use App\Models\Company;
|
||||
use App\Utils\Ninja;
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
use Illuminate\Validation\Rule;
|
||||
|
||||
class RegisterRequest extends FormRequest
|
||||
{
|
||||
@ -31,13 +41,13 @@ class RegisterRequest extends FormRequest
|
||||
|
||||
foreach ($this->company()->client_registration_fields as $field) {
|
||||
if ($field['required']) {
|
||||
$rules[$field['key']] = ['required'];
|
||||
$rules[$field['key']] = ['bail','required'];
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($rules as $field => $properties) {
|
||||
if ($field === 'email') {
|
||||
$rules[$field] = array_merge($rules[$field], ['email:rfc,dns', 'max:255']);
|
||||
$rules[$field] = array_merge($rules[$field], ['email:rfc,dns', 'max:255', Rule::unique('client_contacts')->where('company_id', $this->company()->id)]);
|
||||
}
|
||||
|
||||
if ($field === 'current_password') {
|
||||
|
@ -14,6 +14,7 @@ namespace App\Http\Requests\Expense;
|
||||
use App\Http\Requests\Request;
|
||||
use App\Http\ValidationRules\Expense\UniqueExpenseNumberRule;
|
||||
use App\Models\Expense;
|
||||
use App\Models\Project;
|
||||
use App\Models\PurchaseOrder;
|
||||
use App\Utils\Traits\MakesHash;
|
||||
use Illuminate\Validation\Rule;
|
||||
@ -65,13 +66,29 @@ class StoreExpenseRequest extends Request
|
||||
$input['color'] = '';
|
||||
}
|
||||
|
||||
|
||||
/* Ensure the project is related */
|
||||
if (array_key_exists('project_id', $input) && isset($input['project_id'])) {
|
||||
$project = Project::withTrashed()->where('id', $input['project_id'])->company()->first();
|
||||
|
||||
if($project){
|
||||
$input['client_id'] = $project->client_id;
|
||||
}
|
||||
else
|
||||
{
|
||||
unset($input['project_id']);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
$this->replace($input);
|
||||
}
|
||||
|
||||
public function messages()
|
||||
{
|
||||
return [
|
||||
'unique' => ctrans('validation.unique', ['attribute' => 'email']),
|
||||
// 'unique' => ctrans('validation.unique', ['attribute' => 'number']),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
@ -12,6 +12,7 @@
|
||||
namespace App\Http\Requests\Expense;
|
||||
|
||||
use App\Http\Requests\Request;
|
||||
use App\Models\Project;
|
||||
use App\Utils\Traits\ChecksEntityStatus;
|
||||
use App\Utils\Traits\MakesHash;
|
||||
use Illuminate\Validation\Rule;
|
||||
@ -35,10 +36,7 @@ class UpdateExpenseRequest extends Request
|
||||
{
|
||||
/* Ensure we have a client name, and that all emails are unique*/
|
||||
$rules = [];
|
||||
// $rules['country_id'] = 'integer|nullable';
|
||||
|
||||
// $rules['contacts.*.email'] = 'nullable|distinct';
|
||||
|
||||
|
||||
if (isset($this->number)) {
|
||||
$rules['number'] = Rule::unique('expenses')->where('company_id', auth()->user()->company()->id)->ignore($this->expense->id);
|
||||
}
|
||||
@ -46,16 +44,6 @@ class UpdateExpenseRequest extends Request
|
||||
return $this->globalRules($rules);
|
||||
}
|
||||
|
||||
public function messages()
|
||||
{
|
||||
return [
|
||||
'unique' => ctrans('validation.unique', ['attribute' => 'email']),
|
||||
'email' => ctrans('validation.email', ['attribute' => 'email']),
|
||||
'name.required' => ctrans('validation.required', ['attribute' => 'name']),
|
||||
'required' => ctrans('validation.required', ['attribute' => 'email']),
|
||||
];
|
||||
}
|
||||
|
||||
public function prepareForValidation()
|
||||
{
|
||||
$input = $this->all();
|
||||
@ -74,6 +62,20 @@ class UpdateExpenseRequest extends Request
|
||||
$input['currency_id'] = (string) auth()->user()->company()->settings->currency_id;
|
||||
}
|
||||
|
||||
/* Ensure the project is related */
|
||||
if (array_key_exists('project_id', $input) && isset($input['project_id'])) {
|
||||
$project = Project::withTrashed()->where('id', $input['project_id'])->company()->first();
|
||||
|
||||
if($project){
|
||||
$input['client_id'] = $project->client_id;
|
||||
}
|
||||
else
|
||||
{
|
||||
unset($input['project_id']);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
$this->replace($input);
|
||||
}
|
||||
}
|
||||
|
@ -47,15 +47,4 @@ class LoginRequest extends Request
|
||||
];
|
||||
}
|
||||
|
||||
// public function prepareForValidation()
|
||||
// {
|
||||
// $input = $this->all();
|
||||
|
||||
// // if(base64_decode(base64_encode($input['password'])) === $input['password'])
|
||||
// // $input['password'] = base64_decode($input['password']);
|
||||
|
||||
// // nlog($input['password']);
|
||||
|
||||
// $this->replace($input);
|
||||
// }
|
||||
}
|
||||
|
@ -43,7 +43,7 @@ class StorePaymentRequest extends Request
|
||||
$invoices_total = 0;
|
||||
$credits_total = 0;
|
||||
|
||||
if (isset($input['client_id'])) {
|
||||
if (isset($input['client_id']) && is_string($input['client_id']) ) {
|
||||
$input['client_id'] = $this->decodePrimaryKey($input['client_id']);
|
||||
}
|
||||
|
||||
@ -53,7 +53,9 @@ class StorePaymentRequest extends Request
|
||||
|
||||
if (isset($input['invoices']) && is_array($input['invoices']) !== false) {
|
||||
foreach ($input['invoices'] as $key => $value) {
|
||||
$input['invoices'][$key]['invoice_id'] = $this->decodePrimaryKey($value['invoice_id']);
|
||||
|
||||
if(is_string($value['invoice_id']))
|
||||
$input['invoices'][$key]['invoice_id'] = $this->decodePrimaryKey($value['invoice_id']);
|
||||
|
||||
if (array_key_exists('amount', $value)) {
|
||||
$invoices_total += $value['amount'];
|
||||
@ -68,15 +70,14 @@ class StorePaymentRequest extends Request
|
||||
if (isset($input['credits']) && is_array($input['credits']) !== false) {
|
||||
foreach ($input['credits'] as $key => $value) {
|
||||
if (array_key_exists('credit_id', $input['credits'][$key])) {
|
||||
$input['credits'][$key]['credit_id'] = $value['credit_id'];
|
||||
// $input['credits'][$key]['credit_id'] = $value['credit_id'];
|
||||
$input['credits'][$key]['credit_id'] = $this->decodePrimaryKey($value['credit_id']);
|
||||
|
||||
$credits_total += $value['amount'];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// if (array_key_exists('amount', $input))
|
||||
// $input['amount'] = 0;
|
||||
|
||||
if (isset($input['credits']) && is_array($input['credits']) === false) {
|
||||
$input['credits'] = null;
|
||||
}
|
||||
@ -97,14 +98,15 @@ class StorePaymentRequest extends Request
|
||||
public function rules()
|
||||
{
|
||||
$rules = [
|
||||
'amount' => ['numeric', 'bail', new PaymentAmountsBalanceRule(), new ValidCreditsPresentRule()],
|
||||
'client_id' => 'bail|required|exists:clients,id',
|
||||
'amount' => ['numeric', 'bail', new PaymentAmountsBalanceRule(), new ValidCreditsPresentRule($this->all())],
|
||||
// 'client_id' => 'bail|required|exists:clients,id',
|
||||
'client_id' => 'bail|required|exists:clients,id,company_id,'.auth()->user()->company()->id.',is_deleted,0',
|
||||
'invoices.*.invoice_id' => 'bail|required|distinct|exists:invoices,id',
|
||||
'invoices.*.amount' => 'bail|required',
|
||||
'invoices.*.invoice_id' => new ValidInvoicesRules($this->all()),
|
||||
'credits.*.credit_id' => 'bail|required|exists:credits,id',
|
||||
'credits.*.credit_id' => new ValidCreditsRules($this->all()),
|
||||
'credits.*.amount' => ['required', new CreditsSumRule($this->all())],
|
||||
'credits.*.amount' => ['bail','required', new CreditsSumRule($this->all())],
|
||||
'invoices' => new ValidPayableInvoicesRule(),
|
||||
'number' => ['nullable', 'bail', Rule::unique('payments')->where('company_id', auth()->user()->company()->id)],
|
||||
|
||||
|
@ -36,7 +36,7 @@ class UpdatePaymentRequest extends Request
|
||||
public function rules()
|
||||
{
|
||||
$rules = [
|
||||
'invoices' => ['array', new PaymentAppliedValidAmount, new ValidCreditsPresentRule],
|
||||
'invoices' => ['array', new PaymentAppliedValidAmount, new ValidCreditsPresentRule($this->all())],
|
||||
'invoices.*.invoice_id' => 'distinct',
|
||||
'documents' => 'mimes:png,ai,jpeg,tiff,pdf,gif,psd,txt,doc,xls,ppt,xlsx,docx,pptx',
|
||||
];
|
||||
@ -79,6 +79,14 @@ class UpdatePaymentRequest extends Request
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($input['credits']) && is_array($input['credits']) !== false) {
|
||||
foreach ($input['credits'] as $key => $value) {
|
||||
if (array_key_exists('credits', $input['credits'][$key])) {
|
||||
$input['credits'][$key]['credit_id'] = $this->decodePrimaryKey($value['credit_id']);
|
||||
}
|
||||
}
|
||||
}
|
||||
$this->replace($input);
|
||||
}
|
||||
|
||||
|
@ -139,9 +139,14 @@ class Request extends FormRequest
|
||||
$input['invitations'][$key]['id'] = $this->decodePrimaryKey($input['invitations'][$key]['id']);
|
||||
}
|
||||
|
||||
if (is_string($input['invitations'][$key]['client_contact_id'])) {
|
||||
if (array_key_exists('client_contact_id', $input['invitations'][$key]) && is_string($input['invitations'][$key]['client_contact_id'])) {
|
||||
$input['invitations'][$key]['client_contact_id'] = $this->decodePrimaryKey($input['invitations'][$key]['client_contact_id']);
|
||||
}
|
||||
|
||||
if (array_key_exists('vendor_contact_id', $input['invitations'][$key]) && is_string($input['invitations'][$key]['vendor_contact_id'])) {
|
||||
$input['invitations'][$key]['vendor_contact_id'] = $this->decodePrimaryKey($input['invitations'][$key]['vendor_contact_id']);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -12,6 +12,7 @@
|
||||
namespace App\Http\Requests\Task;
|
||||
|
||||
use App\Http\Requests\Request;
|
||||
use App\Models\Project;
|
||||
use App\Models\Task;
|
||||
use App\Utils\Traits\MakesHash;
|
||||
use Illuminate\Validation\Rule;
|
||||
@ -38,19 +39,49 @@ class StoreTaskRequest extends Request
|
||||
$rules['number'] = Rule::unique('tasks')->where('company_id', auth()->user()->company()->id);
|
||||
}
|
||||
|
||||
if(isset($this->client_id))
|
||||
$rules['client_id'] = 'bail|required|exists:clients,id,company_id,'.auth()->user()->company()->id.',is_deleted,0';
|
||||
|
||||
if(isset($this->project_id))
|
||||
$rules['project_id'] = 'bail|required|exists:projects,id,company_id,'.auth()->user()->company()->id.',is_deleted,0';
|
||||
|
||||
$rules['timelog'] = ['bail','array',function ($attribute, $values, $fail) {
|
||||
|
||||
foreach($values as $k)
|
||||
{
|
||||
if(!is_int($k[0]) || !is_int($k[1]))
|
||||
$fail('The '.$attribute.' - '.print_r($k,1).' is invalid. Unix timestamps only.');
|
||||
}
|
||||
|
||||
}];
|
||||
|
||||
|
||||
return $this->globalRules($rules);
|
||||
}
|
||||
|
||||
public function prepareForValidation()
|
||||
{
|
||||
$input = $this->all();
|
||||
|
||||
$input = $this->decodePrimaryKeys($this->all());
|
||||
|
||||
if (array_key_exists('status_id', $input) && is_string($input['status_id'])) {
|
||||
$input['status_id'] = $this->decodePrimaryKey($input['status_id']);
|
||||
}
|
||||
|
||||
/* Ensure the project is related */
|
||||
if (array_key_exists('project_id', $input) && isset($input['project_id'])) {
|
||||
$project = Project::withTrashed()->where('id', $input['project_id'])->company()->first();
|
||||
;
|
||||
if($project){
|
||||
$input['client_id'] = $project->client_id;
|
||||
}
|
||||
else
|
||||
{
|
||||
unset($input['project_id']);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
$this->replace($input);
|
||||
}
|
||||
}
|
||||
|
@ -12,6 +12,7 @@
|
||||
namespace App\Http\Requests\Task;
|
||||
|
||||
use App\Http\Requests\Request;
|
||||
use App\Models\Project;
|
||||
use App\Utils\Traits\ChecksEntityStatus;
|
||||
use App\Utils\Traits\MakesHash;
|
||||
use Illuminate\Validation\Rule;
|
||||
@ -39,6 +40,22 @@ class UpdateTaskRequest extends Request
|
||||
$rules['number'] = Rule::unique('tasks')->where('company_id', auth()->user()->company()->id)->ignore($this->task->id);
|
||||
}
|
||||
|
||||
if(isset($this->client_id))
|
||||
$rules['client_id'] = 'bail|required|exists:clients,id,company_id,'.auth()->user()->company()->id.',is_deleted,0';
|
||||
|
||||
if(isset($this->project_id))
|
||||
$rules['project_id'] = 'bail|required|exists:projects,id,company_id,'.auth()->user()->company()->id.',is_deleted,0';
|
||||
|
||||
$rules['timelog'] = ['bail','array',function ($attribute, $values, $fail) {
|
||||
|
||||
foreach($values as $k)
|
||||
{
|
||||
if(!is_int($k[0]) || !is_int($k[1]))
|
||||
$fail('The '.$attribute.' - '.print_r($k,1).' is invalid. Unix timestamps only.');
|
||||
}
|
||||
|
||||
}];
|
||||
|
||||
return $this->globalRules($rules);
|
||||
}
|
||||
|
||||
@ -50,6 +67,20 @@ class UpdateTaskRequest extends Request
|
||||
$input['status_id'] = $this->decodePrimaryKey($input['status_id']);
|
||||
}
|
||||
|
||||
/* Ensure the project is related */
|
||||
if (array_key_exists('project_id', $input) && isset($input['project_id'])) {
|
||||
$project = Project::withTrashed()->where('id', $input['project_id'])->company()->first();
|
||||
|
||||
if($project){
|
||||
$input['client_id'] = $project->client_id;
|
||||
}
|
||||
else
|
||||
{
|
||||
unset($input['project_id']);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (array_key_exists('color', $input) && is_null($input['color'])) {
|
||||
$input['color'] = '';
|
||||
}
|
||||
|
@ -24,7 +24,8 @@ class BlackListRule implements Rule
|
||||
'vusra.com',
|
||||
'fourthgenet.com',
|
||||
'arxxwalls.com',
|
||||
'superhostforumla.com'
|
||||
'superhostforumla.com',
|
||||
'wnpop.com',
|
||||
];
|
||||
|
||||
/**
|
||||
|
@ -50,11 +50,23 @@ class ValidCreditsRules implements Rule
|
||||
}
|
||||
|
||||
$unique_array = [];
|
||||
|
||||
$total_credit_amount = array_sum(array_column($this->input['credits'], 'amount'));
|
||||
|
||||
if($total_credit_amount <= 0){
|
||||
|
||||
$this->error_msg = "Total of credits must be more than zero.";
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
$cred_collection = Credit::withTrashed()->whereIn('id', array_column($this->input['credits'], 'credit_id'))->get();
|
||||
|
||||
foreach ($this->input['credits'] as $credit) {
|
||||
$unique_array[] = $credit['credit_id'];
|
||||
|
||||
$cred = Credit::find($this->decodePrimaryKey($credit['credit_id']));
|
||||
// $cred = Credit::find($this->decodePrimaryKey($credit['credit_id']));
|
||||
$cred = $cred_collection->firstWhere('id', $credit['credit_id']);
|
||||
|
||||
if (! $cred) {
|
||||
$this->error_msg = ctrans('texts.credit_not_found');
|
||||
|
@ -51,6 +51,9 @@ class ValidInvoicesRules implements Rule
|
||||
|
||||
$unique_array = [];
|
||||
|
||||
/////
|
||||
$inv_collection = Invoice::withTrashed()->whereIn('id', array_column($this->input['invoices'], 'invoice_id'))->get();
|
||||
|
||||
//todo optimize this into a single query
|
||||
foreach ($this->input['invoices'] as $invoice) {
|
||||
$unique_array[] = $invoice['invoice_id'];
|
||||
@ -61,7 +64,10 @@ class ValidInvoicesRules implements Rule
|
||||
return false;
|
||||
}
|
||||
|
||||
$inv = Invoice::withTrashed()->whereId($invoice['invoice_id'])->first();
|
||||
/////
|
||||
$inv = $inv_collection->firstWhere('id', $invoice['invoice_id']);
|
||||
|
||||
// $inv = Invoice::withTrashed()->whereId($invoice['invoice_id'])->first();
|
||||
|
||||
if (! $inv) {
|
||||
$this->error_msg = ctrans('texts.invoice_not_found');
|
||||
|
@ -22,6 +22,13 @@ class ValidCreditsPresentRule implements Rule
|
||||
{
|
||||
use MakesHash;
|
||||
|
||||
private $input;
|
||||
|
||||
public function __construct($input)
|
||||
{
|
||||
$this->input = $input;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $attribute
|
||||
* @param mixed $value
|
||||
@ -44,11 +51,10 @@ class ValidCreditsPresentRule implements Rule
|
||||
{
|
||||
//todo need to ensure the clients credits are here not random ones!
|
||||
|
||||
if (request()->input('credits') && is_array(request()->input('credits')) && count(request()->input('credits')) > 0) {
|
||||
$credit_collection = Credit::whereIn('id', $this->transformKeys(array_column(request()->input('credits'), 'credit_id')))
|
||||
->count();
|
||||
if (array_key_exists('credits', $this->input) && is_array($this->input['credits']) && count($this->input['credits']) > 0) {
|
||||
$credit_collection = Credit::whereIn('id', array_column($this->input['credits'], 'credit_id'))->count();
|
||||
|
||||
return $credit_collection == count(request()->input('credits'));
|
||||
return $credit_collection == count($this->input['credits']);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -33,6 +33,15 @@ class VendorMap
|
||||
14 => 'vendor.state',
|
||||
15 => 'vendor.postal_code',
|
||||
16 => 'vendor.country_id',
|
||||
17 => 'contact.first_name',
|
||||
18 => 'contact.last_name',
|
||||
19 => 'contact.email',
|
||||
20 => 'contact.phone',
|
||||
21 => 'contact.custom_value1',
|
||||
22 => 'contact.custom_value2',
|
||||
23 => 'contact.custom_value3',
|
||||
24 => 'contact.custom_value4',
|
||||
|
||||
];
|
||||
}
|
||||
|
||||
@ -56,6 +65,14 @@ class VendorMap
|
||||
14 => 'texts.state',
|
||||
15 => 'texts.postal_code',
|
||||
16 => 'texts.country',
|
||||
17 => 'texts.first_name',
|
||||
18 => 'texts.last_name',
|
||||
19 => 'texts.email',
|
||||
20 => 'texts.phone',
|
||||
21 => 'texts.custom_value',
|
||||
22 => 'texts.custom_value',
|
||||
23 => 'texts.custom_value',
|
||||
24 => 'texts.custom_value',
|
||||
];
|
||||
}
|
||||
}
|
||||
|
@ -16,12 +16,14 @@ use App\Factory\ExpenseFactory;
|
||||
use App\Factory\InvoiceFactory;
|
||||
use App\Factory\PaymentFactory;
|
||||
use App\Factory\ProductFactory;
|
||||
use App\Factory\QuoteFactory;
|
||||
use App\Factory\VendorFactory;
|
||||
use App\Http\Requests\Client\StoreClientRequest;
|
||||
use App\Http\Requests\Expense\StoreExpenseRequest;
|
||||
use App\Http\Requests\Invoice\StoreInvoiceRequest;
|
||||
use App\Http\Requests\Payment\StorePaymentRequest;
|
||||
use App\Http\Requests\Product\StoreProductRequest;
|
||||
use App\Http\Requests\Quote\StoreQuoteRequest;
|
||||
use App\Http\Requests\Vendor\StoreVendorRequest;
|
||||
use App\Import\ImportException;
|
||||
use App\Import\Providers\BaseImport;
|
||||
@ -31,12 +33,14 @@ use App\Import\Transformer\Csv\ExpenseTransformer;
|
||||
use App\Import\Transformer\Csv\InvoiceTransformer;
|
||||
use App\Import\Transformer\Csv\PaymentTransformer;
|
||||
use App\Import\Transformer\Csv\ProductTransformer;
|
||||
use App\Import\Transformer\Csv\QuoteTransformer;
|
||||
use App\Import\Transformer\Csv\VendorTransformer;
|
||||
use App\Repositories\ClientRepository;
|
||||
use App\Repositories\ExpenseRepository;
|
||||
use App\Repositories\InvoiceRepository;
|
||||
use App\Repositories\PaymentRepository;
|
||||
use App\Repositories\ProductRepository;
|
||||
use App\Repositories\QuoteRepository;
|
||||
use App\Repositories\VendorRepository;
|
||||
use Illuminate\Support\Facades\Validator;
|
||||
use Symfony\Component\HttpFoundation\ParameterBag;
|
||||
@ -55,6 +59,7 @@ class Csv extends BaseImport implements ImportInterface
|
||||
'payment',
|
||||
'vendor',
|
||||
'expense',
|
||||
'quote',
|
||||
])
|
||||
) {
|
||||
$this->{$entity}();
|
||||
@ -151,6 +156,35 @@ class Csv extends BaseImport implements ImportInterface
|
||||
$this->entity_count['invoices'] = $invoice_count;
|
||||
}
|
||||
|
||||
public function quote()
|
||||
{
|
||||
$entity_type = 'quote';
|
||||
|
||||
$data = $this->getCsvData($entity_type);
|
||||
|
||||
if (is_array($data)) {
|
||||
$data = $this->preTransformCsv($data, $entity_type);
|
||||
}
|
||||
|
||||
if (empty($data)) {
|
||||
$this->entity_count['quotes'] = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
$this->request_name = StoreQuoteRequest::class;
|
||||
$this->repository_name = QuoteRepository::class;
|
||||
$this->factory_name = QuoteFactory::class;
|
||||
|
||||
$this->repository = app()->make($this->repository_name);
|
||||
$this->repository->import_mode = true;
|
||||
|
||||
$this->transformer = new QuoteTransformer($this->company);
|
||||
|
||||
$quote_count = $this->ingestQuotes($data, 'quote.number');
|
||||
|
||||
$this->entity_count['quotes'] = $quote_count;
|
||||
}
|
||||
|
||||
public function payment()
|
||||
{
|
||||
$entity_type = 'payment';
|
||||
@ -241,10 +275,6 @@ class Csv extends BaseImport implements ImportInterface
|
||||
$this->entity_count['expenses'] = $expense_count;
|
||||
}
|
||||
|
||||
public function quote()
|
||||
{
|
||||
}
|
||||
|
||||
public function task()
|
||||
{
|
||||
}
|
||||
|
@ -19,6 +19,14 @@ use App\Models\Country;
|
||||
use App\Models\ExpenseCategory;
|
||||
use App\Models\PaymentType;
|
||||
use App\Models\User;
|
||||
use App\Models\Expense;
|
||||
use App\Models\Project;
|
||||
use App\Models\Invoice;
|
||||
use App\Models\Quote;
|
||||
use App\Models\Client;
|
||||
use App\Models\TaxRate;
|
||||
use App\Models\Product;
|
||||
use App\Models\Vendor;
|
||||
use App\Utils\Number;
|
||||
use Exception;
|
||||
use Illuminate\Support\Carbon;
|
||||
@ -65,9 +73,9 @@ class BaseTransformer
|
||||
|
||||
public function getClient($client_name, $client_email)
|
||||
{
|
||||
|
||||
if (! empty($client_name)) {
|
||||
$client_id_search = $this->company
|
||||
->clients()
|
||||
$client_id_search = Client::where('company_id', $this->company->id)
|
||||
->where('is_deleted', false)
|
||||
->where('id_number', $client_name);
|
||||
|
||||
@ -75,10 +83,11 @@ class BaseTransformer
|
||||
return $client_id_search->first()->id;
|
||||
}
|
||||
|
||||
$client_name_search = $this->company
|
||||
->clients()
|
||||
$client_name_search = Client::where('company_id', $this->company->id)
|
||||
->where('is_deleted', false)
|
||||
->where('name', $client_name);
|
||||
->whereRaw("LOWER(REPLACE(`name`, ' ' ,'')) = ?", [
|
||||
strtolower(str_replace(' ', '', $client_name)),
|
||||
]);
|
||||
|
||||
if ($client_name_search->count() >= 1) {
|
||||
return $client_name_search->first()->id;
|
||||
@ -107,8 +116,7 @@ class BaseTransformer
|
||||
*/
|
||||
public function hasClient($name)
|
||||
{
|
||||
return $this->company
|
||||
->clients()
|
||||
return Client::where('company_id', $this->company->id)
|
||||
->where('is_deleted', false)
|
||||
->whereRaw("LOWER(REPLACE(`name`, ' ' ,'')) = ?", [
|
||||
strtolower(str_replace(' ', '', $name)),
|
||||
@ -123,8 +131,7 @@ class BaseTransformer
|
||||
*/
|
||||
public function hasVendor($name)
|
||||
{
|
||||
return $this->company
|
||||
->vendors()
|
||||
return Vendor::where('company_id', $this->company->id)
|
||||
->where('is_deleted', false)
|
||||
->whereRaw("LOWER(REPLACE(`name`, ' ' ,'')) = ?", [
|
||||
strtolower(str_replace(' ', '', $name)),
|
||||
@ -139,8 +146,7 @@ class BaseTransformer
|
||||
*/
|
||||
public function hasProject($name)
|
||||
{
|
||||
return $this->company
|
||||
->projects()
|
||||
return Project::where('company_id', $this->company->id)
|
||||
->where('is_deleted', false)
|
||||
->whereRaw("LOWER(REPLACE(`name`, ' ' ,'')) = ?", [
|
||||
strtolower(str_replace(' ', '', $name)),
|
||||
@ -155,8 +161,7 @@ class BaseTransformer
|
||||
*/
|
||||
public function hasProduct($key)
|
||||
{
|
||||
return $this->company
|
||||
->products()
|
||||
return Product::where('company_id', $this->company->id)
|
||||
->where('is_deleted', false)
|
||||
->whereRaw("LOWER(REPLACE(`product_key`, ' ' ,'')) = ?", [
|
||||
strtolower(str_replace(' ', '', $key)),
|
||||
@ -188,8 +193,7 @@ class BaseTransformer
|
||||
*/
|
||||
public function getClientId($name)
|
||||
{
|
||||
$client = $this->company
|
||||
->clients()
|
||||
$client = Client::where('company_id', $this->company->id)
|
||||
->where('is_deleted', false)
|
||||
->whereRaw("LOWER(REPLACE(`name`, ' ' ,'')) = ?", [
|
||||
strtolower(str_replace(' ', '', $name)),
|
||||
@ -206,8 +210,7 @@ class BaseTransformer
|
||||
*/
|
||||
public function getProduct($key)
|
||||
{
|
||||
$product = $this->company
|
||||
->products()
|
||||
$product = Product::where('company_id', $this->company->id)
|
||||
->where('is_deleted', false)
|
||||
->whereRaw("LOWER(REPLACE(`product_key`, ' ' ,'')) = ?", [
|
||||
strtolower(str_replace(' ', '', $key)),
|
||||
@ -224,8 +227,7 @@ class BaseTransformer
|
||||
*/
|
||||
public function getContact($email)
|
||||
{
|
||||
$contact = $this->company
|
||||
->client_contacts()
|
||||
$contact = ClientContact::where('company_id', $this->company->id)
|
||||
->whereRaw("LOWER(REPLACE(`email`, ' ' ,'')) = ?", [
|
||||
strtolower(str_replace(' ', '', $email)),
|
||||
])
|
||||
@ -277,8 +279,7 @@ class BaseTransformer
|
||||
{
|
||||
$name = strtolower(trim($name));
|
||||
|
||||
$tax_rate = $this->company
|
||||
->tax_rates()
|
||||
$tax_rate = TaxRate::where('company_id', $this->company->id)
|
||||
->where('is_deleted', false)
|
||||
->whereRaw("LOWER(REPLACE(`name`, ' ' ,'')) = ?", [
|
||||
strtolower(str_replace(' ', '', $name)),
|
||||
@ -297,8 +298,7 @@ class BaseTransformer
|
||||
{
|
||||
$name = strtolower(trim($name));
|
||||
|
||||
$tax_rate = $this->company
|
||||
->tax_rates()
|
||||
$tax_rate = TaxRate::where('company_id', $this->company->id)
|
||||
->where('is_deleted', false)
|
||||
->whereRaw("LOWER(REPLACE(`name`, ' ' ,'')) = ?", [
|
||||
strtolower(str_replace(' ', '', $name)),
|
||||
@ -347,8 +347,7 @@ class BaseTransformer
|
||||
*/
|
||||
public function getInvoiceId($invoice_number)
|
||||
{
|
||||
$invoice = $this->company
|
||||
->invoices()
|
||||
$invoice = Invoice::where('company_id', $this->company->id)
|
||||
->where('is_deleted', false)
|
||||
->whereRaw("LOWER(REPLACE(`number`, ' ' ,'')) = ?", [
|
||||
strtolower(str_replace(' ', '', $invoice_number)),
|
||||
@ -365,8 +364,7 @@ class BaseTransformer
|
||||
*/
|
||||
public function hasInvoice($invoice_number)
|
||||
{
|
||||
return $this->company
|
||||
->invoices()
|
||||
return Invoice::where('company_id', $this->company->id)
|
||||
->where('is_deleted', false)
|
||||
->whereRaw("LOWER(REPLACE(`number`, ' ' ,'')) = ?", [
|
||||
strtolower(str_replace(' ', '', $invoice_number)),
|
||||
@ -379,8 +377,7 @@ class BaseTransformer
|
||||
*/
|
||||
public function hasExpense($expense_number)
|
||||
{
|
||||
return $this->company
|
||||
->expenses()
|
||||
return Expense::where('company_id', $this->company->id)
|
||||
->where('is_deleted', false)
|
||||
->whereRaw("LOWER(REPLACE(`number`, ' ' ,'')) = ?", [
|
||||
strtolower(str_replace(' ', '', $expense_number)),
|
||||
@ -395,8 +392,7 @@ class BaseTransformer
|
||||
*/
|
||||
public function hasQuote($quote_number)
|
||||
{
|
||||
return $this->company
|
||||
->quotes()
|
||||
return Quote::where('company_id', $this->company->id)
|
||||
->where('is_deleted', false)
|
||||
->whereRaw("LOWER(REPLACE(`number`, ' ' ,'')) = ?", [
|
||||
strtolower(str_replace(' ', '', $quote_number)),
|
||||
@ -411,8 +407,7 @@ class BaseTransformer
|
||||
*/
|
||||
public function getInvoiceClientId($invoice_number)
|
||||
{
|
||||
$invoice = $this->company
|
||||
->invoices()
|
||||
$invoice = Invoice::where('company_id', $this->company->id)
|
||||
->where('is_deleted', false)
|
||||
->whereRaw("LOWER(REPLACE(`number`, ' ' ,'')) = ?", [
|
||||
strtolower(str_replace(' ', '', $invoice_number)),
|
||||
@ -429,8 +424,7 @@ class BaseTransformer
|
||||
*/
|
||||
public function getVendorId($name)
|
||||
{
|
||||
$vendor = $this->company
|
||||
->vendors()
|
||||
$vendor = Vendor::where('company_id', $this->company->id)
|
||||
->where('is_deleted', false)
|
||||
->whereRaw("LOWER(REPLACE(`name`, ' ' ,'')) = ?", [
|
||||
strtolower(str_replace(' ', '', $name)),
|
||||
@ -466,8 +460,7 @@ class BaseTransformer
|
||||
*/
|
||||
public function getExpenseCategoryId($name)
|
||||
{
|
||||
$ec = $this->company
|
||||
->expense_categories()
|
||||
$ec = ExpenseCategory::where('company_id', $this->company->id)
|
||||
->where('is_deleted', false)
|
||||
->whereRaw("LOWER(REPLACE(`name`, ' ' ,'')) = ?", [
|
||||
strtolower(str_replace(' ', '', $name)),
|
||||
@ -503,8 +496,7 @@ class BaseTransformer
|
||||
*/
|
||||
public function getProjectId($name, $clientId = null)
|
||||
{
|
||||
$project = $this->company
|
||||
->projects()
|
||||
$project = Project::where('company_id', $this->company->id)
|
||||
->where('is_deleted', false)
|
||||
->whereRaw("LOWER(REPLACE(`name`, ' ' ,'')) = ?", [
|
||||
strtolower(str_replace(' ', '', $name)),
|
||||
|
@ -52,15 +52,42 @@ class VendorTransformer extends BaseTransformer
|
||||
'custom_value2' => $this->getString($data, 'vendor.custom_value2'),
|
||||
'custom_value3' => $this->getString($data, 'vendor.custom_value3'),
|
||||
'custom_value4' => $this->getString($data, 'vendor.custom_value4'),
|
||||
'vendor_contacts' => [
|
||||
// 'vendor_contacts' => [
|
||||
// [
|
||||
// 'first_name' => $this->getString(
|
||||
// $data,
|
||||
// 'vendor.first_name'
|
||||
// ),
|
||||
// 'last_name' => $this->getString($data, 'vendor.last_name'),
|
||||
// 'email' => $this->getString($data, 'vendor.email'),
|
||||
// 'phone' => $this->getString($data, 'vendor.phone'),
|
||||
// ],
|
||||
// ],
|
||||
'contacts' => [
|
||||
[
|
||||
'first_name' => $this->getString(
|
||||
$data,
|
||||
'vendor.first_name'
|
||||
'contact.first_name'
|
||||
),
|
||||
'last_name' => $this->getString($data, 'contact.last_name'),
|
||||
'email' => $this->getString($data, 'contact.email'),
|
||||
'phone' => $this->getString($data, 'contact.phone'),
|
||||
'custom_value1' => $this->getString(
|
||||
$data,
|
||||
'contact.custom_value1'
|
||||
),
|
||||
'custom_value2' => $this->getString(
|
||||
$data,
|
||||
'contact.custom_value2'
|
||||
),
|
||||
'custom_value3' => $this->getString(
|
||||
$data,
|
||||
'contact.custom_value3'
|
||||
),
|
||||
'custom_value4' => $this->getString(
|
||||
$data,
|
||||
'contact.custom_value4'
|
||||
),
|
||||
'last_name' => $this->getString($data, 'vendor.last_name'),
|
||||
'email' => $this->getString($data, 'vendor.email'),
|
||||
'phone' => $this->getString($data, 'vendor.phone'),
|
||||
],
|
||||
],
|
||||
'country_id' => isset($data['vendor.country_id'])
|
||||
|
@ -38,13 +38,15 @@ class ClientTransformer extends BaseTransformer
|
||||
$settings->payment_terms = $data['Payment Terms'];
|
||||
}
|
||||
|
||||
$client_id_proxy = array_key_exists('Customer ID', $data) ? 'Customer ID' : 'Primary Contact ID';
|
||||
|
||||
return [
|
||||
'company_id' => $this->company->id,
|
||||
'name' => $this->getString($data, 'Company Name'),
|
||||
'name' => $this->getString($data, 'Display Name'),
|
||||
'phone' => $this->getString($data, 'Phone'),
|
||||
'private_notes' => $this->getString($data, 'Notes'),
|
||||
'website' => $this->getString($data, 'Website'),
|
||||
'id_number' => $this->getString($data, 'Customer ID'),
|
||||
'id_number' => $this->getString($data, $client_id_proxy),
|
||||
'address1' => $this->getString($data, 'Billing Address'),
|
||||
'address2' => $this->getString($data, 'Billing Street2'),
|
||||
'city' => $this->getString($data, 'Billing City'),
|
||||
|
@ -40,7 +40,7 @@ class InvoiceTransformer extends BaseTransformer
|
||||
|
||||
$transformed = [
|
||||
'company_id' => $this->company->id,
|
||||
'client_id' => $this->getClient($this->getString($invoice_data, 'Customer ID'), null),
|
||||
'client_id' => $this->getClient($this->getString($invoice_data, 'Customer ID'), $this->getString($invoice_data, 'Primary Contact EmailID')),
|
||||
'number' => $this->getString($invoice_data, 'Invoice Number'),
|
||||
'date' => isset($invoice_data['Invoice Date']) ? date('Y-m-d', strtotime($invoice_data['Invoice Date'])) : null,
|
||||
'due_date' => isset($invoice_data['Due Date']) ? date('Y-m-d', strtotime($invoice_data['Due Date'])) : null,
|
||||
@ -51,14 +51,19 @@ class InvoiceTransformer extends BaseTransformer
|
||||
'balance' => $this->getFloat($invoice_data, 'Balance'),
|
||||
'status_id' => $invoiceStatusMap[$status =
|
||||
strtolower($this->getString($invoice_data, 'Invoice Status'))] ?? Invoice::STATUS_SENT,
|
||||
'terms' => $this->getString($invoice_data, 'Terms & Conditions'),
|
||||
|
||||
// 'viewed' => $status === 'viewed',
|
||||
];
|
||||
|
||||
$line_items = [];
|
||||
foreach ($line_items_data as $record) {
|
||||
|
||||
$item_notes_key = array_key_exists('Item Description', $record) ? 'Item Description' : 'Item Desc';
|
||||
|
||||
$line_items[] = [
|
||||
'product_key' => $this->getString($record, 'Item Name'),
|
||||
'notes' => $this->getString($record, 'Item Description'),
|
||||
'notes' => $this->getString($record, $item_notes_key),
|
||||
'cost' => round($this->getFloat($record, 'Item Price'), 2),
|
||||
'quantity' => $this->getFloat($record, 'Quantity'),
|
||||
'discount' => $this->getString($record, 'Discount Amount'),
|
||||
|
@ -152,6 +152,12 @@ class BaseTransformer
|
||||
return Number::parseFloat($number);
|
||||
}
|
||||
|
||||
public function getFloatWithSamePrecision($data, $field)
|
||||
{
|
||||
$precision = (int) strpos(strrev($data[$field]), ".");
|
||||
|
||||
return round($data[$field], $precision);
|
||||
}
|
||||
/**
|
||||
* @param $name
|
||||
*
|
||||
|
@ -39,11 +39,11 @@ class InvoiceTransformer extends BaseTransformer
|
||||
'is_sent' => $this->getString($data, 'invoice.is_sent'),
|
||||
'private_notes' => $this->getString($data, 'invoice.private_notes'),
|
||||
'tax_name1' => $this->getString($data, 'invoice.tax_name1'),
|
||||
'tax_rate1' => $this->getFloat($data, 'invoice.tax_rate1'),
|
||||
'tax_rate1' => $this->getFloatWithSamePrecision($data, 'invoice.tax_rate1'),
|
||||
'tax_name2' => $this->getString($data, 'invoice.tax_name2'),
|
||||
'tax_rate2' => $this->getFloat($data, 'invoice.tax_rate2'),
|
||||
'tax_rate2' => $this->getFloatWithSamePrecision($data, 'invoice.tax_rate2'),
|
||||
'tax_name3' => $this->getString($data, 'invoice.tax_name3'),
|
||||
'tax_rate3' => $this->getFloat($data, 'invoice.tax_rate3'),
|
||||
'tax_rate3' => $this->getFloatWithSamePrecision($data, 'invoice.tax_rate3'),
|
||||
'custom_value1' => $this->getString($data, 'invoice.custom_value1'),
|
||||
'custom_value2' => $this->getString($data, 'invoice.custom_value2'),
|
||||
'custom_value3' => $this->getString($data, 'invoice.custom_value3'),
|
||||
|
@ -85,6 +85,11 @@ class CreateAccount
|
||||
$sp794f3f->hosted_client_count = config('ninja.quotas.free.clients');
|
||||
$sp794f3f->hosted_company_count = config('ninja.quotas.free.max_companies');
|
||||
$sp794f3f->account_sms_verified = true;
|
||||
|
||||
if(in_array($this->getDomain($this->request['email']), ['gmail.com', 'hotmail.com', 'outlook.com', 'yahoo.com'])){
|
||||
$sp794f3f->account_sms_verified = false;
|
||||
}
|
||||
|
||||
// $sp794f3f->trial_started = now();
|
||||
// $sp794f3f->trial_plan = 'pro';
|
||||
}
|
||||
@ -155,4 +160,19 @@ class CreateAccount
|
||||
|
||||
return $sp794f3f;
|
||||
}
|
||||
|
||||
private function getDomain($email)
|
||||
{
|
||||
if( filter_var( $email, FILTER_VALIDATE_EMAIL ) ) {
|
||||
// split on @ and return last value of array (the domain)
|
||||
$domain = explode('@', $email);
|
||||
|
||||
$domain_name = end($domain);
|
||||
|
||||
return $domain_name;
|
||||
}
|
||||
|
||||
return 'gmail.com';
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -288,7 +288,7 @@ class CompanyImport implements ShouldQueue
|
||||
$nmo->company = $_company;
|
||||
$nmo->settings = $_company->settings;
|
||||
$nmo->to_user = $_company->owner();
|
||||
NinjaMailerJob::dispatchNow($nmo);
|
||||
NinjaMailerJob::dispatch($nmo);
|
||||
|
||||
}
|
||||
catch(\Exception $e){
|
||||
@ -1644,7 +1644,7 @@ class CompanyImport implements ShouldQueue
|
||||
$nmo->company = $this->company;
|
||||
$nmo->settings = $this->company->settings;
|
||||
$nmo->to_user = $this->company->owner();
|
||||
NinjaMailerJob::dispatchNow($nmo);
|
||||
NinjaMailerJob::dispatch($nmo);
|
||||
|
||||
}
|
||||
}
|
@ -64,7 +64,8 @@ class CreateCompany
|
||||
$company->custom_fields = new \stdClass;
|
||||
$company->default_password_timeout = 1800000;
|
||||
$company->client_registration_fields = ClientRegistrationFields::generate();
|
||||
$company->markdown_email_enabled = false;
|
||||
$company->markdown_email_enabled = true;
|
||||
$company->markdown_enabled = false;
|
||||
|
||||
if (Ninja::isHosted()) {
|
||||
$company->subdomain = MultiDB::randomSubdomainGenerator();
|
||||
|
@ -85,6 +85,13 @@ class ApplyCreditPayment implements ShouldQueue
|
||||
->save();
|
||||
}
|
||||
|
||||
//22-08-2022
|
||||
$this->credit
|
||||
->client
|
||||
->service()
|
||||
->adjustCreditBalance($this->amount * -1)
|
||||
->save();
|
||||
|
||||
/* Update Payment Applied Amount*/
|
||||
$this->payment->save();
|
||||
}
|
||||
|
@ -44,12 +44,12 @@ class RecurringInvoicesCron
|
||||
nlog('Sending recurring invoices '.$start);
|
||||
|
||||
if (! config('ninja.db.multi_db_enabled')) {
|
||||
$recurring_invoices = RecurringInvoice::where('next_send_date', '<=', now()->toDateTimeString())
|
||||
$recurring_invoices = RecurringInvoice::where('status_id', RecurringInvoice::STATUS_ACTIVE)
|
||||
->where('is_deleted', false)
|
||||
->where('remaining_cycles', '!=', '0')
|
||||
->whereNotNull('next_send_date')
|
||||
->whereNull('deleted_at')
|
||||
->where('is_deleted', false)
|
||||
->where('status_id', RecurringInvoice::STATUS_ACTIVE)
|
||||
->where('remaining_cycles', '!=', '0')
|
||||
->where('next_send_date', '<=', now()->toDateTimeString())
|
||||
->whereHas('client', function ($query) {
|
||||
$query->where('is_deleted', 0)
|
||||
->where('deleted_at', null);
|
||||
@ -84,12 +84,12 @@ class RecurringInvoicesCron
|
||||
foreach (MultiDB::$dbs as $db) {
|
||||
MultiDB::setDB($db);
|
||||
|
||||
$recurring_invoices = RecurringInvoice::where('next_send_date', '<=', now()->toDateTimeString())
|
||||
->whereNotNull('next_send_date')
|
||||
->whereNull('deleted_at')
|
||||
$recurring_invoices = RecurringInvoice::where('status_id', RecurringInvoice::STATUS_ACTIVE)
|
||||
->where('is_deleted', false)
|
||||
->where('status_id', RecurringInvoice::STATUS_ACTIVE)
|
||||
->where('remaining_cycles', '!=', '0')
|
||||
->whereNull('deleted_at')
|
||||
->whereNotNull('next_send_date')
|
||||
->where('next_send_date', '<=', now()->toDateTimeString())
|
||||
->whereHas('client', function ($query) {
|
||||
$query->where('is_deleted', 0)
|
||||
->where('deleted_at', null);
|
||||
|
@ -74,7 +74,7 @@ class CSVIngest implements ShouldQueue
|
||||
|
||||
$engine = $this->bootEngine();
|
||||
|
||||
foreach (['client', 'product', 'invoice', 'payment', 'vendor', 'expense'] as $entity) {
|
||||
foreach (['client', 'product', 'invoice', 'payment', 'vendor', 'expense', 'quote'] as $entity) {
|
||||
$engine->import($entity);
|
||||
}
|
||||
|
||||
|
@ -80,9 +80,9 @@ class AdjustProductInventory implements ShouldQueue
|
||||
$p->in_stock_quantity -= $item->quantity;
|
||||
$p->saveQuietly();
|
||||
|
||||
if ($p->stock_notification_threshold && $p->in_stock_quantity <= $p->stock_notification_threshold) {
|
||||
if ($this->company->stock_notification && $p->stock_notification && $p->stock_notification_threshold && $p->in_stock_quantity <= $p->stock_notification_threshold) {
|
||||
$this->notifyStockLevels($p, 'product');
|
||||
} elseif ($this->company->stock_notification_threshold && $p->in_stock_quantity <= $this->company->stock_notification_threshold) {
|
||||
} elseif ($this->company->stock_notification && $p->stock_notification && $this->company->inventory_notification_threshold && $p->in_stock_quantity <= $this->company->inventory_notification_threshold) {
|
||||
$this->notifyStocklevels($p, 'company');
|
||||
}
|
||||
}
|
||||
|
@ -102,6 +102,17 @@ class NinjaMailerJob implements ShouldQueue
|
||||
|
||||
$this->nmo->mailable->tag($this->company->company_key);
|
||||
|
||||
if($this->nmo->invitation)
|
||||
{
|
||||
|
||||
$this->nmo
|
||||
->mailable
|
||||
->withSymfonyMessage(function ($message) {
|
||||
$message->getHeaders()->addTextHeader('x-invitation', $this->nmo->invitation->key);
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
//send email
|
||||
try {
|
||||
nlog("trying to send to {$this->nmo->to_user->email} ". now()->toDateTimeString());
|
||||
@ -313,6 +324,10 @@ class NinjaMailerJob implements ShouldQueue
|
||||
if($this->company->is_disabled && !$this->override)
|
||||
return true;
|
||||
|
||||
/* To handle spam users we drop all emails from flagged accounts */
|
||||
if(Ninja::isHosted() && $this->company->account && $this->company->account->is_flagged)
|
||||
return true;
|
||||
|
||||
/* On the hosted platform we set default contacts a @example.com email address - we shouldn't send emails to these types of addresses */
|
||||
if(Ninja::isHosted() && $this->nmo->to_user && strpos($this->nmo->to_user->email, '@example.com') !== false)
|
||||
return true;
|
||||
@ -325,10 +340,6 @@ class NinjaMailerJob implements ShouldQueue
|
||||
if(Ninja::isHosted() && $this->company->account && $this->company->account->emailQuotaExceeded())
|
||||
return true;
|
||||
|
||||
/* To handle spam users we drop all emails from flagged accounts */
|
||||
if(Ninja::isHosted() && $this->company->account && $this->company->account->is_flagged)
|
||||
return true;
|
||||
|
||||
/* If the account is verified, we allow emails to flow */
|
||||
if(Ninja::isHosted() && $this->company->account && $this->company->account->is_verified_account) {
|
||||
|
||||
@ -343,14 +354,19 @@ class NinjaMailerJob implements ShouldQueue
|
||||
if(!str_contains($this->nmo->to_user->email, "@"))
|
||||
return true;
|
||||
|
||||
/* On the hosted platform if the user has not verified their account we fail here - but still check what they are trying to send! */
|
||||
if(Ninja::isHosted() && $this->company->account && !$this->company->account->account_sms_verified){
|
||||
|
||||
if(class_exists(\Modules\Admin\Jobs\Account\EmailQuality::class))
|
||||
return (new \Modules\Admin\Jobs\Account\EmailQuality($this->nmo, $this->company))->run();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* On the hosted platform we actively scan all outbound emails to ensure outbound email quality remains high */
|
||||
if(class_exists(\Modules\Admin\Jobs\Account\EmailQuality::class))
|
||||
return (new \Modules\Admin\Jobs\Account\EmailQuality($this->nmo, $this->company))->run();
|
||||
|
||||
/* On the hosted platform if the user has not verified their account we fail here */
|
||||
if(Ninja::isHosted() && $this->company->account && !$this->company->account->account_sms_verified)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -52,8 +52,6 @@ class CheckCompanyData implements ShouldQueue
|
||||
|
||||
/**
|
||||
* Execute the job.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
@ -110,7 +108,7 @@ class CheckCompanyData implements ShouldQueue
|
||||
if ($ledger && number_format($invoice_balance, 4) != number_format($client->balance, 4)) {
|
||||
$wrong_balances++;
|
||||
|
||||
$this->company_data[] = "# {$client->id} ".$client->present()->name.' - '.$client->number." - Balance Failure - Invoice Balances = {$invoice_balance} Client Balance = {$client->balance} Ledger Balance = {$ledger->balance} ";
|
||||
$this->company_data[] = "# {$client->id} ".$client->present()->name().' - '.$client->number." - Balance Failure - Invoice Balances = {$invoice_balance} Client Balance = {$client->balance} Ledger Balance = {$ledger->balance} ";
|
||||
|
||||
$this->is_valid = false;
|
||||
}
|
||||
@ -136,7 +134,7 @@ class CheckCompanyData implements ShouldQueue
|
||||
if ((string) $total_paid != (string) ($invoice->amount - $invoice->balance - $total_credit)) {
|
||||
$wrong_balances++;
|
||||
|
||||
$this->company_data[] = $client->present()->name.' - '.$client->id." - Total Amount = {$total_amount} != Calculated Total = {$calculated_paid_amount} - Total Refund = {$total_refund} Total credit = {$total_credit}";
|
||||
$this->company_data[] = $client->present()->name().' - '.$client->id." - Total Amount = {$total_amount} != Calculated Total = {$calculated_paid_amount} - Total Refund = {$total_refund} Total credit = {$total_credit}";
|
||||
|
||||
$this->is_valid = false;
|
||||
}
|
||||
@ -175,7 +173,7 @@ class CheckCompanyData implements ShouldQueue
|
||||
if (round($total_invoice_payments, 2) != round($client->paid_to_date, 2)) {
|
||||
$wrong_paid_to_dates++;
|
||||
|
||||
$this->company_data[] = $client->present()->name.'id = # '.$client->id." - Paid to date does not match Client Paid To Date = {$client->paid_to_date} - Invoice Payments = {$total_invoice_payments}";
|
||||
$this->company_data[] = $client->present()->name().'id = # '.$client->id." - Paid to date does not match Client Paid To Date = {$client->paid_to_date} - Invoice Payments = {$total_invoice_payments}";
|
||||
|
||||
$this->is_valid = false;
|
||||
}
|
||||
@ -204,7 +202,7 @@ class CheckCompanyData implements ShouldQueue
|
||||
if ($ledger && (string) $invoice_balance != (string) $client->balance) {
|
||||
$wrong_paid_to_dates++;
|
||||
|
||||
$this->company_data[] = $client->present()->name.' - '.$client->id." - calculated client balances do not match {$invoice_balance} - ".rtrim($client->balance, '0').'';
|
||||
$this->company_data[] = $client->present()->name().' - '.$client->id." - calculated client balances do not match {$invoice_balance} - ".rtrim($client->balance, '0').'';
|
||||
|
||||
$this->is_valid = false;
|
||||
}
|
||||
|
@ -12,6 +12,7 @@
|
||||
namespace App\Jobs\Ninja;
|
||||
|
||||
use App\Libraries\MultiDB;
|
||||
use App\Models\Client;
|
||||
use App\Models\Company;
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
@ -54,6 +55,8 @@ class CompanySizeCheck implements ShouldQueue
|
||||
|
||||
private function check()
|
||||
{
|
||||
nlog("Checking all company sizes");
|
||||
|
||||
Company::where('is_large', false)->withCount(['invoices', 'clients', 'products'])->cursor()->each(function ($company) {
|
||||
if ($company->invoices_count > 500 || $company->products_count > 500 || $company->clients_count > 500) {
|
||||
nlog("Marking company {$company->id} as large");
|
||||
@ -61,5 +64,17 @@ class CompanySizeCheck implements ShouldQueue
|
||||
$company->account->companies()->update(['is_large' => true]);
|
||||
}
|
||||
});
|
||||
|
||||
nlog("updating all client credit balances");
|
||||
|
||||
Client::where('updated_at', '>', now()->subDay())
|
||||
->cursor()
|
||||
->each(function ($client){
|
||||
|
||||
$client->credit_balance = $client->service()->getCreditBalance();
|
||||
$client->save();
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -26,6 +26,7 @@ use App\Models\Company;
|
||||
use App\Models\CreditInvitation;
|
||||
use App\Models\InvoiceInvitation;
|
||||
use App\Models\Payment;
|
||||
use App\Models\PurchaseOrderInvitation;
|
||||
use App\Models\QuoteInvitation;
|
||||
use App\Models\RecurringInvoiceInvitation;
|
||||
use App\Models\SystemLog;
|
||||
@ -283,6 +284,8 @@ class ProcessPostmarkWebhook implements ShouldQueue
|
||||
return $invitation;
|
||||
elseif($invitation = CreditInvitation::where('message_id', $message_id)->first())
|
||||
return $invitation;
|
||||
elseif($invitation = PurchaseOrderInvitation::where('message_id', $message_id)->first())
|
||||
return $invitation;
|
||||
else
|
||||
return $invitation;
|
||||
}
|
||||
|
@ -252,7 +252,7 @@ class Import implements ShouldQueue
|
||||
$this->setInitialCompanyLedgerBalances();
|
||||
|
||||
// $this->fixClientBalances();
|
||||
$check_data = CheckCompanyData::dispatchNow($this->company, md5(time()));
|
||||
$check_data = (new CheckCompanyData($this->company, md5(time())))->handle();
|
||||
|
||||
// if(Ninja::isHosted() && array_key_exists('ninja_tokens', $data))
|
||||
$this->processNinjaTokens($data['ninja_tokens']);
|
||||
@ -591,7 +591,7 @@ class Import implements ShouldQueue
|
||||
|
||||
$user_agent = array_key_exists('token_name', $resource) ?: request()->server('HTTP_USER_AGENT');
|
||||
|
||||
CreateCompanyToken::dispatchNow($this->company, $user, $user_agent);
|
||||
(new CreateCompanyToken($this->company, $user, $user_agent))->handle();
|
||||
|
||||
$key = "users_{$resource['id']}";
|
||||
|
||||
@ -1899,7 +1899,7 @@ class Import implements ShouldQueue
|
||||
if(Ninja::isHosted()){
|
||||
|
||||
try{
|
||||
\Modules\Admin\Jobs\Account\NinjaUser::dispatchNow($data, $this->company);
|
||||
\Modules\Admin\Jobs\Account\NinjaUser::dispatch($data, $this->company);
|
||||
}
|
||||
catch(\Exception $e){
|
||||
nlog($e->getMessage());
|
||||
|
@ -14,8 +14,10 @@ namespace App\Jobs\Util;
|
||||
use App\DataMapper\InvoiceItem;
|
||||
use App\Events\Invoice\InvoiceWasEmailed;
|
||||
use App\Jobs\Entity\EmailEntity;
|
||||
use App\Jobs\Ninja\TransactionLog;
|
||||
use App\Libraries\MultiDB;
|
||||
use App\Models\Invoice;
|
||||
use App\Models\TransactionEvent;
|
||||
use App\Utils\Ninja;
|
||||
use App\Utils\Traits\MakesDates;
|
||||
use App\Utils\Traits\MakesReminders;
|
||||
@ -60,11 +62,11 @@ class ReminderJob implements ShouldQueue
|
||||
{
|
||||
nlog('Sending invoice reminders '.now()->format('Y-m-d h:i:s'));
|
||||
|
||||
Invoice::where('next_send_date', '<=', now()->toDateTimeString())
|
||||
->whereNull('deleted_at')
|
||||
->where('is_deleted', 0)
|
||||
Invoice::where('is_deleted', 0)
|
||||
->whereIn('status_id', [Invoice::STATUS_SENT, Invoice::STATUS_PARTIAL])
|
||||
->whereNull('deleted_at')
|
||||
->where('balance', '>', 0)
|
||||
->where('next_send_date', '<=', now()->toDateTimeString())
|
||||
->whereHas('client', function ($query) {
|
||||
$query->where('is_deleted', 0)
|
||||
->where('deleted_at', null);
|
||||
@ -75,6 +77,7 @@ class ReminderJob implements ShouldQueue
|
||||
->with('invitations')->cursor()->each(function ($invoice) {
|
||||
if ($invoice->isPayable()) {
|
||||
$reminder_template = $invoice->calculateTemplate('invoice');
|
||||
nlog("reminder template = {$reminder_template}");
|
||||
$invoice->service()->touchReminder($reminder_template)->save();
|
||||
$invoice = $this->calcLateFee($invoice, $reminder_template);
|
||||
|
||||
@ -93,6 +96,7 @@ class ReminderJob implements ShouldQueue
|
||||
$invoice->client->getSetting($enabled_reminder) &&
|
||||
$invoice->client->getSetting('send_reminders') &&
|
||||
(Ninja::isSelfHost() || $invoice->company->account->isPaidHostedClient())) {
|
||||
|
||||
$invoice->invitations->each(function ($invitation) use ($invoice, $reminder_template) {
|
||||
EmailEntity::dispatch($invitation, $invitation->company, $reminder_template);
|
||||
nlog("Firing reminder email for invoice {$invoice->number} - {$reminder_template}");
|
||||
@ -199,10 +203,20 @@ class ReminderJob implements ShouldQueue
|
||||
$client = $invoice->client;
|
||||
$client = $client->fresh();
|
||||
|
||||
nlog('adjusting client balance and invoice balance by '.($invoice->balance - $temp_invoice_balance));
|
||||
nlog('adjusting client balance and invoice balance by #'.$invoice->number.' '.($invoice->balance - $temp_invoice_balance));
|
||||
$client->service()->updateBalance($invoice->balance - $temp_invoice_balance)->save();
|
||||
$invoice->ledger()->updateInvoiceBalance($invoice->balance - $temp_invoice_balance, "Late Fee Adjustment for invoice {$invoice->number}");
|
||||
|
||||
$transaction = [
|
||||
'invoice' => $invoice->transaction_event(),
|
||||
'payment' => [],
|
||||
'client' => $client->transaction_event(),
|
||||
'credit' => [],
|
||||
'metadata' => ['setLateFee'],
|
||||
];
|
||||
|
||||
TransactionLog::dispatch(TransactionEvent::CLIENT_STATUS, $transaction, $invoice->company->db);
|
||||
|
||||
return $invoice;
|
||||
}
|
||||
}
|
||||
|
@ -12,9 +12,16 @@
|
||||
namespace App\Listeners\Mail;
|
||||
|
||||
use App\Libraries\MultiDB;
|
||||
use App\Models\CreditInvitation;
|
||||
use App\Models\InvoiceInvitation;
|
||||
use App\Models\PurchaseOrderInvitation;
|
||||
use App\Models\QuoteInvitation;
|
||||
use App\Models\RecurringInvoiceInvitation;
|
||||
use App\Utils\Ninja;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Mail\Events\MessageSent;
|
||||
use Illuminate\Support\Facades\Notification;
|
||||
use Symfony\Component\Mime\MessageConverter;
|
||||
|
||||
class MailSentListener implements ShouldQueue
|
||||
{
|
||||
@ -35,19 +42,55 @@ class MailSentListener implements ShouldQueue
|
||||
*/
|
||||
public function handle(MessageSent $event)
|
||||
{
|
||||
nlog("mail listener");
|
||||
nlog($event);
|
||||
// if (property_exists($event->message, 'invitation') && $event->message->invitation) {
|
||||
// MultiDB::setDb($event->sent->invitation->company->db);
|
||||
if(!Ninja::isHosted())
|
||||
return;
|
||||
|
||||
$message_id = $event->sent->getMessageId();
|
||||
|
||||
// if ($event->message->getHeaders()->get('x-pm-message-id')) {
|
||||
// $postmark_id = $event->sent->getHeaders()->get('x-pm-message-id')->getValue();
|
||||
$message = MessageConverter::toEmail($event->sent->getOriginalMessage());
|
||||
|
||||
if(!$message->getHeaders()->get('x-invitation'))
|
||||
return;
|
||||
|
||||
$invitation_key = $message->getHeaders()->get('x-invitation')->getValue();
|
||||
|
||||
if($message_id && $invitation_key)
|
||||
{
|
||||
|
||||
$invitation = $this->discoverInvitation($invitation_key);
|
||||
|
||||
if(!$invitation)
|
||||
return;
|
||||
|
||||
$invitation->message_id = $message_id;
|
||||
$invitation->save();
|
||||
}
|
||||
|
||||
// // nlog($postmark_id);
|
||||
// $invitation = $event->sent->invitation;
|
||||
// $invitation->message_id = $postmark_id;
|
||||
// $invitation->save();
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
private function discoverInvitation($key)
|
||||
{
|
||||
|
||||
$invitation = false;
|
||||
|
||||
foreach (MultiDB::$dbs as $db)
|
||||
{
|
||||
|
||||
if($invitation = InvoiceInvitation::on($db)->where('key', $key)->first())
|
||||
return $invitation;
|
||||
elseif($invitation = QuoteInvitation::on($db)->where('key', $key)->first())
|
||||
return $invitation;
|
||||
elseif($invitation = RecurringInvoiceInvitation::on($db)->where('key', $key)->first())
|
||||
return $invitation;
|
||||
elseif($invitation = CreditInvitation::on($db)->where('key', $key)->first())
|
||||
return $invitation;
|
||||
elseif($invitation = PurchaseOrderInvitation::on($db)->where('key', $key)->first())
|
||||
return $invitation;
|
||||
|
||||
}
|
||||
|
||||
return $invitation;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -112,7 +112,7 @@ class ClientPaymentFailureObject
|
||||
'invoice' => $this->invoices->first()->number,
|
||||
]
|
||||
),
|
||||
'greeting' => ctrans('texts.email_salutation', ['name' => $this->client->present()->name]),
|
||||
'greeting' => ctrans('texts.email_salutation', ['name' => $this->client->present()->name()]),
|
||||
'content' => ctrans('texts.client_payment_failure_body', ['invoice' => implode(',', $this->invoices->pluck('number')->toArray()), 'amount' => $this->getAmount()]),
|
||||
'signature' => $signature,
|
||||
'logo' => $this->company->present()->logo(),
|
||||
|
@ -222,6 +222,7 @@ class PaymentEmailEngine extends BaseEmailEngine
|
||||
|
||||
$data['$view_link'] = ['value' => '<a class="button" href="'.$this->payment->getLink().'">'.ctrans('texts.view_payment').'</a>', 'label' => ctrans('texts.view_payment')];
|
||||
$data['$view_button'] = &$data['$view_link'];
|
||||
$data['$viewButton'] = &$data['$view_link'];
|
||||
$data['$viewLink'] = &$data['$view_link'];
|
||||
$data['$paymentLink'] = &$data['$view_link'];
|
||||
$data['$portalButton'] = ['value' => "<a href='{$this->payment->getPortalLink()}'>".ctrans('texts.login').'</a>', 'label' =>''];
|
||||
@ -237,6 +238,10 @@ class PaymentEmailEngine extends BaseEmailEngine
|
||||
$data['$invoice.po_number'] = ['value' => $this->formatPoNumber(), 'label' => ctrans('texts.po_number')];
|
||||
$data['$poNumber'] = &$data['$invoice.po_number'];
|
||||
$data['$payment.status'] = ['value' => $this->payment->stringStatus($this->payment->status_id), 'label' => ctrans('texts.payment_status')];
|
||||
$data['$invoices.amount'] = ['value' => $this->formatInvoiceField('amount'), 'label' => ctrans('texts.invoices')];
|
||||
$data['$invoices.balance'] = ['value' => $this->formatInvoiceField('balance'), 'label' => ctrans('texts.invoices')];
|
||||
$data['$invoices.due_date'] = ['value' => $this->formatInvoiceField('due_date'), 'label' => ctrans('texts.invoices')];
|
||||
$data['$invoices.po_number'] = ['value' => $this->formatInvoiceField('po_number'), 'label' => ctrans('texts.invoices')];
|
||||
|
||||
$arrKeysLength = array_map('strlen', array_keys($data));
|
||||
array_multisort($arrKeysLength, SORT_DESC, $data);
|
||||
@ -244,6 +249,22 @@ class PaymentEmailEngine extends BaseEmailEngine
|
||||
return $data;
|
||||
}
|
||||
|
||||
private function formatInvoiceField($field)
|
||||
{
|
||||
$invoice = '';
|
||||
|
||||
foreach ($this->payment->invoices as $invoice) {
|
||||
|
||||
$invoice_field = $invoice->{$field};
|
||||
|
||||
$invoice .= ctrans('texts.invoice_number_short') . "{$invoice->number} {$invoice_field}";
|
||||
|
||||
}
|
||||
|
||||
return $invoice;
|
||||
|
||||
}
|
||||
|
||||
private function formatInvoice()
|
||||
{
|
||||
$invoice = '';
|
||||
@ -282,11 +303,15 @@ class PaymentEmailEngine extends BaseEmailEngine
|
||||
$invoice_list = '<br><br>';
|
||||
|
||||
foreach ($this->payment->invoices as $invoice) {
|
||||
$invoice_list .= ctrans('texts.po_number')." {$invoice->po_number} <br>";
|
||||
|
||||
if(strlen($invoice->po_number) > 1)
|
||||
$invoice_list .= ctrans('texts.po_number')." {$invoice->po_number} <br>";
|
||||
|
||||
$invoice_list .= ctrans('texts.invoice_number_short')." {$invoice->number} <br>";
|
||||
$invoice_list .= ctrans('texts.invoice_amount').' '.Number::formatMoney($invoice->pivot->amount, $this->client).'<br>';
|
||||
$invoice_list .= ctrans('texts.invoice_balance').' '.Number::formatMoney($invoice->fresh()->balance, $this->client).'<br>';
|
||||
$invoice_list .= '-----<br>';
|
||||
|
||||
}
|
||||
|
||||
return $invoice_list;
|
||||
|
@ -70,8 +70,13 @@ class SupportMessageSent extends Mailable
|
||||
$trial = $account->isTrial() ? 'T' : '';
|
||||
$plan = str_replace('_', ' ', $plan);
|
||||
|
||||
$plan_status = '';
|
||||
|
||||
if(Carbon::parse($account->plan_expires)->lt(now()))
|
||||
$plan_status = 'Plan Expired';
|
||||
|
||||
if (Ninja::isHosted()) {
|
||||
$subject = "{$priority}Hosted-{$db}-{$is_large}{$platform}{$migrated}{$trial} :: {$plan} :: ".date('M jS, g:ia');
|
||||
$subject = "{$priority}Hosted-{$db}-{$is_large}{$platform}{$migrated}{$trial} :: {$plan} :: {$plan_status} ".date('M jS, g:ia');
|
||||
} else {
|
||||
$subject = "{$priority}Self Hosted :: {$plan} :: {$is_large}{$platform}{$migrated} :: ".date('M jS, g:ia');
|
||||
}
|
||||
|
@ -33,7 +33,7 @@ class Account extends BaseModel
|
||||
use PresentableTrait;
|
||||
use MakesHash;
|
||||
|
||||
private $free_plan_email_quota = 50;
|
||||
private $free_plan_email_quota = 20;
|
||||
|
||||
private $paid_plan_email_quota = 500;
|
||||
/**
|
||||
@ -395,11 +395,11 @@ class Account extends BaseModel
|
||||
|
||||
if($this->isPaid()){
|
||||
$limit = $this->paid_plan_email_quota;
|
||||
$limit += Carbon::createFromTimestamp($this->created_at)->diffInMonths() * 100;
|
||||
$limit += Carbon::createFromTimestamp($this->created_at)->diffInMonths() * 50;
|
||||
}
|
||||
else{
|
||||
$limit = $this->free_plan_email_quota;
|
||||
$limit += Carbon::createFromTimestamp($this->created_at)->diffInMonths() * 50;
|
||||
$limit += Carbon::createFromTimestamp($this->created_at)->diffInMonths() * 10;
|
||||
}
|
||||
|
||||
return min($limit, 5000);
|
||||
|
@ -266,6 +266,11 @@ class Activity extends StaticModel
|
||||
return $this->belongsTo(Invoice::class)->withTrashed();
|
||||
}
|
||||
|
||||
public function vendor()
|
||||
{
|
||||
return $this->belongsTo(Vendor::class)->withTrashed();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
|
@ -236,6 +236,11 @@ class Client extends BaseModel implements HasLocalePreference
|
||||
return $this->hasMany(Task::class)->withTrashed();
|
||||
}
|
||||
|
||||
public function payments()
|
||||
{
|
||||
return $this->hasMany(Payment::class)->withTrashed();
|
||||
}
|
||||
|
||||
public function recurring_invoices()
|
||||
{
|
||||
return $this->hasMany(RecurringInvoice::class)->withTrashed();
|
||||
@ -370,6 +375,8 @@ class Client extends BaseModel implements HasLocalePreference
|
||||
return $this->settings->{$setting};
|
||||
} elseif (is_bool($this->settings->{$setting})) {
|
||||
return $this->settings->{$setting};
|
||||
} elseif (is_int($this->settings->{$setting})) { //10-08-2022 integer client values are not being passed back! This resolves it.
|
||||
return $this->settings->{$setting};
|
||||
}
|
||||
}
|
||||
|
||||
@ -625,11 +632,6 @@ class Client extends BaseModel implements HasLocalePreference
|
||||
return $defaults;
|
||||
}
|
||||
|
||||
public function payments()
|
||||
{
|
||||
return $this->hasMany(Payment::class)->withTrashed();
|
||||
}
|
||||
|
||||
public function timezone_offset()
|
||||
{
|
||||
$offset = 0;
|
||||
|
@ -120,6 +120,7 @@ class Company extends BaseModel
|
||||
'inventory_notification_threshold',
|
||||
'stock_notification',
|
||||
'enabled_expense_tax_rates',
|
||||
'invoice_task_project',
|
||||
];
|
||||
|
||||
protected $hidden = [
|
||||
@ -405,15 +406,21 @@ class Company extends BaseModel
|
||||
{
|
||||
$languages = Cache::get('languages');
|
||||
|
||||
//build cache and reinit
|
||||
if (! $languages) {
|
||||
$this->buildCache(true);
|
||||
$languages = Cache::get('languages');
|
||||
}
|
||||
|
||||
//if the cache is still dead, get from DB
|
||||
if(!$languages && property_exists($this->settings, 'language_id'))
|
||||
return Language::find($this->settings->language_id);
|
||||
|
||||
return $languages->filter(function ($item) {
|
||||
return $item->id == $this->settings->language_id;
|
||||
})->first();
|
||||
|
||||
// return Language::find($this->settings->language_id);
|
||||
|
||||
}
|
||||
|
||||
public function getLocale()
|
||||
|
@ -310,7 +310,7 @@ class CompanyGateway extends BaseModel
|
||||
if(strlen($fees_and_limits->fee_percent) >=1)
|
||||
$label .= $fees_and_limits->fee_percent . '%';
|
||||
|
||||
if(strlen($fees_and_limits->fee_amount) >=1){
|
||||
if(strlen($fees_and_limits->fee_amount) >=1 && $fees_and_limits->fee_amount > 0){
|
||||
|
||||
if(strlen($label) > 1) {
|
||||
|
||||
@ -413,8 +413,9 @@ class CompanyGateway extends BaseModel
|
||||
|
||||
public function resolveRouteBinding($value, $field = null)
|
||||
{
|
||||
|
||||
return $this
|
||||
->where('id', $this->decodePrimaryKey($value))->firstOrFail();
|
||||
->where('id', $this->decodePrimaryKey($value))->withTrashed()->firstOrFail();
|
||||
}
|
||||
|
||||
|
||||
|
@ -212,14 +212,14 @@ class PurchaseOrder extends BaseModel
|
||||
return Storage::disk(config('filesystems.default'))->{$type}($file_path);
|
||||
}
|
||||
elseif(Ninja::isHosted() && $portal){
|
||||
$file_path = CreatePurchaseOrderPdf::dispatchNow($invitation,config('filesystems.default'));
|
||||
$file_path = (new CreatePurchaseOrderPdf($invitation,config('filesystems.default')))->handle();
|
||||
return Storage::disk(config('filesystems.default'))->{$type}($file_path);
|
||||
}
|
||||
|
||||
if(Storage::disk('public')->exists($file_path))
|
||||
return Storage::disk('public')->{$type}($file_path);
|
||||
|
||||
$file_path = CreatePurchaseOrderPdf::dispatchNow($invitation);
|
||||
$file_path = (new CreatePurchaseOrderPdf($invitation))->handle();
|
||||
return Storage::disk('public')->{$type}($file_path);
|
||||
}
|
||||
|
||||
|
@ -83,6 +83,11 @@ class Subscription extends BaseModel
|
||||
return $this->belongsTo(User::class)->withTrashed();
|
||||
}
|
||||
|
||||
public function group_settings()
|
||||
{
|
||||
return $this->belongsTo(GroupSetting::class, 'group_id', 'id');
|
||||
}
|
||||
|
||||
public function nextDateByInterval($date, $frequency_id)
|
||||
{
|
||||
switch ($frequency_id) {
|
||||
|
@ -181,4 +181,10 @@ class Vendor extends BaseModel
|
||||
{
|
||||
return $this->belongsTo(Country::class);
|
||||
}
|
||||
|
||||
public function date_format()
|
||||
{
|
||||
return $this->company->date_format();
|
||||
}
|
||||
|
||||
}
|
||||
|
89
app/Notifications/Ninja/UserQualityNotification.php
Normal file
89
app/Notifications/Ninja/UserQualityNotification.php
Normal file
@ -0,0 +1,89 @@
|
||||
<?php
|
||||
/**
|
||||
* Invoice Ninja (https://invoiceninja.com).
|
||||
*
|
||||
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||
*
|
||||
* @copyright Copyright (c) 2022. Invoice Ninja LLC (https://invoiceninja.com)
|
||||
*
|
||||
* @license https://www.elastic.co/licensing/elastic-license
|
||||
*/
|
||||
|
||||
namespace App\Notifications\Ninja;
|
||||
|
||||
use App\Models\User;
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Foundation\Bus\Dispatchable;
|
||||
use Illuminate\Notifications\Messages\MailMessage;
|
||||
use Illuminate\Notifications\Messages\SlackMessage;
|
||||
use Illuminate\Notifications\Notification;
|
||||
use Illuminate\Queue\InteractsWithQueue;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
|
||||
class UserQualityNotification extends Notification
|
||||
{
|
||||
|
||||
/**
|
||||
* Create a new notification instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
protected User $user;
|
||||
|
||||
protected string $account_key;
|
||||
|
||||
public function __construct(User $user, string $account_key)
|
||||
{
|
||||
$this->user = $user;
|
||||
$this->account_key = $account_key;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the notification's delivery channels.
|
||||
*
|
||||
* @param mixed $notifiable
|
||||
* @return array
|
||||
*/
|
||||
public function via($notifiable)
|
||||
{
|
||||
return ['slack'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the mail representation of the notification.
|
||||
*
|
||||
* @param mixed $notifiable
|
||||
* @return MailMessage
|
||||
*/
|
||||
public function toMail($notifiable)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the array representation of the notification.
|
||||
*
|
||||
* @param mixed $notifiable
|
||||
* @return array
|
||||
*/
|
||||
public function toArray($notifiable)
|
||||
{
|
||||
return [
|
||||
//
|
||||
];
|
||||
}
|
||||
|
||||
public function toSlack($notifiable)
|
||||
{
|
||||
|
||||
$content = "User Quality notification {$this->user->present()->name()} \n";
|
||||
$content .= "Account: {$this->account_key }\n";
|
||||
|
||||
return (new SlackMessage)
|
||||
->success()
|
||||
->from(ctrans('texts.notification_bot'))
|
||||
->image('https://app.invoiceninja.com/favicon.png')
|
||||
->content($content);
|
||||
}
|
||||
}
|
@ -23,7 +23,7 @@ class UserObserver
|
||||
*/
|
||||
public function created(User $user)
|
||||
{
|
||||
//
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@ -34,6 +34,7 @@ class UserObserver
|
||||
*/
|
||||
public function updated(User $user)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -110,22 +110,33 @@ class BraintreePaymentDriver extends BaseDriver
|
||||
}
|
||||
|
||||
$result = $this->gateway->customer()->create([
|
||||
'firstName' => $this->client->present()->name,
|
||||
'email' => $this->client->present()->email,
|
||||
'phone' => $this->client->present()->phone,
|
||||
'firstName' => $this->client->present()->name(),
|
||||
'email' => $this->client->present()->email(),
|
||||
'phone' => $this->client->present()->phone(),
|
||||
]);
|
||||
|
||||
if ($result->success) {
|
||||
$address = $this->gateway->address()->create([
|
||||
'customerId' => $result->customer->id,
|
||||
'firstName' => $this->client->present()->name,
|
||||
'streetAddress' => $this->client->address1,
|
||||
'postalCode' => $this->client->postal_code,
|
||||
'firstName' => $this->client->present()->name(),
|
||||
'streetAddress' => $this->client->address1 ?: '',
|
||||
'postalCode' => $this->client->postal_code ?: '',
|
||||
'countryCodeAlpha2' => $this->client->country ? $this->client->country->iso_3166_2 : '',
|
||||
]);
|
||||
|
||||
return $result->customer;
|
||||
}
|
||||
//12-08-2022 catch when the customer is not created.
|
||||
$data = [
|
||||
'transaction_reference' => null,
|
||||
'transaction_response' => $result,
|
||||
'success' => false,
|
||||
'description' => 'Could not create customer',
|
||||
'code' => 500,
|
||||
];
|
||||
|
||||
SystemLogger::dispatch(['server_response' => $result, 'data' => $data], SystemLog::CATEGORY_GATEWAY_RESPONSE, SystemLog::EVENT_GATEWAY_FAILURE, SystemLog::TYPE_BRAINTREE, $this->client, $this->client->company);
|
||||
|
||||
}
|
||||
|
||||
public function refund(Payment $payment, $amount, $return_client_response = false)
|
||||
|
@ -44,6 +44,7 @@ use Checkout\Payments\PaymentRequest as PaymentsPaymentRequest;
|
||||
use Checkout\Payments\RefundRequest;
|
||||
use Checkout\Payments\Source\RequestIdSource;
|
||||
use Exception;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
|
||||
class CheckoutComPaymentDriver extends BaseDriver
|
||||
{
|
||||
@ -407,9 +408,16 @@ class CheckoutComPaymentDriver extends BaseDriver
|
||||
|
||||
public function process3dsConfirmation(Checkout3dsRequest $request)
|
||||
{
|
||||
|
||||
$this->init();
|
||||
$this->setPaymentHash($request->getPaymentHash());
|
||||
|
||||
//11-08-2022 check the user is autenticated
|
||||
if (!Auth::guard('contact')->check()) {
|
||||
$client = $request->getClient();
|
||||
auth()->guard('contact')->loginUsingId($client->contacts()->first()->id, true);
|
||||
}
|
||||
|
||||
try {
|
||||
$payment = $this->gateway->getPaymentsClient()->getPaymentDetails(
|
||||
$request->query('cko-session-id')
|
||||
|
@ -11,6 +11,8 @@
|
||||
|
||||
namespace App\PaymentDrivers;
|
||||
|
||||
use App\Models\Payment;
|
||||
use App\Jobs\Util\SystemLogger;
|
||||
use App\Models\SystemLog;
|
||||
use App\Models\GatewayType;
|
||||
use App\Utils\Traits\MakesHash;
|
||||
@ -60,31 +62,130 @@ class FortePaymentDriver extends BaseDriver
|
||||
|
||||
public function authorizeView(array $data)
|
||||
{
|
||||
return $this->payment_method->authorizeView($data); //this is your custom implementation from here
|
||||
return $this->payment_method->authorizeView($data);
|
||||
}
|
||||
|
||||
public function authorizeResponse($request)
|
||||
{
|
||||
return $this->payment_method->authorizeResponse($request); //this is your custom implementation from here
|
||||
return $this->payment_method->authorizeResponse($request);
|
||||
}
|
||||
|
||||
public function processPaymentView(array $data)
|
||||
{
|
||||
return $this->payment_method->paymentView($data); //this is your custom implementation from here
|
||||
return $this->payment_method->paymentView($data);
|
||||
}
|
||||
|
||||
public function processPaymentResponse($request)
|
||||
{
|
||||
return $this->payment_method->paymentResponse($request); //this is your custom implementation from here
|
||||
return $this->payment_method->paymentResponse($request);
|
||||
}
|
||||
|
||||
// public function refund(Payment $payment, $amount, $return_client_response = false)
|
||||
// {
|
||||
// return $this->payment_method->yourRefundImplementationHere(); //this is your custom implementation from here
|
||||
// }
|
||||
public function refund(Payment $payment, $amount, $return_client_response = false)
|
||||
{
|
||||
$forte_base_uri = "https://sandbox.forte.net/api/v3/";
|
||||
if($this->company_gateway->getConfigField('testMode') == false){
|
||||
$forte_base_uri = "https://api.forte.net/v3/";
|
||||
}
|
||||
$forte_api_access_id = $this->company_gateway->getConfigField('apiAccessId');
|
||||
$forte_secure_key = $this->company_gateway->getConfigField('secureKey');
|
||||
$forte_auth_organization_id = $this->company_gateway->getConfigField('authOrganizationId');
|
||||
$forte_organization_id = $this->company_gateway->getConfigField('organizationId');
|
||||
$forte_location_id = $this->company_gateway->getConfigField('locationId');
|
||||
|
||||
try {
|
||||
$curl = curl_init();
|
||||
|
||||
curl_setopt_array($curl, array(
|
||||
CURLOPT_URL => $forte_base_uri.'organizations/'.$forte_organization_id.'/locations/'.$forte_location_id.'/transactions',
|
||||
CURLOPT_RETURNTRANSFER => true,
|
||||
CURLOPT_ENCODING => '',
|
||||
CURLOPT_MAXREDIRS => 10,
|
||||
CURLOPT_TIMEOUT => 0,
|
||||
CURLOPT_FOLLOWLOCATION => true,
|
||||
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
|
||||
CURLOPT_CUSTOMREQUEST => 'POST',
|
||||
CURLOPT_POSTFIELDS =>'{
|
||||
"action":"reverse",
|
||||
"authorization_amount":'.$amount.',
|
||||
"original_transaction_id":"'.$payment->transaction_reference.'",
|
||||
"authorization_code": "9ZQ754"
|
||||
}',
|
||||
CURLOPT_HTTPHEADER => array(
|
||||
'Content-Type: application/json',
|
||||
'X-Forte-Auth-Organization-Id: '.$forte_organization_id,
|
||||
'Authorization: Basic '.base64_encode($forte_api_access_id.':'.$forte_secure_key)
|
||||
),
|
||||
));
|
||||
|
||||
$response = curl_exec($curl);
|
||||
$httpcode = curl_getinfo($curl, CURLINFO_HTTP_CODE);
|
||||
|
||||
curl_close($curl);
|
||||
|
||||
$response=json_decode($response);
|
||||
|
||||
} catch (\Throwable $th) {
|
||||
$message = [
|
||||
'action' => 'error',
|
||||
'data' => $th,
|
||||
];
|
||||
|
||||
SystemLogger::dispatch(
|
||||
$message,
|
||||
SystemLog::CATEGORY_GATEWAY_RESPONSE,
|
||||
SystemLog::EVENT_GATEWAY_FAILURE,
|
||||
SystemLog::TYPE_FORTE,
|
||||
$this->client,
|
||||
$this->client->company,
|
||||
);
|
||||
}
|
||||
|
||||
$message = [
|
||||
'action' => 'refund',
|
||||
'server_message' => $response->response->response_desc,
|
||||
'server_response' => $response,
|
||||
'data' => $payment->paymentables,
|
||||
];
|
||||
|
||||
if ($httpcode>299) {
|
||||
SystemLogger::dispatch(
|
||||
$message,
|
||||
SystemLog::CATEGORY_GATEWAY_RESPONSE,
|
||||
SystemLog::EVENT_GATEWAY_FAILURE,
|
||||
SystemLog::TYPE_FORTE,
|
||||
$this->client,
|
||||
$this->client->company,
|
||||
);
|
||||
|
||||
return [
|
||||
'transaction_reference' => $payment->transaction_reference,
|
||||
'transaction_response' => $response,
|
||||
'success' => false,
|
||||
'description' => $payment->paymentables,
|
||||
'code' => 422,
|
||||
];
|
||||
}
|
||||
|
||||
SystemLogger::dispatch(
|
||||
$message,
|
||||
SystemLog::CATEGORY_GATEWAY_RESPONSE,
|
||||
SystemLog::EVENT_GATEWAY_SUCCESS,
|
||||
SystemLog::TYPE_FORTE,
|
||||
$this->client,
|
||||
$this->client->company,
|
||||
);
|
||||
|
||||
return [
|
||||
'transaction_reference' => $payment->transaction_reference,
|
||||
'transaction_response' => $response,
|
||||
'success' => $response->response->response_code == 'A01' ? true : false,
|
||||
'description' => $payment->paymentables,
|
||||
'code' => $httpcode,
|
||||
];
|
||||
}
|
||||
|
||||
// public function tokenBilling(ClientGatewayToken $cgt, PaymentHash $payment_hash)
|
||||
// {
|
||||
// return $this->payment_method->yourTokenBillingImplmentation(); //this is your custom implementation from here
|
||||
// return $this->payment_method->yourTokenBillingImplmentation();
|
||||
// }
|
||||
}
|
||||
|
@ -62,12 +62,12 @@ class DirectDebit implements MethodInterface
|
||||
'session_token' => $session_token,
|
||||
]),
|
||||
'prefilled_customer' => [
|
||||
'given_name' => auth()->guard('contact')->user()->first_name,
|
||||
'family_name' => auth()->guard('contact')->user()->last_name,
|
||||
'email' => auth()->guard('contact')->user()->email,
|
||||
'address_line1' => auth()->guard('contact')->user()->client->address1,
|
||||
'city' => auth()->guard('contact')->user()->client->city,
|
||||
'postal_code' => auth()->guard('contact')->user()->client->postal_code,
|
||||
'given_name' => auth()->guard('contact')->user()->first_name ?: '',
|
||||
'family_name' => auth()->guard('contact')->user()->last_name ?: '',
|
||||
'email' => auth()->guard('contact')->user()->email ?: '',
|
||||
'address_line1' => auth()->guard('contact')->user()->client->address1 ?: '',
|
||||
'city' => auth()->guard('contact')->user()->client->city ?: '',
|
||||
'postal_code' => auth()->guard('contact')->user()->client->postal_code ?: '',
|
||||
],
|
||||
],
|
||||
]);
|
||||
|
@ -47,14 +47,6 @@ class CreditCard
|
||||
return render('gateways.paytrace.authorize', $data);
|
||||
}
|
||||
|
||||
// +"success": true
|
||||
// +"response_code": 160
|
||||
// +"status_message": "The customer profile for PLS5U60OoLUfQXzcmtJYNefPA0gTthzT/11 was successfully created."
|
||||
// +"customer_id": "PLS5U60OoLUfQXzcmtJYNefPA0gTthzT"
|
||||
|
||||
//if(!$response->success)
|
||||
//handle failure
|
||||
|
||||
public function authorizeResponse($request)
|
||||
{
|
||||
$data = $request->all();
|
||||
@ -64,27 +56,6 @@ class CreditCard
|
||||
return redirect()->route('client.payment_methods.index');
|
||||
}
|
||||
|
||||
// "_token" => "Vl1xHflBYQt9YFSaNCPTJKlY5x3rwcFE9kvkw71I"
|
||||
// "company_gateway_id" => "1"
|
||||
// "HPF_Token" => "e484a92c-90ed-4468-ac4d-da66824c75de"
|
||||
// "enc_key" => "zqz6HMHCXALWdX5hyBqrIbSwU7TBZ0FTjjLB3Cp0FQY="
|
||||
// "amount" => "Amount"
|
||||
// "q" => "/client/payment_methods"
|
||||
// "method" => "1"
|
||||
// ]
|
||||
|
||||
// "customer_id":"customer789",
|
||||
// "hpf_token":"e369847e-3027-4174-9161-fa0d4e98d318",
|
||||
// "enc_key":"lI785yOBMet4Rt9o4NLXEyV84WBU3tdStExcsfoaOoo=",
|
||||
// "integrator_id":"xxxxxxxxxx",
|
||||
// "billing_address":{
|
||||
// "name":"Mark Smith",
|
||||
// "street_address":"8320 E. West St.",
|
||||
// "city":"Spokane",
|
||||
// "state":"WA",
|
||||
// "zip":"85284"
|
||||
// }
|
||||
|
||||
private function createCustomer($data)
|
||||
{
|
||||
$post_data = [
|
||||
@ -156,6 +127,7 @@ class CreditCard
|
||||
'zip' => $this->paytrace->client->postal_code,
|
||||
];
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
public function paymentView($data)
|
||||
|
@ -81,7 +81,7 @@ class CreditCard implements MethodInterface
|
||||
$client->addressLines = [$this->square_driver->client->address1 ?: '', $this->square_driver->client->address2 ?: ''];
|
||||
$client->givenName = $this->square_driver->client->present()->first_name();
|
||||
$client->familyName = $this->square_driver->client->present()->last_name();
|
||||
$client->email = $this->square_driver->client->present()->email;
|
||||
$client->email = $this->square_driver->client->present()->email();
|
||||
$client->phone = $this->square_driver->client->phone;
|
||||
$client->city = $this->square_driver->client->city;
|
||||
$client->region = $this->square_driver->client->state;
|
||||
|
@ -195,8 +195,6 @@ class SquarePaymentDriver extends BaseDriver
|
||||
{
|
||||
$fields = [];
|
||||
|
||||
$fields[] = ['name' => 'client_postal_code', 'label' => ctrans('texts.postal_code'), 'type' => 'text', 'validation' => 'required'];
|
||||
|
||||
if ($this->company_gateway->require_client_name) {
|
||||
$fields[] = ['name' => 'client_name', 'label' => ctrans('texts.client_name'), 'type' => 'text', 'validation' => 'required'];
|
||||
}
|
||||
@ -217,6 +215,7 @@ class SquarePaymentDriver extends BaseDriver
|
||||
if ($this->company_gateway->require_billing_address) {
|
||||
$fields[] = ['name' => 'client_address_line_1', 'label' => ctrans('texts.address1'), 'type' => 'text', 'validation' => 'required'];
|
||||
// $fields[] = ['name' => 'client_address_line_2', 'label' => ctrans('texts.address2'), 'type' => 'text', 'validation' => 'nullable'];
|
||||
$fields[] = ['name' => 'client_postal_code', 'label' => ctrans('texts.postal_code'), 'type' => 'text', 'validation' => 'required'];
|
||||
$fields[] = ['name' => 'client_city', 'label' => ctrans('texts.city'), 'type' => 'text', 'validation' => 'required'];
|
||||
$fields[] = ['name' => 'client_state', 'label' => ctrans('texts.state'), 'type' => 'text', 'validation' => 'required'];
|
||||
$fields[] = ['name' => 'client_country_id', 'label' => ctrans('texts.country'), 'type' => 'text', 'validation' => 'required'];
|
||||
|
@ -74,6 +74,9 @@ class UpdatePaymentMethods
|
||||
{
|
||||
$sources = $customer->sources;
|
||||
|
||||
if(!property_exists($sources, 'data'))
|
||||
return;
|
||||
|
||||
foreach ($sources->data as $method) {
|
||||
$token_exists = ClientGatewayToken::where([
|
||||
'gateway_customer_reference' => $customer->id,
|
||||
|
@ -271,9 +271,9 @@ class EventServiceProvider extends ServiceProvider
|
||||
],
|
||||
MessageSending::class => [
|
||||
],
|
||||
// MessageSent::class => [
|
||||
// MailSentListener::class,
|
||||
// ],
|
||||
MessageSent::class => [
|
||||
MailSentListener::class,
|
||||
],
|
||||
UserWasCreated::class => [
|
||||
CreatedUserActivity::class,
|
||||
SendVerificationNotification::class,
|
||||
|
@ -339,6 +339,11 @@ class BaseRepository
|
||||
else
|
||||
event('eloquent.updated: App\Models\Credit', $model);
|
||||
|
||||
if (($state['finished_amount'] != $state['starting_amount']) && ($model->status_id != Credit::STATUS_DRAFT)) {
|
||||
|
||||
$model->client->service()->adjustCreditBalance(($state['finished_amount'] - $state['starting_amount']))->save();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if ($model instanceof Quote) {
|
||||
|
@ -28,10 +28,21 @@ class ClientContactRepository extends BaseRepository
|
||||
|
||||
public function save(array $data, Client $client) : void
|
||||
{
|
||||
if (isset($data['contacts'])) {
|
||||
//06-09-2022 sometimes users pass a contact object instead of a nested array, this sequence handles this scenario
|
||||
if (isset($data['contacts']) && (count($data['contacts']) !== count($data['contacts'], COUNT_RECURSIVE))) {
|
||||
|
||||
$contacts = collect($data['contacts']);
|
||||
} else {
|
||||
|
||||
} elseif(isset($data['contacts'])){
|
||||
|
||||
$temp_array[] = $data['contacts'];
|
||||
$contacts = collect($temp_array);
|
||||
|
||||
}
|
||||
else {
|
||||
|
||||
$contacts = collect();
|
||||
|
||||
}
|
||||
|
||||
$client->contacts->pluck('id')->diff($contacts->pluck('id'))->each(function ($contact) {
|
||||
@ -45,6 +56,7 @@ class ClientContactRepository extends BaseRepository
|
||||
|
||||
/* Set first record to primary - always */
|
||||
$contacts = $contacts->sortByDesc('is_primary')->map(function ($contact) {
|
||||
|
||||
$contact['is_primary'] = $this->is_primary;
|
||||
$this->is_primary = false;
|
||||
|
||||
|
@ -43,4 +43,31 @@ class CreditRepository extends BaseRepository
|
||||
{
|
||||
return CreditInvitation::where('key', $key)->first();
|
||||
}
|
||||
|
||||
public function delete($credit)
|
||||
{
|
||||
if ($credit->is_deleted) {
|
||||
return;
|
||||
}
|
||||
|
||||
$credit = $credit->service()->deleteCredit()->save();
|
||||
|
||||
return parent::delete($credit);
|
||||
|
||||
}
|
||||
|
||||
public function restore($credit)
|
||||
{
|
||||
//we cannot restore a deleted payment.
|
||||
if (! $credit->trashed()) {
|
||||
return;
|
||||
}
|
||||
|
||||
parent::restore($credit);
|
||||
|
||||
$credit = $credit->service()->restoreCredit()->save();
|
||||
|
||||
return $credit;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -73,28 +73,38 @@ class PaymentRepository extends BaseRepository {
|
||||
unset($data['exchange_rate']);
|
||||
|
||||
$is_existing_payment = false;
|
||||
$client = Client::where('id', $data['client_id'])->withTrashed()->first();
|
||||
|
||||
/*We only update the paid to date ONCE per payment*/
|
||||
if (array_key_exists('invoices', $data) && is_array($data['invoices']) && count($data['invoices']) > 0) {
|
||||
if ($data['amount'] == '') {
|
||||
$data['amount'] = array_sum(array_column($data['invoices'], 'amount'));
|
||||
\DB::connection(config('database.default'))->transaction(function () use ($data) {
|
||||
|
||||
$client = Client::where('id', $data['client_id'])->withTrashed()->lockForUpdate()->first();
|
||||
|
||||
/*We only update the paid to date ONCE per payment*/
|
||||
if (array_key_exists('invoices', $data) && is_array($data['invoices']) && count($data['invoices']) > 0) {
|
||||
if ($data['amount'] == '') {
|
||||
$data['amount'] = array_sum(array_column($data['invoices'], 'amount'));
|
||||
}
|
||||
|
||||
$client->service()->updatePaidToDate($data['amount'])->save();
|
||||
// $client->paid_to_date += $data['amount'];
|
||||
$client->save();
|
||||
}
|
||||
|
||||
$client->service()->updatePaidToDate($data['amount'])->save();
|
||||
}
|
||||
else{
|
||||
//this fixes an edge case with unapplied payments
|
||||
$client->service()->updatePaidToDate($data['amount'])->save();
|
||||
// $client->paid_to_date += $data['amount'];
|
||||
$client->save();
|
||||
}
|
||||
|
||||
else{
|
||||
//this fixes an edge case with unapplied payments
|
||||
$client->service()->updatePaidToDate($data['amount'])->save();
|
||||
}
|
||||
if (array_key_exists('credits', $data) && is_array($data['credits']) && count($data['credits']) > 0) {
|
||||
$_credit_totals = array_sum(array_column($data['credits'], 'amount'));
|
||||
|
||||
if (array_key_exists('credits', $data) && is_array($data['credits']) && count($data['credits']) > 0) {
|
||||
$_credit_totals = array_sum(array_column($data['credits'], 'amount'));
|
||||
$client->service()->updatePaidToDate($_credit_totals)->save();
|
||||
// $client->paid_to_date += $_credit_totals;
|
||||
$client->save();
|
||||
}
|
||||
|
||||
$client->service()->updatePaidToDate($_credit_totals)->save();
|
||||
|
||||
}
|
||||
}, 1);
|
||||
|
||||
}
|
||||
|
||||
@ -121,7 +131,8 @@ class PaymentRepository extends BaseRepository {
|
||||
|
||||
/*Ensure payment number generated*/
|
||||
if (! $payment->number || strlen($payment->number) == 0) {
|
||||
$payment->number = $payment->client->getNextPaymentNumber($payment->client, $payment);
|
||||
// $payment->number = $payment->client->getNextPaymentNumber($payment->client, $payment);
|
||||
$payment->service()->applyNumber();
|
||||
}
|
||||
|
||||
/*Set local total variables*/
|
||||
@ -139,7 +150,8 @@ class PaymentRepository extends BaseRepository {
|
||||
|
||||
//todo optimize this into a single query
|
||||
foreach ($data['invoices'] as $paid_invoice) {
|
||||
$invoice = Invoice::withTrashed()->whereId($paid_invoice['invoice_id'])->first();
|
||||
// $invoice = Invoice::withTrashed()->whereId($paid_invoice['invoice_id'])->first();
|
||||
$invoice = $invoices->firstWhere('id', $paid_invoice['invoice_id']);
|
||||
|
||||
if ($invoice) {
|
||||
$invoice = $invoice->service()
|
||||
@ -157,16 +169,20 @@ class PaymentRepository extends BaseRepository {
|
||||
if (array_key_exists('credits', $data) && is_array($data['credits'])) {
|
||||
$credit_totals = array_sum(array_column($data['credits'], 'amount'));
|
||||
|
||||
$credits = Credit::whereIn('id', $this->transformKeys(array_column($data['credits'], 'credit_id')))->get();
|
||||
// $credits = Credit::whereIn('id', $this->transformKeys(array_column($data['credits'], 'credit_id')))->get();
|
||||
|
||||
$credits = Credit::whereIn('id', array_column($data['credits'], 'credit_id'))->get();
|
||||
|
||||
$payment->credits()->saveMany($credits);
|
||||
|
||||
//todo optimize into a single query
|
||||
foreach ($data['credits'] as $paid_credit) {
|
||||
$credit = Credit::withTrashed()->find($this->decodePrimaryKey($paid_credit['credit_id']));
|
||||
|
||||
// $credit = Credit::withTrashed()->find($paid_credit['credit_id']);
|
||||
$credit = $credits->firstWhere('id', $paid_credit['credit_id']);
|
||||
|
||||
if ($credit) {
|
||||
$credit = $credit->service()->markSent()->save();
|
||||
ApplyCreditPayment::dispatchNow($credit, $payment, $paid_credit['amount'], $credit->company);
|
||||
(new ApplyCreditPayment($credit, $payment, $paid_credit['amount'], $credit->company))->handle();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -245,7 +261,7 @@ class PaymentRepository extends BaseRepository {
|
||||
event(new PaymentWasDeleted($payment, $payment->company, Ninja::eventVars(auth()->user() ? auth()->user()->id : null)));
|
||||
|
||||
return $payment;
|
||||
//return parent::delete($payment);
|
||||
|
||||
}
|
||||
|
||||
public function restore($payment)
|
||||
|
@ -62,7 +62,9 @@ class UserRepository extends BaseRepository
|
||||
// $account->num_users++;
|
||||
// $account->save();
|
||||
// }
|
||||
|
||||
if(array_key_exists('oauth_provider_id', $details))
|
||||
unset($details['oauth_provider_id']);
|
||||
|
||||
$user->fill($details);
|
||||
|
||||
//allow users to change only their passwords - not others!
|
||||
|
@ -12,6 +12,7 @@
|
||||
namespace App\Services\Client;
|
||||
|
||||
use App\Models\Client;
|
||||
use App\Models\Credit;
|
||||
use App\Services\Client\Merge;
|
||||
use App\Services\Client\PaymentMethod;
|
||||
use App\Utils\Number;
|
||||
@ -28,14 +29,47 @@ class ClientService
|
||||
|
||||
public function updateBalance(float $amount)
|
||||
{
|
||||
$this->client->balance += $amount;
|
||||
// $this->client->balance += $amount;
|
||||
|
||||
\DB::connection(config('database.default'))->transaction(function () use($amount) {
|
||||
|
||||
$this->client = Client::where('id', $this->client->id)->lockForUpdate()->first();
|
||||
$this->client->balance += $amount;
|
||||
$this->client->save();
|
||||
|
||||
}, 2);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function updateBalanceAndPaidToDate(float $balance, float $paid_to_date)
|
||||
{
|
||||
// $this->client->balance += $amount;
|
||||
// $this->client->paid_to_date += $amount;
|
||||
|
||||
\DB::connection(config('database.default'))->transaction(function () use($balance, $paid_to_date) {
|
||||
|
||||
$this->client = Client::where('id', $this->client->id)->lockForUpdate()->first();
|
||||
$this->client->balance += $balance;
|
||||
$this->client->paid_to_date += $paid_to_date;
|
||||
$this->client->save();
|
||||
|
||||
}, 2);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function updatePaidToDate(float $amount)
|
||||
{
|
||||
$this->client->paid_to_date += $amount;
|
||||
// $this->client->paid_to_date += $amount;
|
||||
|
||||
\DB::connection(config('database.default'))->transaction(function () use($amount) {
|
||||
|
||||
$this->client = Client::where('id', $this->client->id)->lockForUpdate()->first();
|
||||
$this->client->paid_to_date += $amount;
|
||||
$this->client->save();
|
||||
|
||||
}, 2);
|
||||
|
||||
return $this;
|
||||
}
|
||||
@ -49,7 +83,7 @@ class ClientService
|
||||
|
||||
public function getCreditBalance() :float
|
||||
{
|
||||
$credits = $this->client->credits()
|
||||
$credits = Credit::where('client_id', $this->client->id)
|
||||
->where('is_deleted', false)
|
||||
->where('balance', '>', 0)
|
||||
->where(function ($query) {
|
||||
@ -63,7 +97,7 @@ class ClientService
|
||||
|
||||
public function getCredits()
|
||||
{
|
||||
return $this->client->credits()
|
||||
return Credit::where('client_id', $this->client->id)
|
||||
->where('is_deleted', false)
|
||||
->where('balance', '>', 0)
|
||||
->where(function ($query) {
|
||||
|
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