Merge pull request #10870 from turbo124/v5-develop

v5.11.64
This commit is contained in:
David Bomba 2025-04-08 06:43:06 +10:00 committed by GitHub
commit a3a4a5a41b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
23 changed files with 272 additions and 289 deletions

View File

@ -1 +1 @@
5.11.63
5.11.64

View File

@ -63,23 +63,8 @@ class GmailTransport extends AbstractTransport
$body->setRaw($this->base64_encode($bcc_list.$message->toString()));
// try {
$service->users_messages->send('me', $body, []);
// } catch(\Google\Service\Exception $e) {
// /* Need to slow down */
// if ($e->getCode() == '429') {
// nlog("429 google - retrying ");
// sleep(rand(3,8));
// try {
// $service->users_messages->send('me', $body, []);
// } catch(\Google\Service\Exception $e) {
// }
// }
// }
}
private function base64_encode($data)

View File

@ -245,10 +245,6 @@ class NinjaPlanController extends Controller
->orderBy('id', 'DESC')
->first();
//account status means user cannot perform upgrades until they pay their account.
// $data['late_invoice'] = $late_invoice;
//14-01-2022 remove late invoices from blocking upgrades
$data['late_invoice'] = false;
}

View File

@ -29,27 +29,23 @@ class RedirectIfAuthenticated
{
switch ($guard) {
case 'contact':
if (Auth::guard($guard)->check()) {
return redirect()->route('client.dashboard');
}
Auth::logout();
// if (Auth::guard($guard)->check()) {
// return redirect()->route('client.dashboard');
// }
break;
case 'user':
Auth::logout();
// if (Auth::guard($guard)->check()) {
// return redirect()->route('dashboard.index');
// }
break;
case 'vendor':
if (Auth::guard($guard)->check()) {
//TODO create routes for vendor
// return redirect()->route('vendor.dashboard');
}
break;
default:
Auth::logout();
// if (Auth::guard($guard)->check()) {
// return redirect('/');
// }
break;
}

View File

@ -58,6 +58,7 @@ class SetDomainNameDb
MultiDB::setDb('db-ninja-01');
nlog('SetDomainNameDb:: I could not set the DB - defaulting to DB1');
$request->session()->invalidate();
$request->session()->regenerate(true);
$request->session()->regenerateToken();
}
}
@ -76,6 +77,7 @@ class SetDomainNameDb
MultiDB::setDb('db-ninja-01');
nlog('SetDomainNameDb:: I could not set the DB - defaulting to DB1');
$request->session()->invalidate();
$request->session()->regenerate(true);
$request->session()->regenerateToken();
}
}

View File

