diff --git a/VERSION.txt b/VERSION.txt
index 2a06a418a773..fad8076f307d 100644
--- a/VERSION.txt
+++ b/VERSION.txt
@@ -1 +1 @@
-5.6.4
\ No newline at end of file
+5.6.5
\ No newline at end of file
diff --git a/app/DataMapper/Tax/US/Rule.php b/app/DataMapper/Tax/US/Rule.php
index fbfb5b78b323..469d16c74a6f 100644
--- a/app/DataMapper/Tax/US/Rule.php
+++ b/app/DataMapper/Tax/US/Rule.php
@@ -48,7 +48,6 @@ class Rule extends BaseRule implements RuleInterface
{
$this->tax_rate1 = $item->tax_rate1;
-
$this->tax_name1 = $item->tax_name1;
return $this;
@@ -117,6 +116,9 @@ class Rule extends BaseRule implements RuleInterface
if(in_array($this->tax_data?->txbService,['Y','L'])) {
$this->default($item);
}
+ else {
+ $this->taxExempt($item);
+ }
return $this;
}
@@ -165,9 +167,6 @@ class Rule extends BaseRule implements RuleInterface
$this->tax_rate1 = 0;
$this->tax_name1 = '';
- // $this->tax_rate1 = $this->invoice->client->company->tax_data->regions->{$this->client_region}->subregions->{$this->client_subregion}->tax_rate;
- // $this->tax_name1 = "Sales Tax";
-
return $this;
}
diff --git a/app/Exceptions/Handler.php b/app/Exceptions/Handler.php
index c551b6d38306..506213d57797 100644
--- a/app/Exceptions/Handler.php
+++ b/app/Exceptions/Handler.php
@@ -105,7 +105,7 @@ class Handler extends ExceptionHandler
if($exception instanceof ThrottleRequestsException && class_exists(\Modules\Admin\Events\ThrottledExceptionRaised::class)) {
$uri = urldecode(request()->getRequestUri());
- event(new \Modules\Admin\Events\ThrottledExceptionRaised(auth()->user()?->account?->key, $uri, request()->ip()));
+ // event(new \Modules\Admin\Events\ThrottledExceptionRaised(auth()->user()?->account?->key, $uri, request()->ip()));
}
Integration::configureScope(function (Scope $scope): void {
diff --git a/app/Exceptions/QuoteConversion.php b/app/Exceptions/QuoteConversion.php
new file mode 100644
index 000000000000..a4812f4c1bdb
--- /dev/null
+++ b/app/Exceptions/QuoteConversion.php
@@ -0,0 +1,41 @@
+json(['message' => 'This quote has already been converted. Cannot convert again.'], 400);
+ }
+}
diff --git a/app/Factory/RecurringExpenseToExpenseFactory.php b/app/Factory/RecurringExpenseToExpenseFactory.php
index 98c2a7beee6f..82ea9224f75a 100644
--- a/app/Factory/RecurringExpenseToExpenseFactory.php
+++ b/app/Factory/RecurringExpenseToExpenseFactory.php
@@ -95,6 +95,11 @@ class RecurringExpenseToExpenseFactory
$replacements = [
'literal' => [
+ ':MONTHYEAR' => \sprintf(
+ '%s %s',
+ Carbon::createFromDate(now()->year, now()->month)->translatedFormat('F'),
+ now()->year,
+ ),
':MONTH' => Carbon::createFromDate(now()->year, now()->month)->translatedFormat('F'),
':YEAR' => now()->year,
':QUARTER' => 'Q'.now()->quarter,
@@ -240,6 +245,17 @@ class RecurringExpenseToExpenseFactory
$output = \Carbon\Carbon::create()->month($output)->translatedFormat('F');
}
+ if ($matches->keys()->first() == ':MONTHYEAR') {
+
+ $final_date = now()->addMonths($output-now()->month);
+
+ $output = \sprintf(
+ '%s %s',
+ $final_date->translatedFormat('F'),
+ $final_date->year,
+ );
+ }
+
$value = preg_replace(
$target,
$output,
diff --git a/app/Filters/ExpenseFilters.php b/app/Filters/ExpenseFilters.php
index d589362a63b7..6260c1b04b3c 100644
--- a/app/Filters/ExpenseFilters.php
+++ b/app/Filters/ExpenseFilters.php
@@ -106,6 +106,29 @@ class ExpenseFilters extends QueryFilters
return $this->builder;
}
+ /**
+ * Filter expenses that only have invoices
+ *
+ * @param string $value
+ * @return Builder
+ */
+ public function has_invoices(string $value = ''): Builder
+ {
+ $split = explode(",", $value);
+
+ if (is_array($split) && in_array($split[0], ['client', 'project'])) {
+
+ $search_key = $split[0] == 'client' ? 'client_id' : 'project_id';
+
+ return $this->builder->whereHas('invoice', function ($query) use ($search_key, $split){
+ $query->where($search_key, $this->decodePrimaryKey($split[1]))
+ ->whereIn('status_id', [\App\Models\Invoice::STATUS_DRAFT, \App\Models\Invoice::STATUS_SENT, \App\Models\Invoice::STATUS_PARTIAL]);
+ });
+ }
+
+ return $this->builder;
+ }
+
/**
* Returns a list of expenses that can be matched to bank transactions
*/
diff --git a/app/Filters/UserFilters.php b/app/Filters/UserFilters.php
index b0079e339189..20d2a7ce777f 100644
--- a/app/Filters/UserFilters.php
+++ b/app/Filters/UserFilters.php
@@ -89,6 +89,15 @@ class UserFilters extends QueryFilters
->where('account_id', auth()->user()->account_id);
}
+ public function sending_users(string $value = ''): Builder
+ {
+ if (strlen($value) == 0 || $value != 'true') {
+ return $this->builder;
+ }
+
+ return $this->builder->whereNotNull('oauth_user_refresh_token');
+ }
+
/**
* Exclude a list of user_ids, can pass multiple
* user IDs by separating them with a comma.
diff --git a/app/Helpers/Bank/Yodlee/Transformer/IncomeTransformer.php b/app/Helpers/Bank/Yodlee/Transformer/IncomeTransformer.php
index 42c0e9bf5895..48966aa20382 100644
--- a/app/Helpers/Bank/Yodlee/Transformer/IncomeTransformer.php
+++ b/app/Helpers/Bank/Yodlee/Transformer/IncomeTransformer.php
@@ -127,9 +127,12 @@ class IncomeTransformer implements BankRevenueInterface
foreach ($transaction->transaction as $transaction) {
//do not store duplicate / pending transactions
- if (property_exists($transaction, 'status') && $transaction->status == 'PENDING') {
+ if (property_exists($transaction, 'status') && $transaction->status == 'PENDING')
+ continue;
+
+ //some object do no store amounts ignore these
+ if(!property_exists($transaction, 'amount'))
continue;
- }
$data[] = $this->transformTransaction($transaction);
}
@@ -148,7 +151,7 @@ class IncomeTransformer implements BankRevenueInterface
'category_type' => $transaction->categoryType,
'date' => $transaction->date,
'bank_account_id' => $transaction->accountId,
- 'description' => $transaction->description->original,
+ 'description' => $transaction?->description?->original ?? '',
'base_type' => property_exists($transaction, 'baseType') ? $transaction->baseType : $this->calculateBaseType($transaction),
];
}
diff --git a/app/Http/Controllers/ActivityController.php b/app/Http/Controllers/ActivityController.php
index 9bb69c13f15c..ac850442125e 100644
--- a/app/Http/Controllers/ActivityController.php
+++ b/app/Http/Controllers/ActivityController.php
@@ -92,46 +92,47 @@ class ActivityController extends BaseController
->company()
->take($default_activities);
- if ($request->has('react')) {
+ // if ($request->has('react')) {
- /** @var \App\Models\User auth()->user() */
- $user = auth()->user();
+ // /** @var \App\Models\User auth()->user() */
+ // $user = auth()->user();
- if (!$user->isAdmin()) {
- $activities->where('user_id', auth()->user()->id);
- }
+ // if (!$user->isAdmin()) {
+ // $activities->where('user_id', auth()->user()->id);
+ // }
- $system = ctrans('texts.system');
+ // $system = ctrans('texts.system');
- $data = $activities->cursor()->map(function ($activity) {
+ // $data = $activities->cursor()->map(function ($activity) {
- $arr =
- [
- 'client' => $activity->client ? $activity->client : '',
- 'contact' => $activity->client ? $activity->contact : '',
- 'quote' => $activity->quote ? $activity->quote : '',
- 'user' => $activity->user ? $activity->user : '',
- 'expense' => $activity->expense ? $activity->expense : '',
- 'invoice' => $activity->invoice ? $activity->invoice : '',
- 'recurring_invoice' => $activity->recurring_invoice ? $activity->recurring_invoice : '',
- 'payment' => $activity->payment ? $activity->payment : '',
- 'credit' => $activity->credit ? $activity->credit : '',
- 'task' => $activity->task ? $activity->task : '',
- 'vendor' => $activity->vendor ? $activity->vendor : '',
- 'purchase_order' => $activity->purchase_order ? $activity->purchase_order : '',
- 'subscription' => $activity->subscription ? $activity->subscription : '',
- 'vendor_contact' => $activity->vendor_contact ? $activity->vendor_contact : '',
- 'recurring_expense' => $activity->recurring_expense ? $activity->recurring_expense : '',
- ];
+ // $arr =
+ // [
+ // 'client' => $activity->client ? $activity->client : '',
+ // 'contact' => $activity->client ? $activity->contact : '',
+ // 'quote' => $activity->quote ? $activity->quote : '',
+ // 'user' => $activity->user ? $activity->user : '',
+ // 'expense' => $activity->expense ? $activity->expense : '',
+ // 'invoice' => $activity->invoice ? $activity->invoice : '',
+ // 'recurring_invoice' => $activity->recurring_invoice ? $activity->recurring_invoice : '',
+ // 'payment' => $activity->payment ? $activity->payment : '',
+ // 'credit' => $activity->credit ? $activity->credit : '',
+ // 'task' => $activity->task ? $activity->task : '',
+ // 'vendor' => $activity->vendor ? $activity->vendor : '',
+ // 'purchase_order' => $activity->purchase_order ? $activity->purchase_order : '',
+ // 'subscription' => $activity->subscription ? $activity->subscription : '',
+ // 'vendor_contact' => $activity->vendor_contact ? $activity->vendor_contact : '',
+ // 'recurring_expense' => $activity->recurring_expense ? $activity->recurring_expense : '',
+ // ];
- $activity_array = $activity->toArray();
+ // $activity_array = $activity->toArray();
- return array_merge($arr, $activity_array);
- });
+ // return array_merge($arr, $activity_array);
+ // });
- return response()->json(['data' => $data->toArray()], 200);
- }
- elseif($request->has('reactv2')) {
+ // return response()->json(['data' => $data->toArray()], 200);
+ // }
+ // else
+ if($request->has('reactv2')) {
/** @var \App\Models\User auth()->user() */
$user = auth()->user();
diff --git a/app/Http/Controllers/Auth/LoginController.php b/app/Http/Controllers/Auth/LoginController.php
index a2ad553c95e9..a32ea52c4efb 100644
--- a/app/Http/Controllers/Auth/LoginController.php
+++ b/app/Http/Controllers/Auth/LoginController.php
@@ -682,8 +682,6 @@ class LoginController extends BaseController
'email' => $socialite_user->getEmail(),
'oauth_user_id' => $socialite_user->getId(),
'oauth_provider_id' => $provider,
- // 'oauth_user_token' => $oauth_user_token,
- // 'oauth_user_refresh_token' => $socialite_user->refreshToken,
];
$user->update($update_user);
@@ -699,7 +697,7 @@ class LoginController extends BaseController
$request_from_react = Cache::pull("react_redir:".auth()->user()?->account?->key);
- if($request_from_react)
+ // if($request_from_react)
$redirect_url = config('ninja.react_url')."/#/settings/user_details/connect";
return redirect($redirect_url);
@@ -735,6 +733,10 @@ class LoginController extends BaseController
nlog('user not found for oauth');
}
- return redirect('/#/');
+ $redirect_url = config('ninja.react_url')."/#/settings/user_details/connect";
+
+ return redirect($redirect_url);
+
+ // return redirect('/#/');
}
}
diff --git a/app/Http/Controllers/ChartController.php b/app/Http/Controllers/ChartController.php
index 85b387d30202..69669159c68f 100644
--- a/app/Http/Controllers/ChartController.php
+++ b/app/Http/Controllers/ChartController.php
@@ -61,7 +61,7 @@ class ChartController extends BaseController
/** @var \App\Models\User auth()->user() */
$user = auth()->user();
$cs = new ChartService($user->company(), $user, $user->isAdmin());
-
+
return response()->json($cs->chart_summary($request->input('start_date'), $request->input('end_date')), 200);
}
diff --git a/app/Http/Controllers/ConnectedAccountController.php b/app/Http/Controllers/ConnectedAccountController.php
index c93d05477935..614a4ccb9717 100644
--- a/app/Http/Controllers/ConnectedAccountController.php
+++ b/app/Http/Controllers/ConnectedAccountController.php
@@ -90,14 +90,15 @@ class ConnectedAccountController extends BaseController
private function handleMicrosoftOauth($request)
{
- nlog($request->all());
+ $access_token = false;
+ $access_token = $request->has('access_token') ? $request->input('access_token') : $request->input('accessToken');
- if (!$request->has('access_token')) {
+ if (!$access_token) {
return response()->json(['message' => 'No access_token parameter found!'], 400);
}
$graph = new \Microsoft\Graph\Graph();
- $graph->setAccessToken($request->input('access_token'));
+ $graph->setAccessToken($access_token);
$user = $graph->createRequest("GET", "/me")
->setReturnType(Model\User::class)
diff --git a/app/Http/Controllers/InvoiceController.php b/app/Http/Controllers/InvoiceController.php
index 6f515dbcf920..1c691f36f577 100644
--- a/app/Http/Controllers/InvoiceController.php
+++ b/app/Http/Controllers/InvoiceController.php
@@ -408,7 +408,7 @@ class InvoiceController extends BaseController
$invoice->service()
->triggeredActions($request)
- ->touchPdf()
+ ->deletePdf()
->adjustInventory($old_invoice);
event(new InvoiceWasUpdated($invoice, $invoice->company, Ninja::eventVars(auth()->user() ? auth()->user()->id : null)));
@@ -740,7 +740,8 @@ class InvoiceController extends BaseController
}
break;
case 'cancel':
- $invoice = $invoice->service()->handleCancellation()->touchPdf()->save();
+ $invoice = $invoice->service()->handleCancellation()->deletePdf()->save();
+ // $invoice = $invoice->service()->handleCancellation()->touchPdf()->save();
if (! $bulk) {
$this->itemResponse($invoice);
diff --git a/app/Http/Requests/Chart/ShowChartRequest.php b/app/Http/Requests/Chart/ShowChartRequest.php
index 83754f2a86e0..f7b4f63ba7e0 100644
--- a/app/Http/Requests/Chart/ShowChartRequest.php
+++ b/app/Http/Requests/Chart/ShowChartRequest.php
@@ -12,9 +12,12 @@
namespace App\Http\Requests\Chart;
use App\Http\Requests\Request;
+use App\Utils\Traits\MakesDates;
class ShowChartRequest extends Request
{
+ use MakesDates;
+
/**
* Determine if the user is authorized to make this request.
*
@@ -22,14 +25,18 @@ class ShowChartRequest extends Request
*/
public function authorize() : bool
{
- return auth()->user()->isAdmin();
+ /**@var \App\Models\User auth()->user */
+ $user = auth()->user();
+
+ return $user->isAdmin();
}
public function rules()
{
return [
- 'start_date' => 'date',
- 'end_date' => 'date',
+ 'date_range' => 'bail|sometimes|string|in:last7_days,last30_days,last365_days,this_month,last_month,this_quarter,last_quarter,this_year,last_year,all_time,custom',
+ 'start_date' => 'bail|sometimes|date',
+ 'end_date' => 'bail|sometimes|date',
];
}
@@ -37,12 +44,18 @@ class ShowChartRequest extends Request
{
$input = $this->all();
- if (! array_key_exists('start_date', $input)) {
- $input['start_date'] = now()->subDays(20);
+ if(isset($input['date_range'])) {
+ $dates = $this->calculateStartAndEndDates($input);
+ $input['start_date'] = $dates[0];
+ $input['end_date'] = $dates[1];
}
- if (! array_key_exists('end_date', $input)) {
- $input['end_date'] = now();
+ if (! isset($input['start_date'])) {
+ $input['start_date'] = now()->subDays(20)->format('Y-m-d');
+ }
+
+ if (! isset($input['end_date'])) {
+ $input['end_date'] = now()->format('Y-m-d');
}
$this->replace($input);
diff --git a/app/Http/Requests/Preview/PreviewInvoiceRequest.php b/app/Http/Requests/Preview/PreviewInvoiceRequest.php
index b2da03628210..bfa4db546470 100644
--- a/app/Http/Requests/Preview/PreviewInvoiceRequest.php
+++ b/app/Http/Requests/Preview/PreviewInvoiceRequest.php
@@ -48,7 +48,7 @@ class PreviewInvoiceRequest extends Request
$input['line_items'] = isset($input['line_items']) ? $this->cleanItems($input['line_items']) : [];
$input['amount'] = 0;
$input['balance'] = 0;
- $input['number'] = ctrans('texts.live_preview').' #'.rand(0, 1000);
+ $input['number'] = isset($input['number']) ? $input['number'] : ctrans('texts.live_preview').' #'.rand(0, 1000);
$this->replace($input);
}
diff --git a/app/Http/Requests/Preview/PreviewPurchaseOrderRequest.php b/app/Http/Requests/Preview/PreviewPurchaseOrderRequest.php
index d91de03c19ec..927937bf25a7 100644
--- a/app/Http/Requests/Preview/PreviewPurchaseOrderRequest.php
+++ b/app/Http/Requests/Preview/PreviewPurchaseOrderRequest.php
@@ -48,7 +48,7 @@ class PreviewPurchaseOrderRequest extends Request
$input['line_items'] = isset($input['line_items']) ? $this->cleanItems($input['line_items']) : [];
$input['amount'] = 0;
$input['balance'] = 0;
- $input['number'] = ctrans('texts.live_preview') . " #". rand(0, 1000);
+ $input['number'] = isset($input['number']) ? $input['number'] : ctrans('texts.live_preview').' #'.rand(0, 1000); //30-06-2023
$this->replace($input);
}
diff --git a/app/Http/Requests/Report/GenericReportRequest.php b/app/Http/Requests/Report/GenericReportRequest.php
index 3e95479d23b5..d18bb516c233 100644
--- a/app/Http/Requests/Report/GenericReportRequest.php
+++ b/app/Http/Requests/Report/GenericReportRequest.php
@@ -33,7 +33,7 @@ class GenericReportRequest extends Request
'start_date' => 'bail|required_if:date_range,custom|nullable|date',
'report_keys' => 'present|array',
'send_email' => 'required|bool',
- 'status' => 'sometimes|string|nullable|in:all,draft,sent,viewed,paid,unpaid,overdue',
+ // 'status' => 'sometimes|string|nullable|in:all,draft,sent,viewed,paid,unpaid,overdue',
];
}
diff --git a/app/Jobs/Bank/MatchBankTransactions.php b/app/Jobs/Bank/MatchBankTransactions.php
index 31c1e1538059..f2a44c60c809 100644
--- a/app/Jobs/Bank/MatchBankTransactions.php
+++ b/app/Jobs/Bank/MatchBankTransactions.php
@@ -362,7 +362,7 @@ class MatchBankTransactions implements ShouldQueue
$this->invoice
->service()
->applyNumber()
- ->touchPdf()
+ ->deletePdf()
->save();
$payment->ledger()
diff --git a/app/Jobs/Bank/ProcessBankTransactions.php b/app/Jobs/Bank/ProcessBankTransactions.php
index 9cd35817a17b..469ba5c98e49 100644
--- a/app/Jobs/Bank/ProcessBankTransactions.php
+++ b/app/Jobs/Bank/ProcessBankTransactions.php
@@ -11,17 +11,19 @@
namespace App\Jobs\Bank;
-use App\Helpers\Bank\Yodlee\Yodlee;
+use App\Models\Company;
use App\Libraries\MultiDB;
+use Illuminate\Bus\Queueable;
use App\Models\BankIntegration;
use App\Models\BankTransaction;
-use App\Models\Company;
+use App\Helpers\Bank\Yodlee\Yodlee;
+use Illuminate\Queue\SerializesModels;
+use Illuminate\Queue\InteractsWithQueue;
use App\Services\Bank\BankMatchingService;
-use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Events\Dispatchable;
-use Illuminate\Queue\InteractsWithQueue;
-use Illuminate\Queue\SerializesModels;
+use Illuminate\Queue\Middleware\WithoutOverlapping;
+use App\Notifications\Ninja\GenericNinjaAdminNotification;
class ProcessBankTransactions implements ShouldQueue
{
@@ -70,6 +72,14 @@ class ProcessBankTransactions implements ShouldQueue
$this->processTransactions();
} catch(\Exception $e) {
nlog("{$this->bank_integration_account_id} - exited abnormally => ". $e->getMessage());
+
+ $content = [
+ "Processing transactions for account: {$this->bank_integration->account->key} failed",
+ "Exception Details => ",
+ $e->getMessage(),
+ ];
+
+ $this->bank_integration->company->notification(new GenericNinjaAdminNotification($content))->ninja();
return;
}
} while ($this->stop_loop);
@@ -152,4 +162,15 @@ class ProcessBankTransactions implements ShouldQueue
$this->bank_integration->save();
}
}
+
+
+ public function middleware()
+ {
+ return [new WithoutOverlapping($this->bank_integration_account_id)];
+ }
+
+ public function backoff()
+ {
+ return [rand(10, 15), rand(30, 40), rand(60, 79), rand(160, 200), rand(3000, 5000)];
+ }
}
diff --git a/app/Jobs/Mail/NinjaMailerJob.php b/app/Jobs/Mail/NinjaMailerJob.php
index 3b8611bb3f1e..0e81d544f9be 100644
--- a/app/Jobs/Mail/NinjaMailerJob.php
+++ b/app/Jobs/Mail/NinjaMailerJob.php
@@ -243,19 +243,20 @@ class NinjaMailerJob implements ShouldQueue
case 'gmail':
$this->mailer = 'gmail';
$this->setGmailMailer();
- return;
+ return $this;
case 'office365':
+ case 'microsoft':
$this->mailer = 'office365';
$this->setOfficeMailer();
- return;
+ return $this;
case 'client_postmark':
$this->mailer = 'postmark';
$this->setPostmarkMailer();
- return;
+ return $this;
case 'client_mailgun':
$this->mailer = 'mailgun';
$this->setMailgunMailer();
- return;
+ return $this;
default:
break;
@@ -264,6 +265,8 @@ class NinjaMailerJob implements ShouldQueue
if (Ninja::isSelfHost()) {
$this->setSelfHostMultiMailer();
}
+
+ return $this;
}
/**
diff --git a/app/Jobs/Util/Import.php b/app/Jobs/Util/Import.php
index bae27f44c5c0..b45f3ead4cfa 100644
--- a/app/Jobs/Util/Import.php
+++ b/app/Jobs/Util/Import.php
@@ -11,85 +11,89 @@
namespace App\Jobs\Util;
-use App\DataMapper\Analytics\MigrationFailure;
-use App\DataMapper\CompanySettings;
-use App\Exceptions\ClientHostedMigrationException;
-use App\Exceptions\MigrationValidatorFailed;
-use App\Exceptions\ResourceDependencyMissing;
+use Exception;
+use App\Models\Task;
+use App\Models\User;
+use App\Utils\Ninja;
+use App\Models\Quote;
+use App\Models\Client;
+use App\Models\Credit;
+use App\Models\Vendor;
+use App\Models\Company;
+use App\Models\Expense;
+use App\Models\Invoice;
+use App\Models\Payment;
+use App\Models\Product;
+use App\Models\Project;
+use App\Models\TaxRate;
+use App\Models\Activity;
+use App\Models\Document;
+use App\Libraries\MultiDB;
+use App\Models\TaskStatus;
+use App\Models\PaymentTerm;
+use Illuminate\Support\Str;
+use App\Factory\UserFactory;
+use App\Factory\QuoteFactory;
+use App\Models\ClientContact;
+use Illuminate\Bus\Queueable;
use App\Factory\ClientFactory;
-use App\Factory\CompanyLedgerFactory;
use App\Factory\CreditFactory;
+use App\Factory\VendorFactory;
+use App\Models\CompanyGateway;
+use Illuminate\Support\Carbon;
use App\Factory\InvoiceFactory;
use App\Factory\PaymentFactory;
use App\Factory\ProductFactory;
-use App\Factory\QuoteFactory;
-use App\Factory\RecurringInvoiceFactory;
use App\Factory\TaxRateFactory;
-use App\Factory\UserFactory;
-use App\Factory\VendorFactory;
-use App\Http\Requests\Company\UpdateCompanyRequest;
-use App\Http\ValidationRules\ValidCompanyGatewayFeesAndLimitsRule;
-use App\Http\ValidationRules\ValidUserForCompany;
-use App\Jobs\Company\CreateCompanyToken;
-use App\Jobs\Mail\NinjaMailerJob;
-use App\Jobs\Mail\NinjaMailerObject;
-use App\Jobs\Ninja\CheckCompanyData;
-use App\Libraries\MultiDB;
-use App\Mail\Migration\StripeConnectMigration;
-use App\Mail\MigrationCompleted;
-use App\Models\Activity;
-use App\Models\Client;
-use App\Models\ClientContact;
-use App\Models\ClientGatewayToken;
-use App\Models\Company;
-use App\Models\CompanyGateway;
-use App\Models\Credit;
-use App\Models\Document;
-use App\Models\Expense;
+use App\Jobs\Util\VersionCheck;
use App\Models\ExpenseCategory;
-use App\Models\Invoice;
-use App\Models\Payment;
-use App\Models\PaymentTerm;
-use App\Models\Product;
-use App\Models\Project;
-use App\Models\Quote;
+use App\Utils\Traits\MakesHash;
+use App\Mail\MigrationCompleted;
use App\Models\RecurringExpense;
use App\Models\RecurringInvoice;
-use App\Models\Task;
-use App\Models\TaskStatus;
-use App\Models\TaxRate;
-use App\Models\User;
-use App\Models\Vendor;
-use App\Repositories\ClientContactRepository;
-use App\Repositories\ClientRepository;
-use App\Repositories\CompanyRepository;
-use App\Repositories\CreditRepository;
-use App\Repositories\Migration\InvoiceMigrationRepository;
-use App\Repositories\Migration\PaymentMigrationRepository;
-use App\Repositories\ProductRepository;
-use App\Repositories\UserRepository;
-use App\Repositories\VendorContactRepository;
-use App\Repositories\VendorRepository;
-use App\Utils\Ninja;
-use App\Utils\Traits\CleanLineItems;
-use App\Utils\Traits\CompanyGatewayFeesAndLimitsSaver;
-use App\Utils\Traits\MakesHash;
-use App\Utils\Traits\SavesDocuments;
use App\Utils\Traits\Uploadable;
-use Exception;
-use Illuminate\Bus\Queueable;
+use App\Jobs\Mail\NinjaMailerJob;
+use Illuminate\Http\UploadedFile;
+use App\Models\ClientGatewayToken;
+use Illuminate\Support\Facades\DB;
+use App\DataMapper\CompanySettings;
+use Illuminate\Support\Facades\App;
+use App\Jobs\Mail\NinjaMailerObject;
+use App\Jobs\Ninja\CheckCompanyData;
+use App\Repositories\UserRepository;
+use App\Utils\Traits\CleanLineItems;
+use App\Utils\Traits\SavesDocuments;
+use Illuminate\Support\Facades\Mail;
+use App\Factory\CompanyLedgerFactory;
+use App\Repositories\ClientRepository;
+use App\Repositories\CreditRepository;
+use App\Repositories\VendorRepository;
+use Illuminate\Queue\SerializesModels;
+use Turbo124\Beacon\Facades\LightLogs;
+use App\Repositories\CompanyRepository;
+use App\Repositories\ProductRepository;
+use App\Factory\RecurringInvoiceFactory;
+use App\Jobs\Company\CreateCompanyToken;
+use Illuminate\Queue\InteractsWithQueue;
+use Illuminate\Support\Facades\Validator;
+use Modules\Admin\Jobs\Account\NinjaUser;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
-use Illuminate\Http\UploadedFile;
-use Illuminate\Queue\InteractsWithQueue;
+use App\DataMapper\ClientRegistrationFields;
+use App\Exceptions\MigrationValidatorFailed;
+use App\Exceptions\ResourceDependencyMissing;
+use App\Repositories\ClientContactRepository;
+use App\Repositories\VendorContactRepository;
+use App\DataMapper\Analytics\MigrationFailure;
+use App\Mail\Migration\StripeConnectMigration;
+use App\Http\ValidationRules\ValidUserForCompany;
+use App\Exceptions\ClientHostedMigrationException;
+use App\Http\Requests\Company\UpdateCompanyRequest;
use Illuminate\Queue\Middleware\WithoutOverlapping;
-use Illuminate\Queue\SerializesModels;
-use Illuminate\Support\Carbon;
-use Illuminate\Support\Facades\App;
-use Illuminate\Support\Facades\Mail;
-use Illuminate\Support\Facades\Validator;
-use Illuminate\Support\Str;
-use Turbo124\Beacon\Facades\LightLogs;
+use App\Utils\Traits\CompanyGatewayFeesAndLimitsSaver;
+use App\Repositories\Migration\InvoiceMigrationRepository;
+use App\Repositories\Migration\PaymentMigrationRepository;
+use App\Http\ValidationRules\ValidCompanyGatewayFeesAndLimitsRule;
class Import implements ShouldQueue
{
@@ -135,6 +139,7 @@ class Import implements ShouldQueue
'recurring_expenses',
'tasks',
'documents',
+ 'activities',
];
/**
@@ -181,7 +186,7 @@ class Import implements ShouldQueue
public function middleware()
{
- return [(new WithoutOverlapping($this->user->account_id))];
+ return [(new WithoutOverlapping($this->company->company_key))];
}
/**
@@ -303,7 +308,7 @@ class Import implements ShouldQueue
if (round($total_invoice_payments, 2) != round($client->paid_to_date, 2)) {
$client->paid_to_date = $total_invoice_payments;
- $client->save();
+ $client->saveQuietly();
}
});
}
@@ -319,12 +324,12 @@ class Import implements ShouldQueue
$company_ledger->notes = 'Migrated Client Balance';
$company_ledger->balance = $invoice_balances;
$company_ledger->activity_id = Activity::CREATE_CLIENT;
- $company_ledger->save();
+ $company_ledger->saveQuietly();
$client->company_ledger()->save($company_ledger);
$client->balance = $invoice_balances;
- $client->save();
+ $client->saveQuietly();
});
}
@@ -1504,7 +1509,19 @@ class Import implements ShouldQueue
false
);
- $this->saveDocument($uploaded_file, $entity, $is_public = true);
+ // $this->saveDocument($uploaded_file, $entity, $is_public = true);
+
+ $document = (new \App\Jobs\Util\UploadFile(
+ $uploaded_file,
+ \App\Jobs\Util\UploadFile::DOCUMENT,
+ $this->user,
+ $this->company,
+ $entity,
+ null,
+ true
+ ))->handle();
+
+
} catch(\Exception $e) {
//do nothing, gracefully :)
}
@@ -1776,6 +1793,78 @@ class Import implements ShouldQueue
$data = null;
}
+ private function processActivities(array $data): void
+ {
+ Activity::where('company_id', $this->company->id)->cursor()->each(function ($a){
+ $a->forceDelete();
+ nlog("deleting {$a->id}");
+ });
+
+ Activity::unguard();
+
+ foreach ($data as $resource) {
+ $modified = $resource;
+
+ $modified['company_id'] = $this->company->id;
+ $modified['user_id'] = $this->processUserId($resource);
+
+try {
+ if (isset($modified['client_id'])) {
+ $modified['client_id'] = $this->transformId('clients', $resource['client_id']);
+ }
+
+ if (isset($modified['invoice_id'])) {
+ $modified['invoice_id'] = $this->transformId('invoices', $resource['invoice_id']);
+ }
+
+ if (isset($modified['quote_id'])) {
+ $modified['quote_id'] = $this->transformId('quotes', $resource['quote_id']);
+ }
+
+ if (isset($modified['recurring_invoice_id'])) {
+ $modified['recurring_invoice_id'] = $this->transformId('recurring_invoices', $resource['recurring_invoice_id']);
+ }
+
+ if (isset($modified['payment_id'])) {
+ $modified['payment_id'] = $this->transformId('payments', $resource['payment_id']);
+ }
+
+ if (isset($modified['credit_id'])) {
+ $modified['credit_id'] = $this->transformId('credits', $resource['credit_id']);
+ }
+
+ if (isset($modified['expense_id'])) {
+ $modified['expense_id'] = $this->transformId('expenses', $resource['expense_id']);
+ }
+
+ if (isset($modified['task_id'])) {
+ $modified['task_id'] = $this->transformId('tasks', $resource['task_id']);
+ }
+
+ if (isset($modified['client_contact_id'])) {
+ $modified['client_contact_id'] = $this->transformId('client_contacts', $resource['client_contact_id']);
+ }
+
+ $modified['updated_at'] = $modified['created_at'];
+
+ $act = Activity::make($modified);
+
+ $act->save(['timestamps' => false]);
+}
+catch (\Exception $e) {
+
+nlog("could not import activity: {$e->getMessage()}");
+
+}
+
+ }
+
+
+ Activity::reguard();
+
+ }
+
+
private function processExpenses(array $data) :void
{
Expense::unguard();
diff --git a/app/Jobs/Util/ReminderJob.php b/app/Jobs/Util/ReminderJob.php
index c7955d3f40e7..879b759204fd 100644
--- a/app/Jobs/Util/ReminderJob.php
+++ b/app/Jobs/Util/ReminderJob.php
@@ -126,7 +126,7 @@ class ReminderJob implements ShouldQueue
}
$reminder_template = $invoice->calculateTemplate('invoice');
- nlog("reminder template = {$reminder_template}");
+ // nlog("reminder template = {$reminder_template}");
$invoice->service()->touchReminder($reminder_template)->save();
$fees = $this->calcLateFee($invoice, $reminder_template);
@@ -208,7 +208,8 @@ class ReminderJob implements ShouldQueue
->markSent()
->save();
- $invoice->service()->touchPdf(true);
+ //30-6-2023 - fix for duplicate touching
+ // $invoice->service()->touchPdf(true);
$enabled_reminder = 'enable_'.$reminder_template;
if ($reminder_template == 'endless_reminder') {
@@ -268,7 +269,6 @@ class ReminderJob implements ShouldQueue
}
return [$late_fee_amount, $late_fee_percent];
- // return $this->setLateFee($invoice, $late_fee_amount, $late_fee_percent);
}
/**
diff --git a/app/Jobs/Util/WebhookSingle.php b/app/Jobs/Util/WebhookSingle.php
index ca6185a5c3dd..26f79e992250 100644
--- a/app/Jobs/Util/WebhookSingle.php
+++ b/app/Jobs/Util/WebhookSingle.php
@@ -122,7 +122,9 @@ class WebhookSingle implements ShouldQueue
$client = new Client(['headers' => array_merge($base_headers, $headers)]);
try {
- $response = $client->{$subscription->rest_method}($subscription->target_url, [
+ $verb = $subscription->rest_method ?? 'post';
+
+ $response = $client->{$verb}($subscription->target_url, [
RequestOptions::JSON => $data, // or 'json' => [...]
]);
diff --git a/app/Listeners/Activity/PaymentCreatedActivity.php b/app/Listeners/Activity/PaymentCreatedActivity.php
index adbacbdd88e0..ff0c0abd0889 100644
--- a/app/Listeners/Activity/PaymentCreatedActivity.php
+++ b/app/Listeners/Activity/PaymentCreatedActivity.php
@@ -38,25 +38,28 @@ class PaymentCreatedActivity implements ShouldQueue
* @return void
*/
public function handle($event)
- {
+ {
+
MultiDB::setDb($event->company->db);
$payment = $event->payment;
+ $invoice_id = null;
+
+ if($payment->invoices()->exists())
+ $invoice_id = $payment->invoices()->first()->id;
$user_id = array_key_exists('user_id', $event->event_vars) ? $event->event_vars['user_id'] : $event->payment->user_id;
- $invoices = $payment->invoices;
-
$fields = new stdClass;
$fields->payment_id = $payment->id;
+ $fields->invoice_id = $invoice_id;
$fields->client_id = $payment->client_id;
$fields->user_id = $user_id;
$fields->company_id = $payment->company_id;
$fields->activity_type_id = Activity::CREATE_PAYMENT;
- if (count($invoices) == 0) {
- $this->activity_repo->save($fields, $payment, $event->event_vars);
- }
+ $this->activity_repo->save($fields, $payment, $event->event_vars);
+
}
}
diff --git a/app/Models/Activity.php b/app/Models/Activity.php
index 679373fa0363..d0edf254e2c9 100644
--- a/app/Models/Activity.php
+++ b/app/Models/Activity.php
@@ -515,9 +515,8 @@ class Activity extends StaticModel
{
$system = ctrans('texts.system');
- return match($variable) {
- ':invoice' => $translation = [substr($variable, 1) => [ 'label' => $this?->invoice?->number ?? '', 'hashed_id' => $this->invoice?->hashed_id ?? '']],
- ':contact' => $translation = $this->resolveContact(),
+ match($variable) {
+ ':invoice' => $translation = [substr($variable, 1) => [ 'label' => $this?->invoice?->number ?? '', 'hashed_id' => $this->invoice?->hashed_id ?? '']],
':user' => $translation = [substr($variable, 1) => [ 'label' => $this?->user?->present()->name() ?? $system, 'hashed_id' => $this->user->hashed_id ?? '']],
':quote' => $translation = [substr($variable, 1) => [ 'label' => $this?->quote?->number ?? '', 'hashed_id' => $this->quote->hashed_id ?? '']],
':credit' => $translation = [substr($variable, 1) => [ 'label' => $this?->credit?->number ?? '', 'hashed_id' => $this->credit->hashed_id ?? '']],
@@ -531,6 +530,7 @@ class Activity extends StaticModel
':payment_amount' => $translation = [substr($variable, 1) =>[ 'label' => Number::formatMoney($this?->payment?->amount, $this?->payment?->client) ?? '', 'hashed_id' => '']],
':adjustment' => $translation = [substr($variable, 1) =>[ 'label' => Number::formatMoney($this?->payment?->refunded, $this?->payment?->client) ?? '', 'hashed_id' => '']],
':ip' => $translation = [ 'ip' => $this->ip ?? ''],
+ ':contact' => $translation = $this->resolveContact(),
default => $translation = [],
};
diff --git a/app/Models/BaseModel.php b/app/Models/BaseModel.php
index e33453092eeb..fc3dbface7c3 100644
--- a/app/Models/BaseModel.php
+++ b/app/Models/BaseModel.php
@@ -11,15 +11,17 @@
namespace App\Models;
+use Illuminate\Support\Str;
+use Illuminate\Support\Carbon;
+use App\Utils\Traits\MakesHash;
+use App\Jobs\Entity\CreateRawPdf;
use App\Jobs\Util\WebhookHandler;
use App\Models\Traits\Excludable;
-use App\Utils\Traits\MakesHash;
+use Illuminate\Database\Eloquent\Model;
+use App\Jobs\Vendor\CreatePurchaseOrderPdf;
use App\Utils\Traits\UserSessionAttributes;
use Illuminate\Database\Eloquent\Factories\HasFactory;
-use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\ModelNotFoundException as ModelNotFoundException;
-use Illuminate\Support\Carbon;
-use Illuminate\Support\Str;
/**
* Class BaseModel
@@ -255,4 +257,30 @@ class BaseModel extends Model
WebhookHandler::dispatch($event_id, $this, $this->company, $additional_data);
}
}
+
+ /**
+ * Returns the base64 encoded PDF string of the entity
+ */
+ public function fullscreenPdfViewer($invitation = null): string
+ {
+
+ if (! $invitation) {
+ if ($this->invitations()->exists()) {
+ $invitation = $this->invitations()->first();
+ } else {
+ $this->service()->createInvitations();
+ $invitation = $this->invitations()->first();
+ }
+ }
+
+ if (! $invitation) {
+ throw new \Exception('Hard fail, could not create an invitation.');
+ }
+
+ if($this instanceof \App\Models\PurchaseOrder)
+ return "data:application/pdf;base64,".base64_encode((new CreatePurchaseOrderPdf($invitation, $invitation->company->db))->rawPdf());
+
+ return "data:application/pdf;base64,".base64_encode((new CreateRawPdf($invitation, $invitation->company->db))->handle());
+
+ }
}
diff --git a/app/Models/Client.php b/app/Models/Client.php
index 5a4ec88f74b1..959243ccb768 100644
--- a/app/Models/Client.php
+++ b/app/Models/Client.php
@@ -544,9 +544,9 @@ 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.
+ } elseif (is_int($this->settings->{$setting})) {
return $this->settings->{$setting};
- } elseif(is_float($this->settings->{$setting})) { //10-08-2022 integer client values are not being passed back! This resolves it.
+ } elseif(is_float($this->settings->{$setting})) {
return $this->settings->{$setting};
}
}
diff --git a/app/Models/Expense.php b/app/Models/Expense.php
index 648e1d5635e9..00a16129fc9f 100644
--- a/app/Models/Expense.php
+++ b/app/Models/Expense.php
@@ -225,6 +225,11 @@ class Expense extends BaseModel
return $this->belongsTo(Company::class);
}
+ public function invoice()
+ {
+ return $this->belongsTo(Invoice::class);
+ }
+
public function vendor()
{
return $this->belongsTo(Vendor::class);
diff --git a/app/Models/Invoice.php b/app/Models/Invoice.php
index dfdf67c2691a..f390f21fc507 100644
--- a/app/Models/Invoice.php
+++ b/app/Models/Invoice.php
@@ -14,6 +14,7 @@ namespace App\Models;
use App\Utils\Ninja;
use Illuminate\Support\Carbon;
use App\Utils\Traits\MakesDates;
+use App\Jobs\Entity\CreateRawPdf;
use App\Helpers\Invoice\InvoiceSum;
use App\Jobs\Entity\CreateEntityPdf;
use App\Utils\Traits\MakesReminders;
@@ -683,6 +684,7 @@ class Invoice extends BaseModel
public function pdf_file_path($invitation = null, string $type = 'path', bool $portal = false)
{
+
if (! $invitation) {
if ($this->invitations()->exists()) {
$invitation = $this->invitations()->first();
@@ -725,7 +727,6 @@ class Invoice extends BaseModel
return Storage::disk(config('filesystems.default'))->{$type}($file_path);
}
-
try {
$file_exists = Storage::disk('public')->exists($file_path);
} catch (\Exception $e) {
diff --git a/app/Notifications/Ninja/GenericNinjaAdminNotification.php b/app/Notifications/Ninja/GenericNinjaAdminNotification.php
new file mode 100644
index 000000000000..7b40141aa22a
--- /dev/null
+++ b/app/Notifications/Ninja/GenericNinjaAdminNotification.php
@@ -0,0 +1,71 @@
+message_array as $message) {
+ $content .= $message . "\n";
+ }
+
+ return (new SlackMessage)
+ ->success()
+ ->from(ctrans('texts.notification_bot'))
+ ->image('https://app.invoiceninja.com/favicon.png')
+ ->content($content);
+ }
+}
diff --git a/app/PaymentDrivers/BaseDriver.php b/app/PaymentDrivers/BaseDriver.php
index 4bad13f054a3..4f2c6807b706 100644
--- a/app/PaymentDrivers/BaseDriver.php
+++ b/app/PaymentDrivers/BaseDriver.php
@@ -525,7 +525,7 @@ class BaseDriver extends AbstractPaymentDriver
$invoices = Invoice::whereIn('id', $this->transformKeys(array_column($this->payment_hash->invoices(), 'invoice_id')))->withTrashed()->get();
$invoices->each(function ($invoice) {
- $invoice->service()->touchPdf();
+ $invoice->service()->deletePdf();
});
$invoices->first()->invitations->each(function ($invitation) use ($nmo) {
@@ -570,7 +570,7 @@ class BaseDriver extends AbstractPaymentDriver
$invoices = Invoice::whereIn('id', $this->transformKeys(array_column($this->payment_hash->invoices(), 'invoice_id')))->withTrashed()->get();
$invoices->each(function ($invoice) {
- $invoice->service()->touchPdf();
+ $invoice->service()->deletePdf();
});
$invoices->first()->invitations->each(function ($invitation) use ($nmo) {
diff --git a/app/PaymentDrivers/Eway/CreditCard.php b/app/PaymentDrivers/Eway/CreditCard.php
index f93057719b34..969aa3ec670b 100644
--- a/app/PaymentDrivers/Eway/CreditCard.php
+++ b/app/PaymentDrivers/Eway/CreditCard.php
@@ -70,12 +70,17 @@ class CreditCard
$response = $this->eway_driver->init()->eway->createCustomer(\Eway\Rapid\Enum\ApiMethod::DIRECT, $transaction);
- $response_status = ErrorCode::getStatus($response->ResponseMessage);
+ if(property_exists($response, 'ResponseMessage'))
+ $response_status = ErrorCode::getStatus($response->ResponseMessage);
if (! $response_status['success']) {
+
$this->eway_driver->sendFailureMail($response_status['message']);
- throw new PaymentFailed($response_status['message'], 400);
+ $this->logResponse($response);
+
+
+ throw new PaymentFailed($response_status['message'] ?? 'Unknown response from gateway, please contact you merchant.', 400);
}
//success
@@ -94,6 +99,8 @@ class CreditCard
$token = $this->eway_driver->storeGatewayToken($cgt, []);
+ $this->logResponse($response);
+
return $token;
}
@@ -135,7 +142,7 @@ class CreditCard
$amount = array_sum(array_column($this->eway_driver->payment_hash->invoices(), 'amount')) + $this->eway_driver->payment_hash->fee_total;
- $description = "Invoices: {$invoice_numbers} for {$amount} for client {$this->eway_driver->client->present()->name()}";
+ // $description = "Invoices: {$invoice_numbers} for {$amount} for client {$this->eway_driver->client->present()->name()}";
$transaction = [
'Payment' => [
@@ -152,29 +159,6 @@ class CreditCard
$this->logResponse($response);
- // if(!$response || !property_exists($response, 'ResponseMessage'))
- // throw new PaymentFailed('The gateway did not return a valid response. Please check your gateway credentials.', 400);
-
- // $response_status = ErrorCode::getStatus($response->ResponseMessage);
-
- // if(!$response_status['success']){
-
- // if($response->getErrors())
- // {
- // $message = false;
-
- // foreach ($response->getErrors() as $error) {
- // $message = \Eway\Rapid::getMessage($error);
- // }
-
- // $return_message = $message ?: $response_status['message'];
- // }
-
- // $this->eway_driver->sendFailureMail($response_status['message']);
-
- // throw new PaymentFailed($response_status['message'], 400);
- // }
-
if ($response->TransactionStatus) {
$payment = $this->storePayment($response);
} else {
diff --git a/app/PaymentDrivers/PayTrace/CreditCard.php b/app/PaymentDrivers/PayTrace/CreditCard.php
index a07f17e5ea4e..720d5f0b02be 100644
--- a/app/PaymentDrivers/PayTrace/CreditCard.php
+++ b/app/PaymentDrivers/PayTrace/CreditCard.php
@@ -123,6 +123,7 @@ class CreditCard
'city' => $this->paytrace->client->city,
'state' => $this->paytrace->client->state,
'zip' => $this->paytrace->client->postal_code,
+ 'country' => $this->paytrace->client->country->iso_3166_2
];
return $data;
@@ -177,6 +178,7 @@ class CreditCard
'customer_id' => $token,
'integrator_id' => $this->paytrace->company_gateway->getConfigField('integratorId'),
'amount' => $request->input('amount_with_fee'),
+ 'invoice_id' => $this->harvestInvoiceId(),
];
$response = $this->paytrace->gatewayRequest('/v1/transactions/sale/by_customer', $data);
diff --git a/app/PaymentDrivers/Stripe/iDeal.php b/app/PaymentDrivers/Stripe/iDeal.php
index 5353181676e4..3e0c49cc7cab 100644
--- a/app/PaymentDrivers/Stripe/iDeal.php
+++ b/app/PaymentDrivers/Stripe/iDeal.php
@@ -106,7 +106,7 @@ class iDeal
'gateway_type_id' => GatewayType::IDEAL,
];
- $this->stripe->createPayment($data, Payment::STATUS_PENDING);
+ $this->stripe->createPayment($data, Payment::STATUS_COMPLETED);
SystemLogger::dispatch(
['response' => $this->stripe->payment_hash->data, 'data' => $data],
diff --git a/app/Repositories/PaymentRepository.php b/app/Repositories/PaymentRepository.php
index 0b4be3c46880..073f04fd7cec 100644
--- a/app/Repositories/PaymentRepository.php
+++ b/app/Repositories/PaymentRepository.php
@@ -185,7 +185,7 @@ class PaymentRepository extends BaseRepository
$paymentable->payment_id = $payment->id;
$paymentable->paymentable_id = $credit->id;
$paymentable->paymentable_type = Credit::class;
- $paymentable->amount = $paid_invoice['amount'];
+ $paymentable->amount = $paid_credit['amount'];
$paymentable->save();
$credit = $credit->service()->markSent()->save();
diff --git a/app/Repositories/TaskStatusRepository.php b/app/Repositories/TaskStatusRepository.php
index 4cadccd4d645..c3702136056c 100644
--- a/app/Repositories/TaskStatusRepository.php
+++ b/app/Repositories/TaskStatusRepository.php
@@ -38,13 +38,15 @@ class TaskStatusRepository extends BaseRepository
public function archive($task_status)
{
- $task_status = TaskStatus::where('id', $task_status->id)
+ $task_status = TaskStatus::withTrashed()
+ ->where('id', $task_status->id)
->where('company_id', $task_status->company_id)
->first();
$new_status = $task_status ? $task_status->id : null;
- Task::where('status_id', $task_status->id)
+ Task::withTrashed()
+ ->where('status_id', $task_status->id)
->where('company_id', $task_status->company_id)
->update(['status_id' => $new_status]);
diff --git a/app/Services/Chart/ChartService.php b/app/Services/Chart/ChartService.php
index c9a8be50eda7..3378c998aeec 100644
--- a/app/Services/Chart/ChartService.php
+++ b/app/Services/Chart/ChartService.php
@@ -76,6 +76,8 @@ class ChartService
$currencies = $this->getCurrencyCodes();
$data = [];
+ $data['start_date'] = $start_date;
+ $data['end_date'] = $end_date;
foreach ($currencies as $key => $value) {
$data[$key]['invoices'] = $this->getInvoiceChartQuery($start_date, $end_date, $key);
@@ -97,6 +99,9 @@ class ChartService
$data['currencies'] = $this->getCurrencyCodes();
+ $data['start_date'] = $start_date;
+ $data['end_date'] = $end_date;
+
$revenue = $this->getRevenue($start_date, $end_date);
$outstanding = $this->getOutstanding($start_date, $end_date);
$expenses = $this->getExpenses($start_date, $end_date);
diff --git a/app/Services/Credit/ApplyPayment.php b/app/Services/Credit/ApplyPayment.php
index 0f8af8b4aef7..70639ce02001 100644
--- a/app/Services/Credit/ApplyPayment.php
+++ b/app/Services/Credit/ApplyPayment.php
@@ -137,7 +137,7 @@ class ApplyPayment
->updateBalance($this->amount_applied * -1)
->updatePaidToDate($this->amount_applied)
->updateStatus()
- ->touchPdf()
+ ->deletePdf()
->save();
$this->credit
@@ -147,7 +147,7 @@ class ApplyPayment
event(new InvoiceWasUpdated($this->invoice, $this->invoice->company, Ninja::eventVars(auth()->user() ? auth()->user()->id : null)));
if ((int) $this->invoice->balance == 0) {
- $this->invoice->service()->touchPdf();
+ $this->invoice->service()->deletePdf();
$this->invoice = $this->invoice->fresh();
event(new InvoiceWasPaid($this->invoice, $this->payment, $this->payment->company, Ninja::eventVars(auth()->user() ? auth()->user()->id : null)));
}
diff --git a/app/Services/Credit/CreditService.php b/app/Services/Credit/CreditService.php
index ccc61a03d555..811ea7e4cf45 100644
--- a/app/Services/Credit/CreditService.php
+++ b/app/Services/Credit/CreditService.php
@@ -11,15 +11,17 @@
namespace App\Services\Credit;
-use App\Factory\PaymentFactory;
-use App\Jobs\Entity\CreateEntityPdf;
-use App\Jobs\Util\UnlinkFile;
+use App\Utils\Ninja;
use App\Models\Credit;
use App\Models\Payment;
use App\Models\PaymentType;
+use App\Jobs\Util\UnlinkFile;
+use App\Factory\PaymentFactory;
+use App\Utils\Traits\MakesHash;
+use App\Jobs\Entity\CreateEntityPdf;
use App\Repositories\CreditRepository;
use App\Repositories\PaymentRepository;
-use App\Utils\Traits\MakesHash;
+use Illuminate\Support\Facades\Storage;
class CreditService
{
@@ -235,7 +237,24 @@ class CreditService
public function deletePdf()
{
$this->credit->invitations->each(function ($invitation) {
- (new UnlinkFile(config('filesystems.default'), $this->credit->client->credit_filepath($invitation).$this->credit->numberFormatter().'.pdf'))->handle();
+ // (new UnlinkFile(config('filesystems.default'), $this->credit->client->credit_filepath($invitation).$this->credit->numberFormatter().'.pdf'))->handle();
+
+ //30-06-2023
+ try {
+ // if (Storage::disk(config('filesystems.default'))->exists($this->invoice->client->invoice_filepath($invitation).$this->invoice->numberFormatter().'.pdf')) {
+ Storage::disk(config('filesystems.default'))->delete($this->credit->client->credit_filepath($invitation).$this->credit->numberFormatter().'.pdf');
+ // }
+
+ // if (Ninja::isHosted() && Storage::disk('public')->exists($this->invoice->client->invoice_filepath($invitation).$this->invoice->numberFormatter().'.pdf')) {
+ if (Ninja::isHosted()) {
+ Storage::disk('public')->delete($this->credit->client->credit_filepath($invitation).$this->credit->numberFormatter().'.pdf');
+ }
+ } catch (\Exception $e) {
+ nlog($e->getMessage());
+ }
+
+
+
});
return $this;
diff --git a/app/Services/Credit/MarkSent.php b/app/Services/Credit/MarkSent.php
index 3402a019aab9..890f6887c741 100644
--- a/app/Services/Credit/MarkSent.php
+++ b/app/Services/Credit/MarkSent.php
@@ -42,7 +42,7 @@ class MarkSent
->setStatus(Credit::STATUS_SENT)
->applyNumber()
->adjustBalance($this->credit->amount)
- ->touchPdf()
+ ->deletePdf()
->save();
$this->client
diff --git a/app/Services/Email/Email.php b/app/Services/Email/Email.php
index ac606a0b2e9e..4a9663ea43f4 100644
--- a/app/Services/Email/Email.php
+++ b/app/Services/Email/Email.php
@@ -432,6 +432,7 @@ class Email implements ShouldQueue
$this->setGmailMailer();
return $this;
case 'office365':
+ case 'microsoft':
$this->mailer = 'office365';
$this->setOfficeMailer();
return $this;
@@ -445,7 +446,8 @@ class Email implements ShouldQueue
return $this;
default:
- break;
+ $this->mailer = config('mail.default');
+ return $this;
}
if (Ninja::isSelfHost()) {
diff --git a/app/Services/Email/EmailDefaults.php b/app/Services/Email/EmailDefaults.php
index d17ebd8b41f5..9d225c4cc310 100644
--- a/app/Services/Email/EmailDefaults.php
+++ b/app/Services/Email/EmailDefaults.php
@@ -307,9 +307,6 @@ class EmailDefaults
$xinvoice_path = $this->email->email_object->entity->service()->getEInvoice();
- // $xinvoice_path = (new CreateEInvoice($this->email->email_object->entity, true, stream_get_meta_data($tempfile)['uri']))->handle();
- // $this->email->email_object->attachments = array_merge($this->email->email_object->attachments, [['file' => base64_encode($pdf), 'name' => $this->email->email_object->entity->numberFormatter().'.pdf']]);
-
if(Storage::disk(config('filesystems.default'))->exists($xinvoice_path))
$this->email->email_object->attachments = array_merge($this->email->email_object->attachments, [['file' => base64_encode(Storage::get($xinvoice_path)), 'name' => explode(".", $this->email->email_object->entity->getFileName('xml'))[0]."-xinvoice.xml"]]);
diff --git a/app/Services/Invoice/ApplyPayment.php b/app/Services/Invoice/ApplyPayment.php
index 542e871876b4..a0a2fb5f83fd 100644
--- a/app/Services/Invoice/ApplyPayment.php
+++ b/app/Services/Invoice/ApplyPayment.php
@@ -92,7 +92,7 @@ class ApplyPayment extends AbstractService
}
});
- $this->invoice->service()->applyNumber()->workFlow()->touchPdf()->save();
+ $this->invoice->service()->applyNumber()->workFlow()->deletePdf()->save();
return $this->invoice;
}
diff --git a/app/Services/Invoice/HandleCancellation.php b/app/Services/Invoice/HandleCancellation.php
index fe83909e3e36..2fcd20013fee 100644
--- a/app/Services/Invoice/HandleCancellation.php
+++ b/app/Services/Invoice/HandleCancellation.php
@@ -44,9 +44,7 @@ class HandleCancellation extends AbstractService
$this->invoice->balance = 0;
$this->invoice = $this->invoice->service()->setStatus(Invoice::STATUS_CANCELLED)->save();
- //adjust client balance
$this->invoice->client->service()->updateBalance($adjustment)->save();
- // $this->invoice->fresh();
$this->invoice->service()->workFlow()->save();
@@ -54,16 +52,6 @@ class HandleCancellation extends AbstractService
event('eloquent.updated: App\Models\Invoice', $this->invoice);
- $transaction = [
- 'invoice' => $this->invoice->transaction_event(),
- 'payment' => [],
- 'client' => $this->invoice->client->transaction_event(),
- 'credit' => [],
- 'metadata' => [],
- ];
-
- // TransactionLog::dispatch(TransactionEvent::INVOICE_CANCELLED, $transaction, $this->invoice->company->db);
-
return $this->invoice;
}
diff --git a/app/Services/Invoice/InvoiceService.php b/app/Services/Invoice/InvoiceService.php
index f0dc04a88a26..d5a0715ee7d2 100644
--- a/app/Services/Invoice/InvoiceService.php
+++ b/app/Services/Invoice/InvoiceService.php
@@ -115,7 +115,6 @@ class InvoiceService
*/
public function applyPayment(Payment $payment, float $payment_amount)
{
- // $this->deletePdf();
$this->invoice = $this->markSent()->save();
$this->invoice = (new ApplyPayment($this->invoice, $payment, $payment_amount))->run();
@@ -339,7 +338,7 @@ class InvoiceService
return $item;
})->toArray();
- $this->touchPdf();
+ $this->deletePdf();
return $this;
}
@@ -348,13 +347,15 @@ class InvoiceService
{
$this->invoice->load('invitations');
+ //30-06-2023
$this->invoice->invitations->each(function ($invitation) {
try {
- if (Storage::disk(config('filesystems.default'))->exists($this->invoice->client->invoice_filepath($invitation).$this->invoice->numberFormatter().'.pdf')) {
+ // if (Storage::disk(config('filesystems.default'))->exists($this->invoice->client->invoice_filepath($invitation).$this->invoice->numberFormatter().'.pdf')) {
Storage::disk(config('filesystems.default'))->delete($this->invoice->client->invoice_filepath($invitation).$this->invoice->numberFormatter().'.pdf');
- }
+ // }
- if (Ninja::isHosted() && Storage::disk('public')->exists($this->invoice->client->invoice_filepath($invitation).$this->invoice->numberFormatter().'.pdf')) {
+ // if (Ninja::isHosted() && Storage::disk('public')->exists($this->invoice->client->invoice_filepath($invitation).$this->invoice->numberFormatter().'.pdf')) {
+ if (Ninja::isHosted()) {
Storage::disk('public')->delete($this->invoice->client->invoice_filepath($invitation).$this->invoice->numberFormatter().'.pdf');
}
} catch (\Exception $e) {
@@ -371,11 +372,12 @@ class InvoiceService
$this->invoice->invitations->each(function ($invitation) {
try {
- if (Storage::disk(config('filesystems.default'))->exists($this->invoice->client->e_invoice_filepath($invitation).$this->invoice->getFileName("xml"))) {
+ // if (Storage::disk(config('filesystems.default'))->exists($this->invoice->client->e_invoice_filepath($invitation).$this->invoice->getFileName("xml"))) {
Storage::disk(config('filesystems.default'))->delete($this->invoice->client->e_invoice_filepath($invitation).$this->invoice->getFileName("xml"));
- }
+ // }
- if (Ninja::isHosted() && Storage::disk('public')->exists($this->invoice->client->e_invoice_filepath($invitation).$this->invoice->getFileName("xml"))) {
+ // if (Ninja::isHosted() && Storage::disk('public')->exists($this->invoice->client->e_invoice_filepath($invitation).$this->invoice->getFileName("xml"))) {
+ if (Ninja::isHosted()) {
Storage::disk('public')->delete($this->invoice->client->e_invoice_filepath($invitation).$this->invoice->getFileName("xml"));
}
} catch (\Exception $e) {
@@ -403,7 +405,7 @@ class InvoiceService
})->toArray();
$this->invoice = $this->invoice->calc()->getInvoice();
- $this->touchPdf();
+ $this->deletePdf();
/* 24-03-2022 */
$new_balance = $this->invoice->balance;
diff --git a/app/Services/Invoice/MarkPaid.php b/app/Services/Invoice/MarkPaid.php
index a056da4b6038..6b2c515a97cb 100644
--- a/app/Services/Invoice/MarkPaid.php
+++ b/app/Services/Invoice/MarkPaid.php
@@ -102,7 +102,7 @@ class MarkPaid extends AbstractService
$this->invoice
->service()
->applyNumber()
- ->touchPdf()
+ ->deletePdf()
->save();
$payment->ledger()
diff --git a/app/Services/Invoice/TriggeredActions.php b/app/Services/Invoice/TriggeredActions.php
index 7c6e7c4f6ad9..3dae6339b743 100644
--- a/app/Services/Invoice/TriggeredActions.php
+++ b/app/Services/Invoice/TriggeredActions.php
@@ -54,7 +54,7 @@ class TriggeredActions extends AbstractService
}
if ($this->request->has('send_email') && $this->request->input('send_email') == 'true') {
- $this->invoice->service()->markSent()->touchPdf()->save();
+ $this->invoice->service()->markSent()->save();
$this->sendEmail();
$this->updated = false;
}
diff --git a/app/Services/Payment/UpdateInvoicePayment.php b/app/Services/Payment/UpdateInvoicePayment.php
index 4f088eacfc9f..882cba3e95bd 100644
--- a/app/Services/Payment/UpdateInvoicePayment.php
+++ b/app/Services/Payment/UpdateInvoicePayment.php
@@ -79,7 +79,7 @@ class UpdateInvoicePayment
$invoice = $invoice->service()
->clearPartial()
->updateStatus()
- ->touchPdf()
+ ->deletePdf()
->workFlow()
->save();
diff --git a/app/Services/Pdf/PdfBuilder.php b/app/Services/Pdf/PdfBuilder.php
index 39775948626a..78d8d38fb2a9 100644
--- a/app/Services/Pdf/PdfBuilder.php
+++ b/app/Services/Pdf/PdfBuilder.php
@@ -653,7 +653,7 @@ class PdfBuilder
$data[$key][$table_type.".{$_table_type}4"] = strlen($item->custom_value4) >= 1 ? $helpers->formatCustomFieldValue($this->service->company->custom_fields, "{$_table_type}4", $item->custom_value4, $this->service->config->currency_entity) : '';
if ($item->quantity > 0 || $item->cost > 0) {
- $data[$key][$table_type.'.quantity'] = $this->service->config->formatMoney($item->quantity);
+ $data[$key][$table_type.'.quantity'] = $item->quantity;
$data[$key][$table_type.'.unit_cost'] = $this->service->config->formatMoney($item->cost);
diff --git a/app/Services/Pdf/PdfMock.php b/app/Services/Pdf/PdfMock.php
index 8c569ed0323f..06a572c0680d 100644
--- a/app/Services/Pdf/PdfMock.php
+++ b/app/Services/Pdf/PdfMock.php
@@ -232,6 +232,9 @@ class PdfMock
'$secondary_font_url' => 'https://fonts.googleapis.com/css2?family=Roboto&display=swap',
'$contact.signature' => '',
'$company_logo_size' => $this->settings->company_logo_size ?: '65%',
+ '$product.tax_rate1' => ctrans('texts.tax'),
+ '$product.tax_rate2' => ctrans('texts.tax'),
+ '$product.tax_rate3' => ctrans('texts.tax'),
'$product.tax_name1' => '',
'$product.tax_name2' => '',
'$product.tax_name3' => '',
@@ -688,8 +691,11 @@ class PdfMock
'$net_subtotal_label' => ctrans('texts.net_subtotal'),
'$credit.total_label' => ctrans('texts.total'),
'$quote.amount_label' => ctrans('texts.amount'),
- '$description_label' => ctrans('texts.description'),
+ '$product.tax_rate1_label' => ctrans('texts.tax'),
+ '$product.tax_rate2_label' => ctrans('texts.tax'),
+ '$product.tax_rate3_label' => ctrans('texts.tax'),
'$product.tax_label' => ctrans('texts.tax'),
+ '$description_label' => ctrans('texts.description'),
'$your_entity_label' => ctrans("texts.your_{$this->entity_string}"),
'$view_button_label' => ctrans('texts.view'),
'$status_logo_label' => ctrans('texts.logo'),
@@ -782,9 +788,9 @@ class PdfMock
'$amount_label' => ctrans('texts.amount'),
'$notes_label' => ctrans('texts.notes'),
'$terms_label' => ctrans('texts.terms'),
- 'tax_rate1_label' => ctrans('texts.tax_rate1'),
- 'tax_rate2_label' => ctrans('texts.tax_rate2'),
- 'tax_rate3_label' => ctrans('texts.tax_rate3'),
+ '$tax_rate1_label' => ctrans('texts.tax_rate1'),
+ '$tax_rate2_label' => ctrans('texts.tax_rate2'),
+ '$tax_rate3_label' => ctrans('texts.tax_rate3'),
'$phone_label' => ctrans('texts.phone'),
'$email_label' => ctrans('texts.email'),
'$taxes_label' => ctrans('texts.taxes'),
diff --git a/app/Services/PurchaseOrder/GetPurchaseOrderPdf.php b/app/Services/PurchaseOrder/GetPurchaseOrderPdf.php
index dde550a269c7..40044b90b6e5 100644
--- a/app/Services/PurchaseOrder/GetPurchaseOrderPdf.php
+++ b/app/Services/PurchaseOrder/GetPurchaseOrderPdf.php
@@ -19,11 +19,8 @@ use Illuminate\Support\Facades\Storage;
class GetPurchaseOrderPdf extends AbstractService
{
- public function __construct(PurchaseOrder $purchase_order, VendorContact $contact = null)
+ public function __construct(public PurchaseOrder $purchase_order, public ?VendorContact $contact = null)
{
- $this->purchase_order = $purchase_order;
-
- $this->contact = $contact;
}
public function run()
diff --git a/app/Services/PurchaseOrder/TriggeredActions.php b/app/Services/PurchaseOrder/TriggeredActions.php
index 02e9e0bdc871..38510fc70962 100644
--- a/app/Services/PurchaseOrder/TriggeredActions.php
+++ b/app/Services/PurchaseOrder/TriggeredActions.php
@@ -43,10 +43,6 @@ class TriggeredActions extends AbstractService
$this->purchase_order = $this->purchase_order->service()->markSent()->touchPdf()->save();
}
- // if ($this->request->has('cancel') && $this->request->input('cancel') == 'true') {
- // $this->purchase_order = $this->purchase_order->service()->handleCancellation()->save();
- // }
-
if ($this->request->has('save_default_footer') && $this->request->input('save_default_footer') == 'true') {
$company = $this->purchase_order->company;
$settings = $company->settings;
diff --git a/app/Services/Quote/MarkSent.php b/app/Services/Quote/MarkSent.php
index fa9c75a565b9..9969cbfc3f41 100644
--- a/app/Services/Quote/MarkSent.php
+++ b/app/Services/Quote/MarkSent.php
@@ -47,7 +47,7 @@ class MarkSent
->service()
->setStatus(Quote::STATUS_SENT)
->applyNumber()
- ->touchPdf()
+ ->deletePdf()
->save();
event(new QuoteWasMarkedSent($this->quote, $this->quote->company, Ninja::eventVars(auth()->user() ? auth()->user()->id : null)));
diff --git a/app/Services/Quote/QuoteService.php b/app/Services/Quote/QuoteService.php
index 56ab95d8eb38..45b38cc0b52b 100644
--- a/app/Services/Quote/QuoteService.php
+++ b/app/Services/Quote/QuoteService.php
@@ -11,14 +11,15 @@
namespace App\Services\Quote;
-use App\Events\Quote\QuoteWasApproved;
-use App\Jobs\Entity\CreateEntityPdf;
-use App\Jobs\Util\UnlinkFile;
-use App\Models\Invoice;
-use App\Models\Quote;
-use App\Repositories\QuoteRepository;
use App\Utils\Ninja;
+use App\Models\Quote;
+use App\Jobs\Util\UnlinkFile;
use App\Utils\Traits\MakesHash;
+use App\Exceptions\QuoteConversion;
+use App\Jobs\Entity\CreateEntityPdf;
+use App\Repositories\QuoteRepository;
+use App\Events\Quote\QuoteWasApproved;
+use Illuminate\Support\Facades\Storage;
class QuoteService
{
@@ -43,7 +44,7 @@ class QuoteService
public function convert() :self
{
if ($this->quote->invoice_id) {
- return $this;
+ throw new QuoteConversion();
}
$convert_quote = (new ConvertQuote($this->quote->client))->run($this->quote);
@@ -115,7 +116,7 @@ class QuoteService
$this->invoice
->service()
->markSent()
- ->touchPdf()
+ ->deletePdf()
->save();
}
@@ -224,7 +225,22 @@ class QuoteService
public function deletePdf()
{
$this->quote->invitations->each(function ($invitation) {
- (new UnlinkFile(config('filesystems.default'), $this->quote->client->quote_filepath($invitation).$this->quote->numberFormatter().'.pdf'))->handle();
+ // (new UnlinkFile(config('filesystems.default'), $this->quote->client->quote_filepath($invitation).$this->quote->numberFormatter().'.pdf'))->handle();
+
+ //30-06-2023
+ try {
+ // if (Storage::disk(config('filesystems.default'))->exists($this->invoice->client->invoice_filepath($invitation).$this->invoice->numberFormatter().'.pdf')) {
+ Storage::disk(config('filesystems.default'))->delete($this->quote->client->quote_filepath($invitation).$this->quote->numberFormatter().'.pdf');
+ // }
+
+ // if (Ninja::isHosted() && Storage::disk('public')->exists($this->invoice->client->invoice_filepath($invitation).$this->invoice->numberFormatter().'.pdf')) {
+ if (Ninja::isHosted()) {
+ Storage::disk('public')->delete($this->quote->client->quote_filepath($invitation).$this->quote->numberFormatter().'.pdf');
+ }
+ } catch (\Exception $e) {
+ nlog($e->getMessage());
+ }
+
});
return $this;
diff --git a/app/Services/Recurring/RecurringService.php b/app/Services/Recurring/RecurringService.php
index c962b5f45f45..721b94dcd183 100644
--- a/app/Services/Recurring/RecurringService.php
+++ b/app/Services/Recurring/RecurringService.php
@@ -11,11 +11,13 @@
namespace App\Services\Recurring;
+use App\Utils\Ninja;
use App\Jobs\Util\UnlinkFile;
use App\Models\RecurringQuote;
use Illuminate\Support\Carbon;
use App\Models\RecurringExpense;
use App\Models\RecurringInvoice;
+use Illuminate\Support\Facades\Storage;
use App\Jobs\RecurringInvoice\SendRecurring;
class RecurringService
@@ -88,7 +90,22 @@ class RecurringService
public function deletePdf()
{
$this->recurring_entity->invitations->each(function ($invitation) {
- (new UnlinkFile(config('filesystems.default'), $this->recurring_entity->client->recurring_invoice_filepath($invitation) . $this->recurring_entity->numberFormatter().'.pdf'))->handle();
+ // (new UnlinkFile(config('filesystems.default'), $this->recurring_entity->client->recurring_invoice_filepath($invitation) . $this->recurring_entity->numberFormatter().'.pdf'))->handle();
+
+ //30-06-2023
+ try {
+ Storage::disk(config('filesystems.default'))->delete($this->recurring_entity->client->recurring_invoice_filepath($invitation) . $this->recurring_entity->numberFormatter().'.pdf');
+ // if (Storage::disk(config('filesystems.default'))->exists($this->invoice->client->invoice_filepath($invitation).$this->invoice->numberFormatter().'.pdf')) {
+ // }
+
+ // if (Ninja::isHosted() && Storage::disk('public')->exists($this->invoice->client->invoice_filepath($invitation).$this->invoice->numberFormatter().'.pdf')) {
+ Storage::disk('public')->delete($this->recurring_entity->client->recurring_invoice_filepath($invitation) . $this->recurring_entity->numberFormatter().'.pdf');
+ if (Ninja::isHosted()) {
+ }
+ } catch (\Exception $e) {
+ nlog($e->getMessage());
+ }
+
});
diff --git a/app/Services/Scheduler/EmailReport.php b/app/Services/Scheduler/EmailReport.php
index ce76e54fad04..f1def5d9b61c 100644
--- a/app/Services/Scheduler/EmailReport.php
+++ b/app/Services/Scheduler/EmailReport.php
@@ -58,7 +58,8 @@ class EmailReport
public function run()
{
- $start_end_dates = $this->calculateStartAndEndDates();
+ $start_end_dates = $this->calculateStartAndEndDates($this->scheduler->parameters);
+
$data = [];
$data = [
diff --git a/app/Services/Subscription/SubscriptionService.php b/app/Services/Subscription/SubscriptionService.php
index 955e567f62f1..782f08446b6a 100644
--- a/app/Services/Subscription/SubscriptionService.php
+++ b/app/Services/Subscription/SubscriptionService.php
@@ -188,7 +188,7 @@ class SubscriptionService
//update the invoice and attach to the recurring invoice!!!!!
$invoice->recurring_id = $recurring_invoice->id;
$invoice->is_proforma = false;
- $invoice->service()->touchPdf();
+ $invoice->service()->deletePdf();
$invoice->save();
$contact = $invoice->client->contacts()->whereNotNull('email')->first();
@@ -821,13 +821,15 @@ class SubscriptionService
$invoice->is_proforma = false;
$invoice->save();
+ // 29-06-2023 handle webhooks for payment intent - user may not be present.
+
$context = [
'context' => 'change_plan',
'recurring_invoice' => $recurring_invoice->hashed_id,
'invoice' => $this->encodePrimaryKey($payment_hash->fee_invoice_id),
'client' => $recurring_invoice->client->hashed_id,
'subscription' => $this->subscription->hashed_id,
- 'contact' => auth()->guard('contact')->user()->hashed_id,
+ 'contact' => auth()->guard('contact')->user()?->hashed_id ?? $recurring_invoice->client->contacts()->first()->hashed_id,
'account_key' => $recurring_invoice->client->custom_value2,
];
diff --git a/app/Services/Tax/Providers/ZipTax.php b/app/Services/Tax/Providers/ZipTax.php
index 0cc0dd1a5524..dad7ef0768fc 100644
--- a/app/Services/Tax/Providers/ZipTax.php
+++ b/app/Services/Tax/Providers/ZipTax.php
@@ -69,7 +69,7 @@ class ZipTax implements TaxProviderInterface
private function parseResponse($response)
{
- if(isset($response['rCode']) && $response['rCode'] == 100)
+ if(isset($response['rCode']) && $response['rCode'] == 100 && isset($response['results']['0']))
return $response['results']['0'];
if(isset($response['rCode']) && class_exists(\Modules\Admin\Events\TaxProviderException::class))
diff --git a/app/Transformers/CompanyTransformer.php b/app/Transformers/CompanyTransformer.php
index 0d6241ca8c17..32f4966ba1b6 100644
--- a/app/Transformers/CompanyTransformer.php
+++ b/app/Transformers/CompanyTransformer.php
@@ -203,6 +203,7 @@ class CompanyTransformer extends EntityTransformer
'has_e_invoice_certificate_passphrase' => $company->e_invoice_certificate_passphrase ? true : false,
'invoice_task_project_header' => (bool) $company->invoice_task_project_header,
'invoice_task_item_description' => (bool) $company->invoice_task_item_description,
+ 'origin_tax_data' => $company->origin_tax_data ?: new \stdClass,
];
}
diff --git a/app/Transformers/ExpenseTransformer.php b/app/Transformers/ExpenseTransformer.php
index f703da58058a..48a3ed7c4a7d 100644
--- a/app/Transformers/ExpenseTransformer.php
+++ b/app/Transformers/ExpenseTransformer.php
@@ -11,12 +11,15 @@
namespace App\Transformers;
-use App\Models\Document;
-use App\Models\Expense;
use App\Models\Vendor;
+use App\Models\Expense;
+use App\Models\Invoice;
+use App\Models\ExpenseCategory;
+use App\Transformers\ExpenseCategoryTransformer;
+use App\Models\Document;
use App\Utils\Traits\MakesHash;
-use Illuminate\Database\Eloquent\SoftDeletes;
use League\Fractal\Resource\Item;
+use Illuminate\Database\Eloquent\SoftDeletes;
/**
* class ExpenseTransformer.
@@ -36,6 +39,8 @@ class ExpenseTransformer extends EntityTransformer
protected $availableIncludes = [
'client',
'vendor',
+ 'category',
+ 'invoice',
];
public function includeDocuments(Expense $expense)
@@ -56,6 +61,28 @@ class ExpenseTransformer extends EntityTransformer
return $this->includeItem($expense->client, $transformer, Client::class);
}
+ public function includeInvoice(Expense $expense): ?Item
+ {
+ $transformer = new InvoiceTransformer($this->serializer);
+
+ if (!$expense->invoice) {
+ return null;
+ }
+
+ return $this->includeItem($expense->invoice, $transformer, Invoice::class);
+ }
+
+ public function includeCategory(Expense $expense): ?Item
+ {
+ $transformer = new ExpenseCategoryTransformer($this->serializer);
+
+ if (!$expense->category) {
+ return null;
+ }
+
+ return $this->includeItem($expense->category, $transformer, ExpenseCategory::class);
+ }
+
public function includeVendor(Expense $expense): ?Item
{
$transformer = new VendorTransformer($this->serializer);
diff --git a/app/Utils/Traits/MakesDates.php b/app/Utils/Traits/MakesDates.php
index f63977932db2..caea8e926d64 100644
--- a/app/Utils/Traits/MakesDates.php
+++ b/app/Utils/Traits/MakesDates.php
@@ -119,9 +119,9 @@ trait MakesDates
*
* @return array [$start_date, $end_date];
*/
- public function calculateStartAndEndDates(): array
+ public function calculateStartAndEndDates(array $data): array
{
- return match ($this->scheduler->parameters['date_range']) {
+ return match ($data['date_range']) {
EmailStatement::LAST7 => [now()->startOfDay()->subDays(7)->format('Y-m-d'), now()->startOfDay()->format('Y-m-d')],
EmailStatement::LAST30 => [now()->startOfDay()->subDays(30)->format('Y-m-d'), now()->startOfDay()->format('Y-m-d')],
EmailStatement::LAST365 => [now()->startOfDay()->subDays(365)->format('Y-m-d'), now()->startOfDay()->format('Y-m-d')],
@@ -131,9 +131,9 @@ trait MakesDates
EmailStatement::LAST_QUARTER => [now()->startOfDay()->subQuarterNoOverflow()->firstOfQuarter()->format('Y-m-d'), now()->startOfDay()->subQuarterNoOverflow()->lastOfQuarter()->format('Y-m-d')],
EmailStatement::THIS_YEAR => [now()->startOfDay()->firstOfYear()->format('Y-m-d'), now()->startOfDay()->lastOfYear()->format('Y-m-d')],
EmailStatement::LAST_YEAR => [now()->startOfDay()->subYearNoOverflow()->firstOfYear()->format('Y-m-d'), now()->startOfDay()->subYearNoOverflow()->lastOfYear()->format('Y-m-d')],
- EmailStatement::CUSTOM_RANGE => [$this->scheduler->parameters['start_date'], $this->scheduler->parameters['end_date']],
+ EmailStatement::CUSTOM_RANGE => [$data['start_date'], $data['end_date']],
default => [now()->startOfDay()->firstOfMonth()->format('Y-m-d'), now()->startOfDay()->lastOfMonth()->format('Y-m-d')],
};
}
-}
+}
\ No newline at end of file
diff --git a/config/ninja.php b/config/ninja.php
index 482d0131229a..86642783a8a0 100644
--- a/config/ninja.php
+++ b/config/ninja.php
@@ -15,8 +15,8 @@ return [
'require_https' => env('REQUIRE_HTTPS', true),
'app_url' => rtrim(env('APP_URL', ''), '/'),
'app_domain' => env('APP_DOMAIN', 'invoicing.co'),
- 'app_version' => '5.6.4',
- 'app_tag' => '5.6.4',
+ 'app_version' => '5.6.5',
+ 'app_tag' => '5.6.5',
'minimum_client_version' => '5.0.16',
'terms_version' => '1.0.1',
'api_secret' => env('API_SECRET', ''),
diff --git a/database/migrations/2023_04_27_045639_add_kmher_language.php b/database/migrations/2023_04_27_045639_add_kmher_language.php
index 9d2d7a994f95..69e7fb433cb3 100644
--- a/database/migrations/2023_04_27_045639_add_kmher_language.php
+++ b/database/migrations/2023_04_27_045639_add_kmher_language.php
@@ -25,9 +25,12 @@ return new class extends Migration
Language::create(['id' => 38, 'name' => 'Khmer', 'locale' => 'km_KH']);
}
- Schema::table('companies', function (Blueprint $table) {
- $table->dropColumn('enable_e_invoice');
- });
+ if (Schema::hasColumn('companies', 'enable_e_invoice'))
+ {
+ Schema::table('companies', function (Blueprint $table) {
+ $table->dropColumn('enable_e_invoice');
+ });
+ }
Company::query()->cursor()->each(function ($company){
$company->tax_data = new TaxModel();
diff --git a/lang/en/texts.php b/lang/en/texts.php
index aa92fb260bf5..8d7f8c01f0be 100644
--- a/lang/en/texts.php
+++ b/lang/en/texts.php
@@ -3863,7 +3863,7 @@ $LANG = array(
'notification_credit_viewed' => 'The following client :client viewed Credit :credit for :amount.',
'reset_password_text' => 'Enter your email to reset your password.',
'password_reset' => 'Password reset',
- 'account_login_text' => 'Welcome back! Glad to see you.',
+ 'account_login_text' => 'Welcome! Glad to see you.',
'request_cancellation' => 'Request cancellation',
'delete_payment_method' => 'Delete Payment Method',
'about_to_delete_payment_method' => 'You are about to delete the payment method.',
diff --git a/phpstan.neon b/phpstan.neon
index 8bbf3a89f08a..148ec353ba82 100644
--- a/phpstan.neon
+++ b/phpstan.neon
@@ -6,8 +6,6 @@ parameters:
ignoreErrors:
- '#Call to an undefined method .*badMethod\(\)#'
- '#Call to an undefined method Illuminate\Database\Eloquent\Builder::exclude#'
- parallel:
- maximumNumberOfProcesses: 8
level: 4
paths:
- 'app/'
diff --git a/resources/views/pdf-designs/calm.html b/resources/views/pdf-designs/calm.html
index 099bace18ba8..72eb8f6022aa 100644
--- a/resources/views/pdf-designs/calm.html
+++ b/resources/views/pdf-designs/calm.html
@@ -132,7 +132,7 @@
}
#shipping-details {
- visibility: $show_shipping_address_visibility;
+ opacity: $show_shipping_address_visibility;
flex-direction: column;
line-height: var(--line-height);
}
diff --git a/resources/views/portal/ninja2020/credits/show-fullscreen.blade.php b/resources/views/portal/ninja2020/credits/show-fullscreen.blade.php
index 438899646beb..3655bf8f68e4 100644
--- a/resources/views/portal/ninja2020/credits/show-fullscreen.blade.php
+++ b/resources/views/portal/ninja2020/credits/show-fullscreen.blade.php
@@ -1,2 +1,3 @@
-
+
+
+
diff --git a/resources/views/portal/ninja2020/invoices/show-fullscreen.blade.php b/resources/views/portal/ninja2020/invoices/show-fullscreen.blade.php
index d15cebda832d..8de82110754e 100644
--- a/resources/views/portal/ninja2020/invoices/show-fullscreen.blade.php
+++ b/resources/views/portal/ninja2020/invoices/show-fullscreen.blade.php
@@ -1,2 +1,2 @@
-
+
+
diff --git a/resources/views/portal/ninja2020/purchase_orders/show-fullscreen.blade.php b/resources/views/portal/ninja2020/purchase_orders/show-fullscreen.blade.php
index e69de29bb2d1..2aa2bf4b229b 100644
--- a/resources/views/portal/ninja2020/purchase_orders/show-fullscreen.blade.php
+++ b/resources/views/portal/ninja2020/purchase_orders/show-fullscreen.blade.php
@@ -0,0 +1,2 @@
+
+
diff --git a/resources/views/portal/ninja2020/quotes/show-fullscreen.blade.php b/resources/views/portal/ninja2020/quotes/show-fullscreen.blade.php
index 0cfa59fec10b..22043d045fe8 100644
--- a/resources/views/portal/ninja2020/quotes/show-fullscreen.blade.php
+++ b/resources/views/portal/ninja2020/quotes/show-fullscreen.blade.php
@@ -1,2 +1,3 @@
-
+
+
+
diff --git a/resources/views/portal/ninja2020/statement/index.blade.php b/resources/views/portal/ninja2020/statement/index.blade.php
index 14ea29843d5c..f0780705b29a 100644
--- a/resources/views/portal/ninja2020/statement/index.blade.php
+++ b/resources/views/portal/ninja2020/statement/index.blade.php
@@ -45,6 +45,7 @@
@include('portal.ninja2020.components.pdf-viewer', ['url' => route('client.statement.raw')])
+
@endsection
@push('footer')
diff --git a/routes/client.php b/routes/client.php
index 0a95a333c600..f708f64113a5 100644
--- a/routes/client.php
+++ b/routes/client.php
@@ -40,7 +40,7 @@ Route::get('tmp_pdf/{hash}', [App\Http\Controllers\ClientPortal\TempRouteControl
Route::get('client/key_login/{contact_key}', [App\Http\Controllers\ClientPortal\ContactHashLoginController::class, 'login'])->name('client.contact_login')->middleware(['domain_db','contact_key_login']);
Route::get('client/magic_link/{magic_link}', [App\Http\Controllers\ClientPortal\ContactHashLoginController::class, 'magicLink'])->name('client.contact_magic_link')->middleware(['domain_db','contact_key_login']);
-Route::get('documents/{document_hash}', [App\Http\Controllers\ClientPortal\DocumentController::class, 'publicDownload'])->name('documents.public_download')->middleware(['domain_db','token_auth']);
+Route::get('documents/{document_hash}', [App\Http\Controllers\ClientPortal\DocumentController::class, 'publicDownload'])->name('documents.public_download')->middleware(['api_db','token_auth']);
Route::get('error', [App\Http\Controllers\ClientPortal\ContactHashLoginController::class, 'errorPage'])->name('client.error');
Route::get('client/payment/{contact_key}/{payment_id}', [App\Http\Controllers\ClientPortal\InvitationController::class, 'paymentRouter'])->middleware(['domain_db','contact_key_login']);
Route::get('client/ninja/{contact_key}/{company_key}', [App\Http\Controllers\ClientPortal\NinjaPlanController::class, 'index'])->name('client.ninja_contact_login')->middleware(['domain_db']);
diff --git a/tests/Feature/ExpenseApiTest.php b/tests/Feature/ExpenseApiTest.php
index 2e9b1405479f..ef6fadf3d019 100644
--- a/tests/Feature/ExpenseApiTest.php
+++ b/tests/Feature/ExpenseApiTest.php
@@ -31,6 +31,8 @@ class ExpenseApiTest extends TestCase
use DatabaseTransactions;
use MockAccountData;
+ public $faker;
+
protected function setUp() :void
{
parent::setUp();
diff --git a/tests/Feature/QuoteTest.php b/tests/Feature/QuoteTest.php
index c324f05f8c30..320a4f1149d0 100644
--- a/tests/Feature/QuoteTest.php
+++ b/tests/Feature/QuoteTest.php
@@ -11,16 +11,17 @@
namespace Tests\Feature;
-use App\Models\ClientContact;
-use App\Models\Project;
-use App\Models\Quote;
-use App\Utils\Traits\MakesHash;
-use Illuminate\Database\Eloquent\Model;
-use Illuminate\Foundation\Testing\DatabaseTransactions;
-use Illuminate\Routing\Middleware\ThrottleRequests;
-use Illuminate\Support\Facades\Session;
-use Tests\MockAccountData;
use Tests\TestCase;
+use App\Models\Quote;
+use App\Models\Project;
+use Tests\MockAccountData;
+use App\Models\ClientContact;
+use App\Utils\Traits\MakesHash;
+use App\Exceptions\QuoteConversion;
+use Illuminate\Database\Eloquent\Model;
+use Illuminate\Support\Facades\Session;
+use Illuminate\Routing\Middleware\ThrottleRequests;
+use Illuminate\Foundation\Testing\DatabaseTransactions;
/**
* @test
@@ -32,6 +33,8 @@ class QuoteTest extends TestCase
use DatabaseTransactions;
use MockAccountData;
+ public $faker;
+
protected function setUp() :void
{
parent::setUp();
@@ -49,6 +52,19 @@ class QuoteTest extends TestCase
);
}
+ public function testQuoteConversion()
+ {
+ $invoice = $this->quote->service()->convertToInvoice();
+
+ $this->assertInstanceOf('\App\Models\Invoice', $invoice);
+
+ $this->expectException(QuoteConversion::class);
+
+ $invoice = $this->quote->service()->convertToInvoice();
+
+
+ }
+
public function testQuoteDownloadPDF()
{
$i = $this->quote->invitations->first();