@ -32,7 +32,7 @@ class SetEmailDb
'errors' => new stdClass(),
];
if ($request->input('email') && is_string($request->input('email')) && config('ninja.db.multi_db_enabled')) {
if (config('ninja.db.multi_db_enabled') && $request->input('email') && is_string($request->input('email'))) {
if (! MultiDB::userFindAndSetDb($request->input('email'))) {
return response()->json($error, 400);
}

View File

@ -70,7 +70,8 @@ class AutoBill implements ShouldQueue
$invoice->invitations->each(function ($invitation) use ($invoice) {
if ($invitation->contact && !$invitation->contact->trashed() && strlen($invitation->contact->email) >= 1 && $invoice->client->getSetting('auto_email_invoice') && !$invitation->contact->is_locked) {
//2025-04-06 additional conditional check to prevent duplicate emails from being sent.
if ($invitation->contact && !$invitation->contact->trashed() && strlen($invitation->contact->email) >= 1 && $invoice->client->getSetting('auto_email_invoice') && !$invitation->contact->is_locked && $invoice->client->getSetting('client_online_payment_notification')) {
try {
EmailEntity::dispatch($invitation->withoutRelations(), $invoice->company->db)->delay(rand(1, 2));

View File

@ -711,7 +711,8 @@ class Client extends BaseModel implements HasLocalePreference
}
}
if (in_array($this->currency()->code, ['CAD','USD']) && in_array(GatewayType::ACSS, array_column($pms, 'gateway_type_id'))) {
if (in_array($this->currency()->code, ['USD']) && in_array(GatewayType::ACSS, array_column($pms, 'gateway_type_id'))) {
// if (in_array($this->currency()->code, ['CAD','USD']) && in_array(GatewayType::ACSS, array_column($pms, 'gateway_type_id'))) {
// if ($this->currency()->code == 'CAD' && in_array(GatewayType::ACSS, array_column($pms, 'gateway_type_id'))) {
foreach ($pms as $pm) {
if ($pm['gateway_type_id'] == GatewayType::ACSS) {
@ -744,7 +745,6 @@ class Client extends BaseModel implements HasLocalePreference
public function getBankTransferMethodType()
{
$pms = $this->service()->getPaymentMethods(-1);
if ($this->currency()->code == 'USD' && in_array(GatewayType::BANK_TRANSFER, array_column($pms, 'gateway_type_id'))) {

View File

@ -102,7 +102,7 @@ class CreditCard implements MethodInterface, LivewireMethodInterface
try {
$response = $this->checkout->gateway->getPaymentsClient()->requestPayment($request);
if ($response['approved'] && $response['status'] === 'Authorized') {
if (isset($response['approved']) && $response['status'] === 'Authorized') {
$payment_meta = new \stdClass();
$payment_meta->exp_month = (string) $response['source']['expiry_month'];
$payment_meta->exp_year = (string) $response['source']['expiry_year'];

View File

@ -61,7 +61,7 @@ class PaymentIntentWebhook implements ShouldQueue
{
MultiDB::findAndSetDbByCompanyKey($this->company_key);
$company = Company::query()->where('company_key', $this->company_key)->first();
$company = Company::query()->where('company_key', $this->company_key)->firstOrFail();
foreach ($this->stripe_request as $transaction) {

View File

@ -127,8 +127,7 @@ class StripePaymentDriver extends BaseDriver implements SupportsHeadlessInterfac
);
Stripe::setApiKey($this->company_gateway->getConfigField('apiKey'));
// Stripe::setApiVersion('2022-11-15');
Stripe::setAPiVersion('2023-08-16');
Stripe::setAPiVersion('2023-10-16');
}
return $this;
@ -550,7 +549,7 @@ class StripePaymentDriver extends BaseDriver implements SupportsHeadlessInterfac
//Search by email
$searchResults = \Stripe\Customer::all([
'email' => $this->client->present()->email(),
'email' => (string)$this->client->present()->email(),
'limit' => 2,
'starting_after' => null,
], $this->stripe_connect_auth);
@ -1037,16 +1036,6 @@ class StripePaymentDriver extends BaseDriver implements SupportsHeadlessInterfac
public function auth(): string
{
// $this->init();
// try {
// $this->verifyConnect();
// return 'ok';
// } catch (\Throwable $th) {
// }
// return 'error';
$this->init();

View File

@ -714,7 +714,7 @@ class Email implements ShouldQueue
if ($sending_user == "0") {
$user = $this->company->owner();
} else {
$user = User::find($this->decodePrimaryKey($sending_user));
$user = User::withTrashed()->find($this->decodePrimaryKey($sending_user));
}
return $user;

View File

@ -55,7 +55,7 @@ class EmailReport
public function run()
{
$start_end_dates = $this->calculateStartAndEndDates($this->scheduler->parameters);
$start_end_dates = $this->calculateStartAndEndDates($this->scheduler->parameters, $this->scheduler->company);
$data = $this->scheduler->parameters;
$data['start_date'] = $start_end_dates[0];

View File

@ -562,8 +562,8 @@ class TemplateService
$this->entity = $invoice;
if ($invoice->payments ?? false) {
$payments = $invoice->payments->map(function ($payment) {
return $this->transformPayment($payment);
$payments = $invoice->payments->map(function ($payment) use($invoice) {
return $this->transformPayment($payment, $invoice);
})->toArray();
}
@ -674,12 +674,16 @@ class TemplateService
* @param Payment $payment
* @return array
*/
private function transformPayment(Payment $payment): array
private function transformPayment(Payment $payment, $entity = null): array
{
$this->payment = $payment;
$credits = $payment->credits->map(function ($credit) use ($payment) {
$credits = $payment->credits
->when($entity instanceof Credit, function($collection) use ($entity) {
return $collection->where('number', $entity->number);
})
->map(function ($credit) use ($payment) {
return [
'credit' => $credit->number,
'amount_raw' => $credit->pivot->amount,
@ -696,7 +700,11 @@ class TemplateService
];
});
$pivot = $payment->invoices->map(function ($invoice) use ($payment) {
$pivot = $payment->invoices
->when($entity instanceof Invoice, function($collection) use ($entity) {
return $collection->where('number', $entity->number);
})
->map(function ($invoice) use ($payment) {
return [
'invoice' => $invoice->number,
'amount_raw' => $invoice->pivot->amount,
@ -876,8 +884,8 @@ class TemplateService
$this->entity = $credit;
if ($credit->payments ?? false) {
$payments = $credit->payments->map(function ($payment) {
return $this->transformPayment($payment);
$payments = $credit->payments->map(function ($payment) use($credit) {
return $this->transformPayment($payment, $credit);
})->toArray();
}

View File

@ -125,9 +125,9 @@ trait MakesDates
//override for financial years
if ($data['date_range'] == 'this_year') {
$first_month_of_year = $company ? $company?->first_month_of_year : 1;
$fin_year_start = now()->createFromDate(now()->year, $first_month_of_year, 1);
$fin_year_start = now()->setTimezone($company->timezone()->name ?? 'Pacific/Midway')->createFromDate(now()->year, $first_month_of_year, 1);
if (now()->lt($fin_year_start)) {
if (now()->setTimezone($company->timezone()->name ?? 'Pacific/Midway')->lt($fin_year_start)) {
$fin_year_start->subYearNoOverflow();
}
@ -147,17 +147,17 @@ trait MakesDates
}
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')],
EmailStatement::THIS_MONTH => [now()->startOfDay()->firstOfMonth()->format('Y-m-d'), now()->startOfDay()->lastOfMonth()->format('Y-m-d')],
EmailStatement::LAST_MONTH => [now()->startOfDay()->subMonthNoOverflow()->firstOfMonth()->format('Y-m-d'), now()->startOfDay()->subMonthNoOverflow()->lastOfMonth()->format('Y-m-d')],
EmailStatement::THIS_QUARTER => [now()->startOfDay()->startOfQuarter()->format('Y-m-d'), now()->startOfDay()->endOfQuarter()->format('Y-m-d')],
EmailStatement::LAST_QUARTER => [now()->startOfDay()->subQuarterNoOverflow()->startOfQuarter()->format('Y-m-d'), now()->startOfDay()->subQuarterNoOverflow()->endOfQuarter()->format('Y-m-d')],
EmailStatement::LAST7 => [now()->setTimezone($company->timezone()->name ?? 'Pacific/Midway')->startOfDay()->subDays(7)->format('Y-m-d'), now()->setTimezone($company->timezone()->name ?? 'Pacific/Midway')->startOfDay()->format('Y-m-d')],
EmailStatement::LAST30 => [now()->setTimezone($company->timezone()->name ?? 'Pacific/Midway')->startOfDay()->subDays(30)->format('Y-m-d'), now()->setTimezone($company->timezone()->name ?? 'Pacific/Midway')->startOfDay()->format('Y-m-d')],
EmailStatement::LAST365 => [now()->setTimezone($company->timezone()->name ?? 'Pacific/Midway')->startOfDay()->subDays(365)->format('Y-m-d'), now()->setTimezone($company->timezone()->name ?? 'Pacific/Midway')->startOfDay()->format('Y-m-d')],
EmailStatement::THIS_MONTH => [now()->setTimezone($company->timezone()->name ?? 'Pacific/Midway')->startOfDay()->firstOfMonth()->format('Y-m-d'), now()->startOfDay()->lastOfMonth()->format('Y-m-d')],
EmailStatement::LAST_MONTH => [now()->setTimezone($company->timezone()->name ?? 'Pacific/Midway')->startOfDay()->subMonthNoOverflow()->firstOfMonth()->format('Y-m-d'), now()->startOfDay()->subMonthNoOverflow()->lastOfMonth()->format('Y-m-d')],
EmailStatement::THIS_QUARTER => [now()->setTimezone($company->timezone()->name ?? 'Pacific/Midway')->startOfDay()->startOfQuarter()->format('Y-m-d'), now()->startOfDay()->endOfQuarter()->format('Y-m-d')],
EmailStatement::LAST_QUARTER => [now()->setTimezone($company->timezone()->name ?? 'Pacific/Midway')->startOfDay()->subQuarterNoOverflow()->startOfQuarter()->format('Y-m-d'), now()->startOfDay()->subQuarterNoOverflow()->endOfQuarter()->format('Y-m-d')],
EmailStatement::THIS_YEAR => [$fin_year_start->format('Y-m-d'), $fin_year_start->copy()->addYear()->subDay()->format('Y-m-d')],
EmailStatement::LAST_YEAR => [$fin_year_start->format('Y-m-d'), $fin_year_start->copy()->addYear()->subDay()->format('Y-m-d')],
EmailStatement::CUSTOM_RANGE => [$data['start_date'], $data['end_date']],
default => [now()->startOfDay()->firstOfMonth()->format('Y-m-d'), now()->startOfDay()->lastOfMonth()->format('Y-m-d')],
default => [now()->setTimezone($company->timezone()->name ?? 'Pacific/Midway')->startOfDay()->firstOfMonth()->format('Y-m-d'), now()->setTimezone($company->timezone()->name ?? 'Pacific/Midway')->startOfDay()->lastOfMonth()->format('Y-m-d')],
};
}
@ -168,28 +168,28 @@ trait MakesDates
if ($data['date_range'] == 'this_year') {
$first_month_of_year = $company ? $company?->first_month_of_year : 1;
$fin_year_start = now()->createFromDate(now()->year, $first_month_of_year, 1);
$fin_year_start = now()->setTimezone($company->timezone()->name ?? 'Pacific/Midway')->createFromDate(now()->year, $first_month_of_year, 1);
$fin_year_start->subYearNoOverflow();
if (now()->subYear()->lt($fin_year_start)) {
if (now()->setTimezone($company->timezone()->name ?? 'Pacific/Midway')->subYear()->lt($fin_year_start)) {
$fin_year_start->subYearNoOverflow();
}
}
return match ($data['date_range']) {
EmailStatement::LAST7 => [now()->startOfDay()->subDays(14)->format('Y-m-d'), now()->subDays(7)->startOfDay()->format('Y-m-d')],
EmailStatement::LAST30 => [now()->startOfDay()->subDays(60)->format('Y-m-d'), now()->subDays(30)->startOfDay()->format('Y-m-d')],
EmailStatement::LAST365 => [now()->startOfDay()->subDays(739)->format('Y-m-d'), now()->subDays(365)->startOfDay()->format('Y-m-d')],
EmailStatement::THIS_MONTH => [now()->startOfDay()->subMonthNoOverflow()->firstOfMonth()->format('Y-m-d'), now()->startOfDay()->subMonthNoOverflow()->lastOfMonth()->format('Y-m-d')],
EmailStatement::LAST_MONTH => [now()->startOfDay()->subMonthsNoOverflow(2)->firstOfMonth()->format('Y-m-d'), now()->startOfDay()->subMonthNoOverflow()->lastOfMonth()->format('Y-m-d')],
EmailStatement::THIS_QUARTER => [now()->startOfDay()->subQuarterNoOverflow()->startOfQuarter()->format('Y-m-d'), now()->startOfDay()->subQuarterNoOverflow()->endOfQuarter()->format('Y-m-d')],
EmailStatement::LAST_QUARTER => [now()->startOfDay()->subQuartersNoOverflow(2)->startOfQuarter()->format('Y-m-d'), now()->startOfDay()->subQuartersNoOverflow(2)->endOfQuarter()->format('Y-m-d')],
EmailStatement::LAST7 => [now()->setTimezone($company->timezone()->name ?? 'Pacific/Midway')->startOfDay()->subDays(14)->format('Y-m-d'), now()->setTimezone($company->timezone()->name ?? 'Pacific/Midway')->startOfDay()->subDays(7)->format('Y-m-d')],
EmailStatement::LAST30 => [now()->setTimezone($company->timezone()->name ?? 'Pacific/Midway')->startOfDay()->subDays(60)->format('Y-m-d'), now()->setTimezone($company->timezone()->name ?? 'Pacific/Midway')->startOfDay()->subDays(30)->format('Y-m-d')],
EmailStatement::LAST365 => [now()->setTimezone($company->timezone()->name ?? 'Pacific/Midway')->startOfDay()->subDays(739)->format('Y-m-d'), now()->setTimezone($company->timezone()->name ?? 'Pacific/Midway')->startOfDay()->subDays(365)->format('Y-m-d')],
EmailStatement::THIS_MONTH => [now()->setTimezone($company->timezone()->name ?? 'Pacific/Midway')->startOfDay()->subMonthNoOverflow()->firstOfMonth()->format('Y-m-d'), now()->setTimezone($company->timezone()->name ?? 'Pacific/Midway')->startOfDay()->subMonthNoOverflow()->lastOfMonth()->format('Y-m-d')],
EmailStatement::LAST_MONTH => [now()->setTimezone($company->timezone()->name ?? 'Pacific/Midway')->startOfDay()->subMonthsNoOverflow(2)->firstOfMonth()->format('Y-m-d'), now()->setTimezone($company->timezone()->name ?? 'Pacific/Midway')->startOfDay()->subMonthNoOverflow()->lastOfMonth()->format('Y-m-d')],
EmailStatement::THIS_QUARTER => [now()->setTimezone($company->timezone()->name ?? 'Pacific/Midway')->startOfDay()->subQuarterNoOverflow()->startOfQuarter()->format('Y-m-d'), now()->setTimezone($company->timezone()->name ?? 'Pacific/Midway')->startOfDay()->subQuarterNoOverflow()->endOfQuarter()->format('Y-m-d')],
EmailStatement::LAST_QUARTER => [now()->setTimezone($company->timezone()->name ?? 'Pacific/Midway')->startOfDay()->subQuartersNoOverflow(2)->startOfQuarter()->format('Y-m-d'), now()->setTimezone($company->timezone()->name ?? 'Pacific/Midway')->startOfDay()->subQuartersNoOverflow(2)->endOfQuarter()->format('Y-m-d')],
EmailStatement::THIS_YEAR => [$fin_year_start->subYear()->format('Y-m-d'), $fin_year_start->copy()->subDay()->format('Y-m-d')],
EmailStatement::LAST_YEAR => [$fin_year_start->subYear(2)->format('Y-m-d'), $fin_year_start->copy()->subYear()->subDay()->format('Y-m-d')],
EmailStatement::CUSTOM_RANGE => [$data['start_date'], $data['end_date']],
default => [now()->startOfDay()->firstOfMonth()->format('Y-m-d'), now()->startOfDay()->lastOfMonth()->format('Y-m-d')],
default => [now()->setTimezone($company->timezone()->name ?? 'Pacific/Midway')->startOfDay()->firstOfMonth()->format('Y-m-d'), now()->setTimezone($company->timezone()->name ?? 'Pacific/Midway')->startOfDay()->lastOfMonth()->format('Y-m-d')],
};
}

View File

@ -101,7 +101,7 @@
"socialiteproviders/microsoft": "^4.1",
"sprain/swiss-qr-bill": "^4.3",
"square/square": "30.0.0.*",
"stripe/stripe-php": "^12",
"stripe/stripe-php": "^13",
"symfony/brevo-mailer": "^7.1",
"symfony/http-client": "^7.0.3",
"symfony/mailer": "7.1.6",

409
composer.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -17,8 +17,8 @@ return [
'require_https' => env('REQUIRE_HTTPS', true),
'app_url' => rtrim(env('APP_URL', ''), '/'),
'app_domain' => env('APP_DOMAIN', 'invoicing.co'),
'app_version' => env('APP_VERSION', '5.11.63'),
'app_tag' => env('APP_TAG', '5.11.63'),
'app_version' => env('APP_VERSION', '5.11.64'),
'app_tag' => env('APP_TAG', '5.11.64'),
'minimum_client_version' => '5.0.16',
'terms_version' => '1.0.1',
'api_secret' => env('API_SECRET', false),

View File

@ -153,7 +153,7 @@
<div class="dark-bg"
style="background-color:#f9f9f9; padding-bottom: 20px; margin-top:20px;">
@if($logo && strpos($logo, 'blank.png') === false)
<img class="" src="{{ $logo ?? '' }}" width="50%" height="" alt=" " border="0" style="width: 50%; max-width: 570px; height: auto; display: block;" class="g-img">
<img class="" src="{{ $logo ?? '' }}" alt=" " border="0" style="display: block; width: auto; max-width: 300px; max-height: 100px; height: auto; margin: 0 auto;" class="g-img">
@endif
</div>
</td>

View File

@ -158,7 +158,7 @@
<td align="center" cellpadding="20">
<div style="border: 1px solid #c2c2c2; border-bottom: none; padding-bottom: 10px; border-top-left-radius: 3px; border-top-right-radius: 3px; padding-top:10px;">
@if($logo && strpos($logo, 'blank.png') === false)
<img class="" src="{{ $logo ?? '' }}" width="50%" height="" alt=" " border="0" style="width: 50%; max-width: 570px; display: block;">
<img class="" src="{{ $logo ?? '' }}" alt=" " border="0" style="display: block; width: auto; max-width: 300px; max-height: 100px; height: auto; margin: 0 auto;">
@endif
</div>
</td>

View File

@ -178,6 +178,7 @@
[data-ref="table"]>thead {
text-align: left;
break-inside: auto !important;
}
[data-ref="table"]>thead>tr>th {

View File

@ -47,7 +47,7 @@ Route::get('client/ninja/{contact_key}/{company_key}', [App\Http\Controllers\Cli
Route::group(['middleware' => ['auth:contact', 'locale', 'domain_db','check_client_existence'], 'prefix' => 'client', 'as' => 'client.'], function () {
Route::get('dashboard', [App\Http\Controllers\ClientPortal\DashboardController::class, 'index'])->name('dashboard'); // name = (dashboard. index / create / show / update / destroy / edit
Route::post('ninja/trial_confirmation', [App\Http\Controllers\ClientPortal\NinjaPlanController::class, 'trial_confirmation'])->name('client.trial.response')->middleware(['domain_db']);
Route::post('ninja/trial_confirmation', [App\Http\Controllers\ClientPortal\NinjaPlanController::class, 'trial_confirmation'])->name('trial.response')->middleware(['domain_db']);
Route::get('plan', [App\Http\Controllers\ClientPortal\NinjaPlanController::class, 'plan'])->name('plan'); // name = (dashboard. index / create / show / update / destroy / edit