Merge pull request #8288 from turbo124/v5-stable
Some checks failed
phpunit / run (0, 8, prefer-stable, 9.*, ubuntu-20.04, 8.1, latest) (push) Has been cancelled
phpunit / run (0, 8, prefer-stable, 9.*, ubuntu-20.04, 8.2, latest) (push) Has been cancelled
phpunit / run (0, 8, prefer-stable, 9.*, ubuntu-22.04, 8.1, latest) (push) Has been cancelled
phpunit / run (0, 8, prefer-stable, 9.*, ubuntu-22.04, 8.2, latest) (push) Has been cancelled
phpunit / run (1, 8, prefer-stable, 9.*, ubuntu-20.04, 8.1, latest) (push) Has been cancelled
phpunit / run (1, 8, prefer-stable, 9.*, ubuntu-20.04, 8.2, latest) (push) Has been cancelled
phpunit / run (1, 8, prefer-stable, 9.*, ubuntu-22.04, 8.1, latest) (push) Has been cancelled
phpunit / run (1, 8, prefer-stable, 9.*, ubuntu-22.04, 8.2, latest) (push) Has been cancelled
phpunit / run (2, 8, prefer-stable, 9.*, ubuntu-20.04, 8.1, latest) (push) Has been cancelled
phpunit / run (2, 8, prefer-stable, 9.*, ubuntu-20.04, 8.2, latest) (push) Has been cancelled
phpunit / run (2, 8, prefer-stable, 9.*, ubuntu-22.04, 8.1, latest) (push) Has been cancelled
phpunit / run (2, 8, prefer-stable, 9.*, ubuntu-22.04, 8.2, latest) (push) Has been cancelled
phpunit / run (3, 8, prefer-stable, 9.*, ubuntu-20.04, 8.1, latest) (push) Has been cancelled
phpunit / run (3, 8, prefer-stable, 9.*, ubuntu-20.04, 8.2, latest) (push) Has been cancelled
phpunit / run (3, 8, prefer-stable, 9.*, ubuntu-22.04, 8.1, latest) (push) Has been cancelled
phpunit / run (3, 8, prefer-stable, 9.*, ubuntu-22.04, 8.2, latest) (push) Has been cancelled
phpunit / run (4, 8, prefer-stable, 9.*, ubuntu-20.04, 8.1, latest) (push) Has been cancelled
phpunit / run (4, 8, prefer-stable, 9.*, ubuntu-20.04, 8.2, latest) (push) Has been cancelled
phpunit / run (4, 8, prefer-stable, 9.*, ubuntu-22.04, 8.1, latest) (push) Has been cancelled
phpunit / run (4, 8, prefer-stable, 9.*, ubuntu-22.04, 8.2, latest) (push) Has been cancelled
phpunit / run (5, 8, prefer-stable, 9.*, ubuntu-20.04, 8.1, latest) (push) Has been cancelled
phpunit / run (5, 8, prefer-stable, 9.*, ubuntu-20.04, 8.2, latest) (push) Has been cancelled
phpunit / run (5, 8, prefer-stable, 9.*, ubuntu-22.04, 8.1, latest) (push) Has been cancelled
phpunit / run (5, 8, prefer-stable, 9.*, ubuntu-22.04, 8.2, latest) (push) Has been cancelled
phpunit / run (6, 8, prefer-stable, 9.*, ubuntu-20.04, 8.1, latest) (push) Has been cancelled
phpunit / run (6, 8, prefer-stable, 9.*, ubuntu-20.04, 8.2, latest) (push) Has been cancelled
phpunit / run (6, 8, prefer-stable, 9.*, ubuntu-22.04, 8.1, latest) (push) Has been cancelled
phpunit / run (6, 8, prefer-stable, 9.*, ubuntu-22.04, 8.2, latest) (push) Has been cancelled
phpunit / run (7, 8, prefer-stable, 9.*, ubuntu-20.04, 8.1, latest) (push) Has been cancelled
phpunit / run (7, 8, prefer-stable, 9.*, ubuntu-20.04, 8.2, latest) (push) Has been cancelled
phpunit / run (7, 8, prefer-stable, 9.*, ubuntu-22.04, 8.1, latest) (push) Has been cancelled
phpunit / run (7, 8, prefer-stable, 9.*, ubuntu-22.04, 8.2, latest) (push) Has been cancelled

Patches
This commit is contained in:
David Bomba 2023-02-19 17:18:13 +11:00 committed by GitHub
commit 96dadaa5d4
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
66 changed files with 28575 additions and 426 deletions

View file

@ -2,6 +2,7 @@ on:
push:
branches:
- v5-develop
- v5-stable
pull_request:
branches:
- v5-develop

View file

@ -18,7 +18,7 @@ jobs:
- name: Checkout code
uses: actions/checkout@v1
with:
ref: v5-stable
ref: v5-develop
- name: Copy .env file
run: |

View file

@ -1 +1 @@
5.5.70
5.5.71

28081
_ide_helper.php Normal file

File diff suppressed because it is too large Load diff

View file

@ -11,24 +11,20 @@
namespace App\DataMapper\Schedule;
use App\Models\Client;
use stdClass;
class ClientStatement
class EmailStatement
{
/**
* Defines the template name
*
*
* @var string
*/
public string $template = 'client_statement';
public string $template = 'email_statement';
/**
* An array of clients hashed_ids
*
* Leave blank if this action should apply to all clients
*
*
* @var array
*/
public array $clients = [];
@ -36,17 +32,21 @@ class ClientStatement
/**
* The consts to be used to define the date_range variable of the statement
*/
public const THIS_MONTH = 'this_month';
public const THIS_QUARTER = 'this_quarter';
public const THIS_YEAR = 'this_year';
public const PREVIOUS_MONTH = 'previous_month';
public const PREVIOUS_QUARTER = 'previous_quarter';
public const PREVIOUS_YEAR = 'previous_year';
public const CUSTOM_RANGE = "custom_range";
public const LAST7 = "last7_days";
public const LAST30 = "last30_days";
public const LAST365 = "last365_days";
public const THIS_MONTH = "this_month";
public const LAST_MONTH = "last_month";
public const THIS_QUARTER = "this_quarter";
public const LAST_QUARTER = "last_quarter";
public const THIS_YEAR = "this_year";
public const LAST_YEAR = "last_year";
public const CUSTOM_RANGE = "custom";
/**
* The date range the statement should include
*
*
* @var string
*/
public string $date_range = 'this_month';
@ -54,7 +54,7 @@ class ClientStatement
/**
* If a custom range is select for the date range then
* the start_date should be supplied in Y-m-d format
*
*
* @var string
*/
public string $start_date = '';
@ -62,7 +62,7 @@ class ClientStatement
/**
* If a custom range is select for the date range then
* the end_date should be supplied in Y-m-d format
*
*
* @var string
*/
public string $end_date = '';
@ -87,10 +87,8 @@ class ClientStatement
* String const which defines whether
* the invoices to be shown are either
* paid or unpaid
*
*
* @var string
*/
public string $status = 'paid'; // paid | unpaid
}

View file

@ -48,4 +48,5 @@ class InvoiceWasPaid
$this->company = $company;
$this->event_vars = $event_vars;
}
}

View file

@ -127,6 +127,10 @@ class IncomeTransformer implements BankRevenueInterface
foreach($transaction->transaction as $transaction)
{
//do not store duplicate / pending transactions
if(property_exists($transaction,'status') && $transaction->status == 'PENDING')
continue;
$data[] = $this->transformTransaction($transaction);
}

View file

@ -11,32 +11,33 @@
namespace App\Http\Controllers;
use App\Models\Account;
use App\Models\BankIntegration;
use App\Models\BankTransaction;
use App\Models\BankTransactionRule;
use App\Models\CompanyGateway;
use App\Models\Design;
use App\Models\ExpenseCategory;
use App\Models\GroupSetting;
use App\Models\PaymentTerm;
use App\Models\Scheduler;
use App\Models\TaxRate;
use App\Models\User;
use App\Models\Webhook;
use App\Transformers\ArraySerializer;
use App\Transformers\EntityTransformer;
use App\Utils\Ninja;
use App\Models\Design;
use App\Utils\Statics;
use App\Utils\Traits\AppSetup;
use Illuminate\Contracts\Container\BindingResolutionException;
use Illuminate\Database\Eloquent\Builder;
use App\Models\Account;
use App\Models\TaxRate;
use App\Models\Webhook;
use App\Models\Scheduler;
use App\Models\TaskStatus;
use App\Models\PaymentTerm;
use Illuminate\Support\Str;
use League\Fractal\Manager;
use League\Fractal\Pagination\IlluminatePaginatorAdapter;
use League\Fractal\Resource\Collection;
use App\Models\GroupSetting;
use App\Models\CompanyGateway;
use App\Utils\Traits\AppSetup;
use App\Models\BankIntegration;
use App\Models\BankTransaction;
use App\Models\ExpenseCategory;
use League\Fractal\Resource\Item;
use App\Models\BankTransactionRule;
use App\Transformers\ArraySerializer;
use App\Transformers\EntityTransformer;
use League\Fractal\Resource\Collection;
use Illuminate\Database\Eloquent\Builder;
use League\Fractal\Serializer\JsonApiSerializer;
use League\Fractal\Pagination\IlluminatePaginatorAdapter;
use Illuminate\Contracts\Container\BindingResolutionException;
/**
* Class BaseController.
@ -911,8 +912,9 @@ class BaseController extends Controller
else
$query->where('user_id', '=', auth()->user()->id);
}
elseif(in_array($this->entity_type,[Design::class, GroupSetting::class, PaymentTerm::class])){
// nlog($this->entity_type);
elseif(in_array($this->entity_type, [Design::class, GroupSetting::class, PaymentTerm::class, TaskStatus::class])){
nlog("inside");
nlog($this->entity_type);
}
else
$query->where('user_id', '=', auth()->user()->id)->orWhere('assigned_user_id', auth()->user()->id);
@ -1033,7 +1035,7 @@ class BaseController extends Controller
if ((bool) $this->checkAppSetup() !== false && $account = Account::first()) {
//always redirect invoicing.co to invoicing.co
if(Ninja::isHosted() && (request()->getSchemeAndHttpHost() != 'https://invoicing.co'))
if(Ninja::isHosted() && !in_array(request()->getSchemeAndHttpHost(), ['https://staging.invoicing.co', 'https://invoicing.co', 'https://demo.invoicing.co']))
return redirect()->secure('https://invoicing.co');
if (config('ninja.require_https') && ! request()->isSecure()) {

View file

@ -238,8 +238,8 @@ class RequiredClientInfo extends Component
if($cg && $cg->update_details){
$payment_gateway = $cg->driver($this->client)->init();
if(method_exists($payment_gateway, "updateCustomer"))
$payment_gateway->updateCustomer();
// if(method_exists($payment_gateway, "updateCustomer"))
// $payment_gateway->updateCustomer();
}
return true;

View file

@ -11,9 +11,10 @@
namespace App\Http\Requests\BankTransactionRule;
use App\Models\Account;
use App\Http\Requests\Request;
use App\Models\BankTransactionRule;
use App\Utils\Traits\MakesHash;
use App\Models\BankTransactionRule;
class StoreBankTransactionRuleRequest extends Request
{
@ -26,7 +27,7 @@ class StoreBankTransactionRuleRequest extends Request
*/
public function authorize() : bool
{
return auth()->user()->can('create', BankTransactionRule::class);
return auth()->user()->can('create', BankTransactionRule::class) && auth()->user()->account->hasFeature(Account::FEATURE_API);;
}
public function rules()

View file

@ -11,6 +11,7 @@
namespace App\Http\Requests\Design;
use App\Models\Account;
use App\Http\Requests\Request;
class StoreDesignRequest extends Request
@ -22,7 +23,7 @@ class StoreDesignRequest extends Request
*/
public function authorize() : bool
{
return auth()->user()->isAdmin();
return auth()->user()->isAdmin() && auth()->user()->account->hasFeature(Account::FEATURE_API);;
}
public function rules()

View file

@ -11,10 +11,11 @@
namespace App\Http\Requests\GroupSetting;
use App\DataMapper\ClientSettings;
use App\Http\Requests\Request;
use App\Http\ValidationRules\ValidClientGroupSettingsRule;
use App\Models\Account;
use App\Models\GroupSetting;
use App\Http\Requests\Request;
use App\DataMapper\ClientSettings;
use App\Http\ValidationRules\ValidClientGroupSettingsRule;
class StoreGroupSettingRequest extends Request
{
@ -25,7 +26,7 @@ class StoreGroupSettingRequest extends Request
*/
public function authorize() : bool
{
return auth()->user()->can('create', GroupSetting::class);
return auth()->user()->can('create', GroupSetting::class) && auth()->user()->account->hasFeature(Account::FEATURE_API);
}
public function rules()

View file

@ -11,8 +11,9 @@
namespace App\Http\Requests\Subscription;
use App\Http\Requests\Request;
use App\Models\Account;
use App\Models\Subscription;
use App\Http\Requests\Request;
use Illuminate\Validation\Rule;
class StoreSubscriptionRequest extends Request
@ -24,7 +25,7 @@ class StoreSubscriptionRequest extends Request
*/
public function authorize()
{
return auth()->user()->can('create', Subscription::class);
return auth()->user()->can('create', Subscription::class) && auth()->user()->account->hasFeature(Account::FEATURE_API);
}
/**

View file

@ -11,6 +11,7 @@
namespace App\Http\Requests\Webhook;
use App\Models\Account;
use App\Http\Requests\Request;
class StoreWebhookRequest extends Request
@ -22,7 +23,7 @@ class StoreWebhookRequest extends Request
*/
public function authorize() : bool
{
return auth()->user()->isAdmin();
return auth()->user()->isAdmin() && auth()->user()->account->hasFeature(Account::FEATURE_API);
}
public function rules()

View file

@ -76,19 +76,15 @@ class CreateEntityPdf implements ShouldQueue
$this->invitation = $invitation;
if ($invitation instanceof InvoiceInvitation) {
// $invitation->load('contact.client.company','invoice.client','invoice.user.account');
$this->entity = $invitation->invoice;
$this->entity_string = 'invoice';
} elseif ($invitation instanceof QuoteInvitation) {
// $invitation->load('contact.client.company','quote.client','quote.user.account');
$this->entity = $invitation->quote;
$this->entity_string = 'quote';
} elseif ($invitation instanceof CreditInvitation) {
// $invitation->load('contact.client.company','credit.client','credit.user.account');
$this->entity = $invitation->credit;
$this->entity_string = 'credit';
} elseif ($invitation instanceof RecurringInvoiceInvitation) {
// $invitation->load('contact.client.company','recurring_invoice');
$this->entity = $invitation->recurring_invoice;
$this->entity_string = 'recurring_invoice';
}

View file

@ -19,25 +19,16 @@ use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\Middleware\WithoutOverlapping;
use Illuminate\Queue\SerializesModels;
class ClientLedgerBalanceUpdate implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
public $tries = 1;
public $company;
public $client;
public $deleteWhenMissingModels = true;
public function __construct(Company $company, Client $client)
{
$this->company = $company;
$this->client = $client;
}
public function __construct(public Company $company, public Client $client)
{}
/**
* Execute the job.
@ -78,4 +69,11 @@ class ClientLedgerBalanceUpdate implements ShouldQueue
});
}
public function middleware()
{
return [(new WithoutOverlapping($this->client->id))->dontRelease()];
}
}

View file

@ -225,7 +225,7 @@ class NinjaMailerJob implements ShouldQueue
switch ($class) {
case Invoice::class:
event(new InvoiceWasEmailedAndFailed($this->nmo->invitation, $this->nmo->company, $message, $this->nmo->reminder_template, Ninja::eventVars(auth()->user() ? auth()->user()->id : null)));
event(new InvoiceWasEmailedAndFailed($this->nmo->invitation, $this->nmo->company, $message, $this->nmo->template, Ninja::eventVars(auth()->user() ? auth()->user()->id : null)));
break;
case Payment::class:
event(new PaymentWasEmailedAndFailed($this->nmo->entity, $this->nmo->company, $message, Ninja::eventVars(auth()->user() ? auth()->user()->id : null)));
@ -578,7 +578,7 @@ class NinjaMailerJob implements ShouldQueue
* Logs any errors to the SystemLog
*
* @param string $errors
* @param App\Models\User | App\Models\Client $recipient_object
* @param App\Models\User | App\Models\Client | null $recipient_object
* @return void
*/
private function logMailError($errors, $recipient_object) :void

View file

@ -77,7 +77,7 @@ class ZipPurchaseOrders implements ShouldQueue
// create new zip object
$zipFile = new \PhpZip\ZipFile();
$file_name = date('Y-m-d').'_'.str_replace(' ', '_', trans('texts.invoices')).'.zip';
$file_name = date('Y-m-d').'_'.str_replace(' ', '_', trans('texts.purchase_orders')).'.zip';
$invitation = $this->purchase_orders->first()->invitations->first();
$path = $this->purchase_orders->first()->vendor->purchase_order_filepath($invitation);

View file

@ -56,9 +56,5 @@ class QuoteWorkflowSettings implements ShouldQueue
$this->quote->service()->sendEmail($invitation->contact);
});
}
// if ($this->client->getSetting('auto_archive_quote')) {
// $this->base_repository->archive($this->quote);
// }
}
}

View file

@ -50,6 +50,7 @@ class WebhookSingle implements ShouldQueue
private string $includes;
private Company $company;
/**
* Create a new job instance.
*
@ -125,48 +126,47 @@ class WebhookSingle implements ShouldQueue
RequestOptions::JSON => $data, // or 'json' => [...]
]);
SystemLogger::dispatch(
(new SystemLogger(
array_merge((array) $response, $data),
SystemLog::CATEGORY_WEBHOOK,
SystemLog::EVENT_WEBHOOK_SUCCESS,
SystemLog::TYPE_WEBHOOK_RESPONSE,
$this->resolveClient(),
$this->company
);
}
catch(\GuzzleHttp\Exception\ConnectException $e){
))->handle();
} catch(\GuzzleHttp\Exception\ConnectException $e) {
nlog("connection problem");
nlog($e->getCode());
nlog($e->getMessage());
SystemLogger::dispatch(
(new SystemLogger(
['message' => "Error connecting to ". $subscription->target_url],
SystemLog::CATEGORY_WEBHOOK,
SystemLog::EVENT_WEBHOOK_FAILURE,
SystemLog::TYPE_WEBHOOK_RESPONSE,
$this->resolveClient(),
$this->company
);
}
catch (BadResponseException $e) {
if ($e->getResponse()->getStatusCode() >= 400 && $e->getResponse()->getStatusCode() < 500){
$message = "Server encountered a problem when connecting to {$subscription->target_url} => status code ". $e->getResponse()->getStatusCode(). " scheduling retry.";
))->handle();
} catch (BadResponseException $e) {
if ($e->getResponse()->getStatusCode() >= 400 && $e->getResponse()->getStatusCode() < 500) {
$message = "There was a problem when connecting to {$subscription->target_url} => status code ". $e->getResponse()->getStatusCode();
nlog($message);
SystemLogger::dispatch(
(new SystemLogger(
['message' => $message],
SystemLog::CATEGORY_WEBHOOK,
SystemLog::EVENT_WEBHOOK_FAILURE,
SystemLog::TYPE_WEBHOOK_RESPONSE,
$this->resolveClient(),
$this->company
);
))->handle();
/* Some 400's should never be repeated */
if(in_array($e->getResponse()->getStatusCode(), [404, 410])){
$this->fail();
return;
}
$this->release($this->backoff()[$this->attempts()-1]);
@ -175,16 +175,16 @@ class WebhookSingle implements ShouldQueue
if($e->getResponse()->getStatusCode() >= 500){
nlog("endpoint returned a 500, failing");
$message = "Server encountered a problem when connecting to {$subscription->target_url} => status code ". $e->getResponse()->getStatusCode(). " no retry attempted.";
$message = "The was a problem when connecting to {$subscription->target_url} => status code ". $e->getResponse()->getStatusCode(). " no retry attempted.";
SystemLogger::dispatch(
(new SystemLogger(
['message' => $message],
SystemLog::CATEGORY_WEBHOOK,
SystemLog::EVENT_WEBHOOK_FAILURE,
SystemLog::TYPE_WEBHOOK_RESPONSE,
$this->resolveClient(),
$this->company
);
))->handle();
$this->fail();
return;
@ -197,45 +197,38 @@ class WebhookSingle implements ShouldQueue
nlog("Server exception");
$error = json_decode($e->getResponse()->getBody()->getContents());
SystemLogger::dispatch(
(new SystemLogger(
['message' => $error],
SystemLog::CATEGORY_WEBHOOK,
SystemLog::EVENT_WEBHOOK_FAILURE,
SystemLog::TYPE_WEBHOOK_RESPONSE,
$this->resolveClient(),
$this->company
);
}
catch (ClientException $e) {
))->handle();
} catch (ClientException $e) {
nlog("Client exception");
$error = json_decode($e->getResponse()->getBody()->getContents());
SystemLogger::dispatch(
(new SystemLogger(
['message' => $error],
SystemLog::CATEGORY_WEBHOOK,
SystemLog::EVENT_WEBHOOK_FAILURE,
SystemLog::TYPE_WEBHOOK_RESPONSE,
$this->resolveClient(),
$this->company
);
}
catch (\Exception $e) {
))->handle();
} catch (\Exception $e) {
nlog("Exception handler => " . $e->getMessage());
nlog($e->getCode());
SystemLogger::dispatch(
(new SystemLogger(
$e->getMessage(),
SystemLog::CATEGORY_WEBHOOK,
SystemLog::EVENT_WEBHOOK_FAILURE,
SystemLog::TYPE_WEBHOOK_RESPONSE,
$this->resolveClient(),
$this->company,
);
))->handle();
$this->release($this->backoff()[$this->attempts()-1]);
@ -243,7 +236,7 @@ class WebhookSingle implements ShouldQueue
}
private function resolveClient()
{ nlog(get_class($this->entity));
{
//make sure it isn't an instance of the Client Model
if (!$this->entity instanceof \App\Models\Client &&
@ -255,9 +248,9 @@ class WebhookSingle implements ShouldQueue
return $this->entity->client;
}
return null;
}
public function failed($exception = null)

View file

@ -24,6 +24,8 @@ class CreditCreatedNotification implements ShouldQueue
{
use UserNotifies;
public $delay = 10;
public function __construct()
{
}
@ -65,10 +67,8 @@ class CreditCreatedNotification implements ShouldQueue
$nmo->to_user = $user;
NinjaMailerJob::dispatch($nmo);
(new NinjaMailerJob($nmo))->handle();
/* This prevents more than one notification being sent */
// $first_notification_sent = false;
}
/* Override the methods in the Notification Class */

View file

@ -62,14 +62,10 @@ class CreditEmailedNotification implements ShouldQueue
$nmo->to_user = $user;
NinjaMailerJob::dispatch($nmo);
(new NinjaMailerJob($nmo))->handle();
// $first_notification_sent = false;
}
// $notification->method = $methods;
// $user->notify($notification);
}
}
}

View file

@ -24,7 +24,7 @@ class InvoiceCreatedNotification implements ShouldQueue
{
use UserNotifies;
public $delay = 5;
public $delay = 7;
public function __construct()
{
@ -71,7 +71,7 @@ class InvoiceCreatedNotification implements ShouldQueue
$nmo->to_user = $user;
NinjaMailerJob::dispatch($nmo);
(new NinjaMailerJob($nmo))->handle();
/* This prevents more than one notification being sent */
$first_notification_sent = false;

View file

@ -24,7 +24,7 @@ class InvoiceEmailedNotification implements ShouldQueue
{
use UserNotifies;
public $delay = 5;
public $delay = 10;
public function __construct()
{
@ -69,7 +69,7 @@ class InvoiceEmailedNotification implements ShouldQueue
$nmo->to_user = $user;
NinjaMailerJob::dispatch($nmo);
(new NinjaMailerJob($nmo))->handle();
/* This prevents more than one notification being sent */
$first_notification_sent = false;

View file

@ -29,6 +29,8 @@ class InvoiceFailedEmailNotification
use UserNotifies, Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
public $delay = 7;
public function __construct()
{
}
@ -63,7 +65,7 @@ class InvoiceFailedEmailNotification
$nmo->to_user = $user;
NinjaMailerJob::dispatch($nmo);
(new NinjaMailerJob($nmo))->handle();
$first_notification_sent = false;
}

View file

@ -59,10 +59,5 @@ class InvoicePaidActivity implements ShouldQueue
$event->invoice->subscription->service()->planPaid($event->invoice);
}
try {
$event->invoice->service()->touchPdf();
} catch (\Exception $e) {
nlog(print_r($e->getMessage(), 1));
}
}
}

View file

@ -76,7 +76,7 @@ class InvitationViewedListener implements ShouldQueue
unset($methods[$key]);
$nmo->to_user = $company_user->user;
NinjaMailerJob::dispatch($nmo);
(new NinjaMailerJob($nmo))->handle();
}
}
}

View file

@ -39,7 +39,6 @@ class PaymentEmailedActivity implements ShouldQueue
public function handle($event)
{
MultiDB::setDb($event->company->db);
$payment = $event->payment;
}
}

View file

@ -26,7 +26,7 @@ class PaymentNotification implements ShouldQueue
{
use UserNotifies;
public $delay = 5;
public $delay = 20;
/**
* Create the event listener.
@ -74,7 +74,7 @@ class PaymentNotification implements ShouldQueue
$nmo->to_user = $user;
NinjaMailerJob::dispatch($nmo);
(new NinjaMailerJob($nmo))->handle();
}
}

View file

@ -67,7 +67,7 @@ class PurchaseOrderAcceptedListener implements ShouldQueue
$nmo->to_user = $user;
NinjaMailerJob::dispatch($nmo);
(new NinjaMailerJob($nmo))->handle();
/* This prevents more than one notification being sent */
$first_notification_sent = false;

View file

@ -25,6 +25,8 @@ class PurchaseOrderCreatedListener implements ShouldQueue
{
use UserNotifies;
public $delay = 7;
public function __construct()
{
}
@ -71,7 +73,7 @@ class PurchaseOrderCreatedListener implements ShouldQueue
$nmo->to_user = $user;
NinjaMailerJob::dispatch($nmo);
(new NinjaMailerJob($nmo))->handle();
/* This prevents more than one notification being sent */
$first_notification_sent = false;

View file

@ -69,7 +69,7 @@ class PurchaseOrderEmailedNotification implements ShouldQueue
$nmo->to_user = $user;
NinjaMailerJob::dispatch($nmo);
(new NinjaMailerJob($nmo))->handle();
/* This prevents more than one notification being sent */
$first_notification_sent = false;

View file

@ -25,7 +25,7 @@ class QuoteApprovedNotification implements ShouldQueue
{
use UserNotifies;
public $delay = 5;
public $delay = 8;
public function __construct()
{
@ -69,7 +69,7 @@ class QuoteApprovedNotification implements ShouldQueue
$nmo->to_user = $user;
NinjaMailerJob::dispatch($nmo);
(new NinjaMailerJob($nmo))->handle();
/* This prevents more than one notification being sent */
$first_notification_sent = false;

View file

@ -71,7 +71,7 @@ class QuoteCreatedNotification implements ShouldQueue
$nmo->to_user = $user;
NinjaMailerJob::dispatch($nmo);
(new NinjaMailerJob($nmo))->handle();
/* This prevents more than one notification being sent */
$first_notification_sent = false;

View file

@ -54,8 +54,6 @@ class QuoteEmailedNotification implements ShouldQueue
foreach ($event->invitation->company->company_users as $company_user) {
$user = $company_user->user;
// $notification = new EntitySentNotification($event->invitation, 'quote');
$methods = $this->findUserNotificationTypes($event->invitation, $company_user, 'quote', ['all_notifications', 'quote_sent', 'quote_sent_all', 'quote_sent_user']);
if (($key = array_search('mail', $methods)) !== false) {
@ -63,14 +61,10 @@ class QuoteEmailedNotification implements ShouldQueue
$nmo->to_user = $user;
NinjaMailerJob::dispatch($nmo);
(new NinjaMailerJob($nmo))->handle();
// $first_notification_sent = false;
}
// $notification->method = $methods;
// $user->notify($notification);
}
}
}

View file

@ -59,10 +59,6 @@ class AppStoreRenewSubscription implements ShouldQueue
$account->save();
// $server_notification = $event->getServerNotification();
// $subscription = $event->getSubscription();
// $subscription_identifier = $event->getSubscriptionIdentifier();
}
}

View file

@ -0,0 +1,49 @@
<?php
/**
* Invoice Ninja (https://invoiceninja.com).
*
* @link https://github.com/invoiceninja/invoiceninja source repository
*
* @copyright Copyright (c) 2023. Invoice Ninja LLC (https://invoiceninja.com)
*
* @license https://www.elastic.co/licensing/elastic-license
*/
namespace App\Listeners\Subscription;
use Carbon\Carbon;
use App\Models\Account;
use App\Models\Company;
use App\Libraries\MultiDB;
use Illuminate\Contracts\Queue\ShouldQueue;
use App\Notifications\Ninja\RenewalFailureNotification;
use Imdhemy\Purchases\Events\GooglePlay\SubscriptionRenewed;
class PlayStoreRenewSubscription implements ShouldQueue
{
public function handle(SubscriptionRenewed $event)
{
$notification = $event->getServerNotification();
nlog("google");
nlog($notification);
$in_app_identifier = $event->getSubscriptionIdentifier();
MultiDB::findAndSetDbByInappTransactionId($in_app_identifier);
$expirationTime = $event->getSubscription()->getExpiryTime();
$account = Account::where('inapp_transaction_id', $in_app_identifier)->first();
if ($account) {
$account->update(['plan_expires' => Carbon::parse($expirationTime)]);
}
if (!$account) {
$ninja_company = Company::on('db-ninja-01')->find(config('ninja.ninja_default_company_id'));
$ninja_company->notification(new RenewalFailureNotification("{$in_app_identifier}"))->ninja();
return;
}
}
}

View file

@ -16,6 +16,7 @@ use App\Utils\Ninja;
use App\Utils\Number;
use Illuminate\Support\Facades\App;
use stdClass;
use App\Models\Payment;
class EntityPaidObject
{
@ -29,7 +30,7 @@ class EntityPaidObject
public $settings;
public function __construct($payment)
public function __construct(public Payment $payment)
{
$this->payment = $payment;
$this->company = $payment->company;

View file

@ -330,7 +330,7 @@ class PaymentEmailEngine extends BaseEmailEngine
$invoice_list = '<br><br>';
foreach ($this->payment->invoices as $invoice) {
$invoice_list .= ctrans('texts.invoice_number_short')." {$invoice->number} - ".Number::formatMoney($invoice->pivot->amount, $this->client).'<br>';
$invoice_list .= ctrans('texts.invoice_number_short')." {$invoice->number} ".Number::formatMoney($invoice->pivot->amount, $this->client).'<br>';
}
return $invoice_list;

View file

@ -14,9 +14,7 @@ namespace App\Mail\Import;
use App\Models\Company;
use App\Utils\Ninja;
use Illuminate\Bus\Queueable;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\App;
class CsvImportCompleted extends Mailable

View file

@ -110,6 +110,7 @@ class Account extends BaseModel
const FEATURE_USERS = 'users'; // Grandfathered for old Pro users
const FEATURE_DOCUMENTS = 'documents';
const FEATURE_USER_PERMISSIONS = 'permissions';
const FEATURE_SUBSCRIPTIONS = 'subscriptions';
const RESULT_FAILURE = 'failure';
const RESULT_SUCCESS = 'success';

View file

@ -18,6 +18,7 @@ use App\Mail\ClientContact\ClientContactResetPasswordObject;
use App\Models\Presenters\ClientContactPresenter;
use App\Notifications\ClientContactResetPassword;
use App\Utils\Ninja;
use App\Utils\Traits\AppSetup;
use App\Utils\Traits\MakesHash;
use Illuminate\Contracts\Translation\HasLocalePreference;
use Illuminate\Database\Eloquent\Factories\HasFactory;
@ -40,7 +41,8 @@ class ClientContact extends Authenticatable implements HasLocalePreference
use PresentableTrait;
use SoftDeletes;
use HasFactory;
use AppSetup;
/* Used to authenticate a contact */
protected $guard = 'contact';

View file

@ -78,6 +78,8 @@ class CompanyGateway extends BaseModel
// const TYPE_WEPAY = 309;
// const TYPE_PAYFAST = 310;
// const TYPE_PAYTRACE = 311;
// const TYPE_MOLLIE = 312;
// const TYPE_EWAY = 313;
// const TYPE_FORTE = 314;
public $gateway_consts = [
@ -91,6 +93,8 @@ class CompanyGateway extends BaseModel
'8fdeed552015b3c7b44ed6c8ebd9e992' => 309,
'd6814fc83f45d2935e7777071e629ef9' => 310,
'bbd736b3254b0aabed6ad7fda1298c88' => 311,
'1bd651fb213ca0c9d66ae3c336dc77e7' => 312,
'944c20175bbe6b9972c05bcfe294c2c7' => 313,
'kivcvjexxvdiyqtj3mju5d6yhpeht2xs' => 314,
'65faab2ab6e3223dbe848b1686490baz' => 320,
'b9886f9257f0c6ee7c302f1c74475f6c' => 321,

View file

@ -11,7 +11,6 @@
namespace App\Models;
use App\Events\Credit\CreditWasUpdated;
use App\Jobs\Entity\CreateEntityPdf;
use App\Utils\Ninja;
use App\Utils\Traits\Inviteable;
@ -44,38 +43,6 @@ class CreditInvitation extends BaseModel
return self::class;
}
// public function getSignatureDateAttribute($value)
// {
// if (!$value) {
// return (new Carbon($value))->format('Y-m-d');
// }
// return $value;
// }
// public function getSentDateAttribute($value)
// {
// if (!$value) {
// return (new Carbon($value))->format('Y-m-d');
// }
// return $value;
// }
// public function getViewedDateAttribute($value)
// {
// if (!$value) {
// return (new Carbon($value))->format('Y-m-d');
// }
// return $value;
// }
// public function getOpenedDateAttribute($value)
// {
// if (!$value) {
// return (new Carbon($value))->format('Y-m-d');
// }
// return $value;
// }
public function entityType()
{
return Credit::class;
@ -129,7 +96,6 @@ class CreditInvitation extends BaseModel
$storage_path = Storage::url($this->credit->client->quote_filepath($this).$this->credit->numberFormatter().'.pdf');
if (! Storage::exists($this->credit->client->credit_filepath($this).$this->credit->numberFormatter().'.pdf')) {
event(new CreditWasUpdated($this->credit, $this->company, Ninja::eventVars(auth()->user() ? auth()->user()->id : null)));
(new CreateEntityPdf($this))->handle();
}

View file

@ -101,7 +101,6 @@ class QuoteInvitation extends BaseModel
$storage_path = Storage::url($this->quote->client->quote_filepath($this).$this->quote->numberFormatter().'.pdf');
if (! Storage::exists($this->quote->client->quote_filepath($this).$this->quote->numberFormatter().'.pdf')) {
event(new QuoteWasUpdated($this->quote, $this->company, Ninja::eventVars(auth()->user() ? auth()->user()->id : null)));
(new CreateEntityPdf($this))->handle();
}

View file

@ -29,7 +29,9 @@ class RenewalFailureNotification extends Notification
* @return void
*/
public function __construct(protected string $notification_message){}
public function __construct(protected ?string $notification_message)
{
}
/**
* Get the notification's delivery channels.

View file

@ -99,6 +99,16 @@ class BaseDriver extends AbstractPaymentDriver
* @return array[]
*/
public function init()
{
return $this;
}
public function updateCustomer()
{
return $this;
}
public function getClientRequiredFields(): array
{
$fields = [];

View file

@ -409,16 +409,13 @@ class EventServiceProvider extends ServiceProvider
],
InvoiceWasUpdated::class => [
UpdateInvoiceActivity::class,
CreateInvoicePdf::class,
],
InvoiceWasCreated::class => [
CreateInvoiceActivity::class,
InvoiceCreatedNotification::class,
// CreateInvoicePdf::class,
],
InvoiceWasPaid::class => [
InvoicePaidActivity::class,
CreateInvoicePdf::class,
],
InvoiceWasViewed::class => [
InvoiceViewedActivity::class,
@ -436,7 +433,6 @@ class EventServiceProvider extends ServiceProvider
],
InvoiceWasDeleted::class => [
InvoiceDeletedActivity::class,
CreateInvoicePdf::class,
],
InvoiceWasArchived::class => [
InvoiceArchivedActivity::class,
@ -455,7 +451,7 @@ class EventServiceProvider extends ServiceProvider
InvitationViewedListener::class,
],
PaymentWasEmailed::class => [
PaymentEmailedActivity::class,
// PaymentEmailedActivity::class,
],
PaymentWasEmailedAndFailed::class => [
// PaymentEmailFailureActivity::class,

View file

@ -33,8 +33,9 @@ use Illuminate\Support\Facades\Cache;
class BankMatchingService implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
public function __construct(public $company_id, public $db){}
public function __construct(public $company_id, public $db)
{
}
public function handle() :void
{

View file

@ -59,7 +59,7 @@ class Merge extends AbstractService
/* Loop through contacts an only merge distinct contacts by email */
$this->mergable_client->contacts->each(function ($contact) {
$exist = $this->client->contacts->contains(function ($client_contact) use ($contact) {
return $client_contact->email == $contact->email;
return $client_contact->email == $contact->email || empty($contact->email) || $contact->email == ' ';
});
if ($exist) {

View file

@ -138,6 +138,7 @@ class ApplyPayment
->updateBalance($this->amount_applied * -1)
->updatePaidToDate($this->amount_applied)
->updateStatus()
->touchPdf()
->save();
$this->credit

View file

@ -11,11 +11,11 @@
namespace App\Services\Email;
use App\Models\Client;
use App\Models\ClientContact;
use App\Models\Company;
use App\Models\User;
use App\Models\Client;
use App\Models\Vendor;
use App\Models\Company;
use App\Models\ClientContact;
use App\Models\VendorContact;
use Illuminate\Mail\Mailables\Address;
@ -79,6 +79,7 @@ class EmailObject
public ?string $entity_class = null;
public array $variables = [];
}
public array $variables = [];
public ?Company $company = null;
}

View file

@ -17,6 +17,7 @@ use App\Models\Scheduler;
use App\Utils\Traits\MakesDates;
use App\Utils\Traits\MakesHash;
use Carbon\Carbon;
use App\DataMapper\Schedule\EmailStatement;
class SchedulerService
{
@ -39,8 +40,8 @@ class SchedulerService
$this->{$this->scheduler->template}();
}
private function client_statement()
{
private function email_statement()
{
$query = Client::query()
->where('company_id', $this->scheduler->company_id)
->where('is_deleted',0);
@ -93,14 +94,17 @@ class SchedulerService
private function calculateStartAndEndDates(): array
{
return match ($this->scheduler->parameters['date_range']) {
'this_month' => [now()->startOfDay()->firstOfMonth()->format('Y-m-d'), now()->startOfDay()->lastOfMonth()->format('Y-m-d')],
'this_quarter' => [now()->startOfDay()->firstOfQuarter()->format('Y-m-d'), now()->startOfDay()->lastOfQuarter()->format('Y-m-d')],
'this_year' => [now()->startOfDay()->firstOfYear()->format('Y-m-d'), now()->startOfDay()->lastOfYear()->format('Y-m-d')],
'previous_month' => [now()->startOfDay()->subMonthNoOverflow()->firstOfMonth()->format('Y-m-d'), now()->startOfDay()->subMonthNoOverflow()->lastOfMonth()->format('Y-m-d')],
'previous_quarter' => [now()->startOfDay()->subQuarterNoOverflow()->firstOfQuarter()->format('Y-m-d'), now()->startOfDay()->subQuarterNoOverflow()->lastOfQuarter()->format('Y-m-d')],
'previous_year' => [now()->startOfDay()->subYearNoOverflow()->firstOfYear()->format('Y-m-d'), now()->startOfDay()->subYearNoOverflow()->lastOfYear()->format('Y-m-d')],
'custom_range' => [$this->scheduler->parameters['start_date'], $this->scheduler->parameters['end_date']],
default => [now()->startOfDay()->firstOfMonth()->format('Y-m-d'), now()->startOfDay()->lastOfMonth()->format('Y-m-d')],
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()->firstOfQuarter()->format('Y-m-d'), now()->startOfDay()->lastOfQuarter()->format('Y-m-d')],
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']],
default => [now()->startOfDay()->firstOfMonth()->format('Y-m-d'), now()->startOfDay()->lastOfMonth()->format('Y-m-d')],
};
}

View file

@ -139,6 +139,8 @@ class Number
$value = floatval($value);
$_value = $value;
$currency = $entity->currency();
$thousand = $currency->thousand_separator;
@ -179,6 +181,15 @@ class Number
} elseif ($swapSymbol) {
return "{$value} ".trim($symbol);
} elseif ($entity->getSetting('show_currency_code') === false) {
/* Ensures we place the negative symbol ahead of the currency symbol*/
if($_value < 0){
$value = substr($value, 1);
$symbol = "-{$symbol}";
}
return "{$symbol}{$value}";
} else {
return self::formatValue($value, $currency);

View file

@ -74,7 +74,7 @@
"omnipay/paypal": "^3.0",
"payfast/payfast-php-sdk": "^1.1",
"pragmarx/google2fa": "^8.0",
"predis/predis": "2.*",
"turbo124/predis": "1.1.11",
"razorpay/razorpay": "2.*",
"sentry/sentry-laravel": "^3",
"setasign/fpdf": "^1.8",

274
composer.lock generated
View file

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "0ac024e516d3ec373954f9da6e3d6256",
"content-hash": "0c7d0b98049debcdc39406241b36770a",
"packages": [
{
"name": "afosto/yaac",
@ -379,16 +379,16 @@
},
{
"name": "aws/aws-sdk-php",
"version": "3.258.5",
"version": "3.258.10",
"source": {
"type": "git",
"url": "https://github.com/aws/aws-sdk-php.git",
"reference": "c29a1db83373f8a5c4735acfdd3470e1bc594fee"
"reference": "e164c9c5faf3965bd27ff2a4e9b7b3048ba8a337"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/c29a1db83373f8a5c4735acfdd3470e1bc594fee",
"reference": "c29a1db83373f8a5c4735acfdd3470e1bc594fee",
"url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/e164c9c5faf3965bd27ff2a4e9b7b3048ba8a337",
"reference": "e164c9c5faf3965bd27ff2a4e9b7b3048ba8a337",
"shasum": ""
},
"require": {
@ -467,9 +467,9 @@
"support": {
"forum": "https://forums.aws.amazon.com/forum.jspa?forumID=80",
"issues": "https://github.com/aws/aws-sdk-php/issues",
"source": "https://github.com/aws/aws-sdk-php/tree/3.258.5"
"source": "https://github.com/aws/aws-sdk-php/tree/3.258.10"
},
"time": "2023-02-07T19:22:14+00:00"
"time": "2023-02-14T19:21:16+00:00"
},
{
"name": "bacon/bacon-qr-code",
@ -1909,16 +1909,16 @@
},
{
"name": "firebase/php-jwt",
"version": "v6.3.2",
"version": "v6.4.0",
"source": {
"type": "git",
"url": "https://github.com/firebase/php-jwt.git",
"reference": "ea7dda77098b96e666c5ef382452f94841e439cd"
"reference": "4dd1e007f22a927ac77da5a3fbb067b42d3bc224"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/firebase/php-jwt/zipball/ea7dda77098b96e666c5ef382452f94841e439cd",
"reference": "ea7dda77098b96e666c5ef382452f94841e439cd",
"url": "https://api.github.com/repos/firebase/php-jwt/zipball/4dd1e007f22a927ac77da5a3fbb067b42d3bc224",
"reference": "4dd1e007f22a927ac77da5a3fbb067b42d3bc224",
"shasum": ""
},
"require": {
@ -1933,6 +1933,7 @@
"psr/http-factory": "^1.0"
},
"suggest": {
"ext-sodium": "Support EdDSA (Ed25519) signatures",
"paragonie/sodium_compat": "Support EdDSA (Ed25519) signatures when libsodium is not present"
},
"type": "library",
@ -1965,9 +1966,9 @@
],
"support": {
"issues": "https://github.com/firebase/php-jwt/issues",
"source": "https://github.com/firebase/php-jwt/tree/v6.3.2"
"source": "https://github.com/firebase/php-jwt/tree/v6.4.0"
},
"time": "2022-12-19T17:10:46+00:00"
"time": "2023-02-09T21:01:23+00:00"
},
{
"name": "fruitcake/php-cors",
@ -2042,16 +2043,16 @@
},
{
"name": "gocardless/gocardless-pro",
"version": "4.25.0",
"version": "4.26.0",
"source": {
"type": "git",
"url": "https://github.com/gocardless/gocardless-pro-php.git",
"reference": "ebaed83ae21cf40d7eb05f568c26f88d2cae1e5a"
"reference": "a8595043eb13d597e8d11c4c1bfb0e040696e6b7"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/gocardless/gocardless-pro-php/zipball/ebaed83ae21cf40d7eb05f568c26f88d2cae1e5a",
"reference": "ebaed83ae21cf40d7eb05f568c26f88d2cae1e5a",
"url": "https://api.github.com/repos/gocardless/gocardless-pro-php/zipball/a8595043eb13d597e8d11c4c1bfb0e040696e6b7",
"reference": "a8595043eb13d597e8d11c4c1bfb0e040696e6b7",
"shasum": ""
},
"require": {
@ -2091,9 +2092,9 @@
],
"support": {
"issues": "https://github.com/gocardless/gocardless-pro-php/issues",
"source": "https://github.com/gocardless/gocardless-pro-php/tree/v4.25.0"
"source": "https://github.com/gocardless/gocardless-pro-php/tree/v4.26.0"
},
"time": "2023-01-31T13:01:05+00:00"
"time": "2023-02-14T11:07:20+00:00"
},
{
"name": "google/apiclient",
@ -2167,16 +2168,16 @@
},
{
"name": "google/apiclient-services",
"version": "v0.286.0",
"version": "v0.287.0",
"source": {
"type": "git",
"url": "https://github.com/googleapis/google-api-php-client-services.git",
"reference": "4a00eb9803e01f97d96e49fd82dbb03802610def"
"reference": "ed58596d34272a5cd0dc2c0595d9a678b9834880"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/googleapis/google-api-php-client-services/zipball/4a00eb9803e01f97d96e49fd82dbb03802610def",
"reference": "4a00eb9803e01f97d96e49fd82dbb03802610def",
"url": "https://api.github.com/repos/googleapis/google-api-php-client-services/zipball/ed58596d34272a5cd0dc2c0595d9a678b9834880",
"reference": "ed58596d34272a5cd0dc2c0595d9a678b9834880",
"shasum": ""
},
"require": {
@ -2205,9 +2206,9 @@
],
"support": {
"issues": "https://github.com/googleapis/google-api-php-client-services/issues",
"source": "https://github.com/googleapis/google-api-php-client-services/tree/v0.286.0"
"source": "https://github.com/googleapis/google-api-php-client-services/tree/v0.287.0"
},
"time": "2023-02-05T01:20:11+00:00"
"time": "2023-02-12T01:08:11+00:00"
},
{
"name": "google/auth",
@ -3576,16 +3577,16 @@
},
{
"name": "laravel/framework",
"version": "v9.51.0",
"version": "v9.52.0",
"source": {
"type": "git",
"url": "https://github.com/laravel/framework.git",
"reference": "b81123134349a013a738a9f7f715c6ce99d5a414"
"reference": "eb85cd9d72e5bfa54b4d0d9040786f26d6184a9e"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/laravel/framework/zipball/b81123134349a013a738a9f7f715c6ce99d5a414",
"reference": "b81123134349a013a738a9f7f715c6ce99d5a414",
"url": "https://api.github.com/repos/laravel/framework/zipball/eb85cd9d72e5bfa54b4d0d9040786f26d6184a9e",
"reference": "eb85cd9d72e5bfa54b4d0d9040786f26d6184a9e",
"shasum": ""
},
"require": {
@ -3770,7 +3771,7 @@
"issues": "https://github.com/laravel/framework/issues",
"source": "https://github.com/laravel/framework"
},
"time": "2023-02-07T15:37:18+00:00"
"time": "2023-02-14T14:51:14+00:00"
},
{
"name": "laravel/serializable-closure",
@ -7092,76 +7093,6 @@
},
"time": "2022-06-13T21:57:56+00:00"
},
{
"name": "predis/predis",
"version": "v2.1.1",
"source": {
"type": "git",
"url": "https://github.com/predis/predis.git",
"reference": "c5b60884e89630f9518a7919f0566db438f0fc9a"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/predis/predis/zipball/c5b60884e89630f9518a7919f0566db438f0fc9a",
"reference": "c5b60884e89630f9518a7919f0566db438f0fc9a",
"shasum": ""
},
"require": {
"php": "^7.2 || ^8.0"
},
"require-dev": {
"phpunit/phpunit": "^8.0 || ~9.4.4"
},
"suggest": {
"ext-curl": "Allows access to Webdis when paired with phpiredis"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-main": "2.0-dev"
}
},
"autoload": {
"psr-4": {
"Predis\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Till Krüss",
"homepage": "https://till.im",
"role": "Maintainer"
},
{
"name": "Daniele Alessandri",
"email": "suppakilla@gmail.com",
"homepage": "http://clorophilla.net",
"role": "Creator"
}
],
"description": "A flexible and feature-complete Redis client for PHP.",
"homepage": "http://github.com/predis/predis",
"keywords": [
"nosql",
"predis",
"redis"
],
"support": {
"issues": "https://github.com/predis/predis/issues",
"source": "https://github.com/predis/predis/tree/v2.1.1"
},
"funding": [
{
"url": "https://github.com/sponsors/tillkruss",
"type": "github"
}
],
"time": "2023-01-17T20:57:35+00:00"
},
{
"name": "psr/cache",
"version": "3.0.0",
@ -8255,16 +8186,16 @@
},
{
"name": "sentry/sentry",
"version": "3.13.0",
"version": "3.13.1",
"source": {
"type": "git",
"url": "https://github.com/getsentry/sentry-php.git",
"reference": "a046ff5a37f5a0a0c285a6543dc17a7fc93b47f8"
"reference": "71c86fe4699a7f1a40c7d985f3dc7667045152f0"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/getsentry/sentry-php/zipball/a046ff5a37f5a0a0c285a6543dc17a7fc93b47f8",
"reference": "a046ff5a37f5a0a0c285a6543dc17a7fc93b47f8",
"url": "https://api.github.com/repos/getsentry/sentry-php/zipball/71c86fe4699a7f1a40c7d985f3dc7667045152f0",
"reference": "71c86fe4699a7f1a40c7d985f3dc7667045152f0",
"shasum": ""
},
"require": {
@ -8276,7 +8207,7 @@
"php": "^7.2|^8.0",
"php-http/async-client-implementation": "^1.0",
"php-http/client-common": "^1.5|^2.0",
"php-http/discovery": "^1.11",
"php-http/discovery": "^1.11, <1.15",
"php-http/httplug": "^1.1|^2.0",
"php-http/message": "^1.5",
"psr/http-factory": "^1.0",
@ -8343,7 +8274,7 @@
],
"support": {
"issues": "https://github.com/getsentry/sentry-php/issues",
"source": "https://github.com/getsentry/sentry-php/tree/3.13.0"
"source": "https://github.com/getsentry/sentry-php/tree/3.13.1"
},
"funding": [
{
@ -8355,7 +8286,7 @@
"type": "custom"
}
],
"time": "2023-02-03T10:03:13+00:00"
"time": "2023-02-10T10:17:57+00:00"
},
{
"name": "sentry/sentry-laravel",
@ -8498,16 +8429,16 @@
},
{
"name": "setasign/fpdi",
"version": "v2.3.6",
"version": "v2.3.7",
"source": {
"type": "git",
"url": "https://github.com/Setasign/FPDI.git",
"reference": "6231e315f73e4f62d72b73f3d6d78ff0eed93c31"
"reference": "bccc892d5fa1f48c43f8ba7db5ed4ba6f30c8c05"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/Setasign/FPDI/zipball/6231e315f73e4f62d72b73f3d6d78ff0eed93c31",
"reference": "6231e315f73e4f62d72b73f3d6d78ff0eed93c31",
"url": "https://api.github.com/repos/Setasign/FPDI/zipball/bccc892d5fa1f48c43f8ba7db5ed4ba6f30c8c05",
"reference": "bccc892d5fa1f48c43f8ba7db5ed4ba6f30c8c05",
"shasum": ""
},
"require": {
@ -8558,7 +8489,7 @@
],
"support": {
"issues": "https://github.com/Setasign/FPDI/issues",
"source": "https://github.com/Setasign/FPDI/tree/v2.3.6"
"source": "https://github.com/Setasign/FPDI/tree/v2.3.7"
},
"funding": [
{
@ -8566,20 +8497,20 @@
"type": "tidelift"
}
],
"time": "2021-02-11T11:37:01+00:00"
"time": "2023-02-09T10:38:43+00:00"
},
{
"name": "socialiteproviders/apple",
"version": "5.3.0",
"version": "5.3.1",
"source": {
"type": "git",
"url": "https://github.com/SocialiteProviders/Apple.git",
"reference": "13bfd5ad4a6ab33ecab35d933deba01e9de6e404"
"reference": "f3b9a435e302b1a3d9a50285e934a6be66b2754a"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/SocialiteProviders/Apple/zipball/13bfd5ad4a6ab33ecab35d933deba01e9de6e404",
"reference": "13bfd5ad4a6ab33ecab35d933deba01e9de6e404",
"url": "https://api.github.com/repos/SocialiteProviders/Apple/zipball/f3b9a435e302b1a3d9a50285e934a6be66b2754a",
"reference": "f3b9a435e302b1a3d9a50285e934a6be66b2754a",
"shasum": ""
},
"require": {
@ -8637,7 +8568,7 @@
"issues": "https://github.com/socialiteproviders/providers/issues",
"source": "https://github.com/socialiteproviders/providers"
},
"time": "2022-07-18T08:37:00+00:00"
"time": "2023-02-11T04:00:50+00:00"
},
{
"name": "socialiteproviders/manager",
@ -12292,17 +12223,83 @@
"time": "2023-01-29T00:13:12+00:00"
},
{
"name": "twilio/sdk",
"version": "6.44.2",
"name": "turbo124/predis",
"version": "v1.1.11",
"source": {
"type": "git",
"url": "git@github.com:twilio/twilio-php.git",
"reference": "deec3203857387213825e2634c4eb4b56880877a"
"url": "https://github.com/turbo124/predis.git",
"reference": "3ebce475e48ed0842dbe6f252ae55a4523b35116"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/twilio/twilio-php/zipball/deec3203857387213825e2634c4eb4b56880877a",
"reference": "deec3203857387213825e2634c4eb4b56880877a",
"url": "https://api.github.com/repos/turbo124/predis/zipball/3ebce475e48ed0842dbe6f252ae55a4523b35116",
"reference": "3ebce475e48ed0842dbe6f252ae55a4523b35116",
"shasum": ""
},
"require": {
"php": ">=5.3.9"
},
"require-dev": {
"phpunit/phpunit": "~4.8"
},
"suggest": {
"ext-curl": "Allows access to Webdis when paired with phpiredis",
"ext-phpiredis": "Allows faster serialization and deserialization of the Redis protocol"
},
"type": "library",
"autoload": {
"psr-4": {
"Predis\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Daniele Alessandri",
"email": "suppakilla@gmail.com",
"homepage": "http://clorophilla.net",
"role": "Creator & Maintainer"
},
{
"name": "Till Krüss",
"homepage": "https://till.im",
"role": "Maintainer"
}
],
"description": "Flexible and feature-complete Redis client for PHP and HHVM",
"homepage": "http://github.com/predis/predis",
"keywords": [
"nosql",
"predis",
"redis"
],
"support": {
"issues": "https://github.com/predis/predis/issues",
"source": "https://github.com/turbo124/predis/tree/v1.1.11"
},
"funding": [
{
"url": "https://github.com/sponsors/tillkruss",
"type": "github"
}
],
"time": "2022-10-28T04:36:19+00:00"
},
{
"name": "twilio/sdk",
"version": "6.44.3",
"source": {
"type": "git",
"url": "git@github.com:twilio/twilio-php.git",
"reference": "0e3e513d3c428f08bde195c579cbc0788415190f"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/twilio/twilio-php/zipball/0e3e513d3c428f08bde195c579cbc0788415190f",
"reference": "0e3e513d3c428f08bde195c579cbc0788415190f",
"shasum": ""
},
"require": {
@ -12310,7 +12307,7 @@
},
"require-dev": {
"guzzlehttp/guzzle": "^6.3 || ^7.0",
"phpunit/phpunit": ">=7.0"
"phpunit/phpunit": ">=7.0 < 10"
},
"suggest": {
"guzzlehttp/guzzle": "An HTTP client to execute the API requests"
@ -12338,7 +12335,7 @@
"sms",
"twilio"
],
"time": "2023-01-25T19:34:30+00:00"
"time": "2023-02-08T20:09:20+00:00"
},
{
"name": "vlucas/phpdotenv",
@ -14549,37 +14546,38 @@
},
{
"name": "php-webdriver/webdriver",
"version": "1.13.1",
"version": "1.14.0",
"source": {
"type": "git",
"url": "https://github.com/php-webdriver/php-webdriver.git",
"reference": "6dfe5f814b796c1b5748850aa19f781b9274c36c"
"reference": "3ea4f924afb43056bf9c630509e657d951608563"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/php-webdriver/php-webdriver/zipball/6dfe5f814b796c1b5748850aa19f781b9274c36c",
"reference": "6dfe5f814b796c1b5748850aa19f781b9274c36c",
"url": "https://api.github.com/repos/php-webdriver/php-webdriver/zipball/3ea4f924afb43056bf9c630509e657d951608563",
"reference": "3ea4f924afb43056bf9c630509e657d951608563",
"shasum": ""
},
"require": {
"ext-curl": "*",
"ext-json": "*",
"ext-zip": "*",
"php": "^5.6 || ~7.0 || ^8.0",
"php": "^7.3 || ^8.0",
"symfony/polyfill-mbstring": "^1.12",
"symfony/process": "^2.8 || ^3.1 || ^4.0 || ^5.0 || ^6.0"
"symfony/process": "^5.0 || ^6.0"
},
"replace": {
"facebook/webdriver": "*"
},
"require-dev": {
"ondram/ci-detector": "^2.1 || ^3.5 || ^4.0",
"ergebnis/composer-normalize": "^2.20.0",
"ondram/ci-detector": "^4.0",
"php-coveralls/php-coveralls": "^2.4",
"php-mock/php-mock-phpunit": "^1.1 || ^2.0",
"php-mock/php-mock-phpunit": "^2.0",
"php-parallel-lint/php-parallel-lint": "^1.2",
"phpunit/phpunit": "^5.7 || ^7 || ^8 || ^9",
"phpunit/phpunit": "^9.3",
"squizlabs/php_codesniffer": "^3.5",
"symfony/var-dumper": "^3.3 || ^4.0 || ^5.0 || ^6.0"
"symfony/var-dumper": "^5.0 || ^6.0"
},
"suggest": {
"ext-SimpleXML": "For Firefox profile creation"
@ -14608,9 +14606,9 @@
],
"support": {
"issues": "https://github.com/php-webdriver/php-webdriver/issues",
"source": "https://github.com/php-webdriver/php-webdriver/tree/1.13.1"
"source": "https://github.com/php-webdriver/php-webdriver/tree/1.14.0"
},
"time": "2022-10-11T11:49:44+00:00"
"time": "2023-02-09T12:12:19+00:00"
},
{
"name": "phpdocumentor/reflection-common",

View file

@ -201,7 +201,7 @@ return [
App\Providers\MultiDBProvider::class,
App\Providers\ClientPortalServiceProvider::class,
App\Providers\NinjaTranslationServiceProvider::class,
App\Providers\MailCssInlinerServiceProvider::class,
// App\Providers\MailCssInlinerServiceProvider::class,
],
/*

View file

@ -14,8 +14,8 @@ return [
'require_https' => env('REQUIRE_HTTPS', true),
'app_url' => rtrim(env('APP_URL', ''), '/'),
'app_domain' => env('APP_DOMAIN', 'invoicing.co'),
'app_version' => '5.5.70',
'app_tag' => '5.5.70',
'app_version' => '5.5.71',
'app_tag' => '5.5.71',
'minimum_client_version' => '5.0.16',
'terms_version' => '1.0.1',
'api_secret' => env('API_SECRET', ''),

View file

@ -1,35 +1,36 @@
<?php
use App\Listeners\Subscription\AppStoreRenewSubscription;
use Imdhemy\Purchases\Events\AppStore\Cancel;
use Imdhemy\Purchases\Events\AppStore\DidChangeRenewalPref;
use Imdhemy\Purchases\Events\AppStore\DidChangeRenewalStatus;
use Imdhemy\Purchases\Events\AppStore\DidFailToRenew;
use Imdhemy\Purchases\Events\AppStore\DidRecover;
use Imdhemy\Purchases\Events\AppStore\DidRenew;
use Imdhemy\Purchases\Events\AppStore\InitialBuy;
use Imdhemy\Purchases\Events\AppStore\InteractiveRenewal;
use Imdhemy\Purchases\Events\AppStore\PriceIncreaseConsent;
use Imdhemy\Purchases\Events\AppStore\Refund;
use Imdhemy\Purchases\Events\AppStore\Revoke;
use Imdhemy\Purchases\Events\AppStore\DidRenew;
use Imdhemy\Purchases\Events\AppStore\DidRecover;
use Imdhemy\Purchases\Events\AppStore\InitialBuy;
use Imdhemy\Purchases\Events\AppStore\DidFailToRenew;
use App\Listeners\Subscription\AppStoreRenewSubscription;
use Imdhemy\Purchases\Events\AppStore\InteractiveRenewal;
use App\Listeners\Subscription\PlayStoreRenewSubscription;
use Imdhemy\Purchases\Events\AppStore\DidChangeRenewalPref;
use Imdhemy\Purchases\Events\AppStore\PriceIncreaseConsent;
use Imdhemy\Purchases\Events\GooglePlay\SubscriptionOnHold;
use Imdhemy\Purchases\Events\GooglePlay\SubscriptionPaused;
use Imdhemy\Purchases\Events\GooglePlay\SubscriptionExpired;
use Imdhemy\Purchases\Events\GooglePlay\SubscriptionRenewed;
use Imdhemy\Purchases\Events\GooglePlay\SubscriptionRevoked;
use Imdhemy\Purchases\Events\AppStore\DidChangeRenewalStatus;
use Imdhemy\Purchases\Events\GooglePlay\SubscriptionCanceled;
use Imdhemy\Purchases\Events\GooglePlay\SubscriptionDeferred;
use Imdhemy\Purchases\Events\GooglePlay\SubscriptionExpired;
use Imdhemy\Purchases\Events\GooglePlay\SubscriptionInGracePeriod;
use Imdhemy\Purchases\Events\GooglePlay\SubscriptionOnHold;
use Imdhemy\Purchases\Events\GooglePlay\SubscriptionPauseScheduleChanged;
use Imdhemy\Purchases\Events\GooglePlay\SubscriptionPaused;
use Imdhemy\Purchases\Events\GooglePlay\SubscriptionPriceChangeConfirmed;
use Imdhemy\Purchases\Events\GooglePlay\SubscriptionPurchased;
use Imdhemy\Purchases\Events\GooglePlay\SubscriptionRecovered;
use Imdhemy\Purchases\Events\GooglePlay\SubscriptionRenewed;
use Imdhemy\Purchases\Events\GooglePlay\SubscriptionRestarted;
use Imdhemy\Purchases\Events\GooglePlay\SubscriptionRevoked;
use Imdhemy\Purchases\Events\GooglePlay\SubscriptionInGracePeriod;
use Imdhemy\Purchases\Events\GooglePlay\SubscriptionPauseScheduleChanged;
use Imdhemy\Purchases\Events\GooglePlay\SubscriptionPriceChangeConfirmed;
return [
'routing' => [],
'google_play_package_name' => env('GOOGLE_PLAY_PACKAGE_NAME', 'com.example.name'),
'google_play_package_name' => env('GOOGLE_PLAY_PACKAGE_NAME', 'com.invoiceninja.app'),
'appstore_password' => env('APPSTORE_PASSWORD', ''),
@ -40,7 +41,7 @@ return [
* --------------------------------------------------------
*/
SubscriptionPurchased::class => [],
SubscriptionRenewed::class => [],
SubscriptionRenewed::class => [PlayStoreRenewSubscription::class],
SubscriptionInGracePeriod::class => [],
SubscriptionExpired::class => [],
SubscriptionCanceled::class => [],

View file

@ -4952,6 +4952,7 @@ $LANG = array(
'update_payment' => 'Update Payment',
'markup' => 'Markup',
'unlock_pro' => 'Unlock Pro',
'preferences' => 'Preferences'
);

View file

@ -3,6 +3,6 @@
<h1>{{ ctrans('texts.login_link_requested_label') }}</h1>
<p>{{ ctrans('texts.login_link_requested') }}</p>
<a href="{{ $url }}" target="_blank" class="button">Sign in to Invoice Ninja</a>
<a href="{{ $url }}" target="_blank" class="button"> {{ ctrans('texts.login')}}</a>
</div>
@endcomponent

View file

@ -2,8 +2,6 @@
<div class="center">
<h1>{{ ctrans('texts.import_complete') }}</h1>
<p><img src="{{ $logo }}"></p>
@if($client_count)
<p><b>{{ ctrans('texts.clients') }}:</b> {{ $client_count }} </p>
@endif

View file

@ -150,16 +150,8 @@
<td align="center">
<div class="dark-bg"
style="background-color:#f9f9f9; border: 1px solid #c2c2c2; border-bottom: none; padding-bottom: 20px; border-top-left-radius: 3px; border-top-right-radius: 3px;">
<!--[if gte mso 9]>
<img src="{{ $logo ?? '' }}" alt="" width="155" border="0" align="middle" style="display:block;" />
<div style="mso-hide:all;">
<![endif]-->
<img class="logo-light" src="{{ $logo ?? '' }}" alt="" width="400" style="margin-top: 10px; max-width: 200px; display: block; margin-left: auto; margin-right: auto;"/>
<!--[if gte mso 9]>
</div>
<![endif]-->
<img class="" src="{{ $logo ?? '' }}" width="50%" height="" alt="alt_text" border="0" style="width: 50%; max-width: 570px; height: auto; display: block;" class="g-img">
</div>
</td>

View file

@ -144,14 +144,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;">
<!--[if gte mso 9]>
<img src="{{ $logo ?? '' }}" alt="" width="400" border="0" align="middle" style="display:block;" />
<div style="mso-hide:all;">
<![endif]-->
<img src="{{ $logo ?? '' }}" alt="" width="400" style="margin-top: 40px; max-width: 200px; display: block; margin-left: auto; margin-right: auto;"/>
<!--[if gte mso 9]>
</div>
<![endif]-->
<img class="" src="{{ $logo ?? '' }}" width="570" height="" alt="alt_text" border="0" style="width: 50%; max-width: 570px; height: auto; display: block;" class="g-img">
</div>
</td>

View file

@ -63,6 +63,62 @@ class ClientTest extends TestCase
$this->makeTestData();
}
public function testClientMergeContactDrop()
{
$c = Client::factory()->create(['user_id' => $this->user->id, 'company_id' => $this->company->id]);
ClientContact::factory()->create([
'user_id' => $this->user->id,
'client_id' => $c->id,
'company_id' => $this->company->id,
'is_primary' => 1,
]);
ClientContact::factory()->create([
'user_id' => $this->user->id,
'client_id' => $c->id,
'company_id' => $this->company->id,
]);
$c1 = Client::factory()->create(['user_id' => $this->user->id, 'company_id' => $this->company->id]);
ClientContact::factory()->create([
'user_id' => $this->user->id,
'client_id' => $c1->id,
'company_id' => $this->company->id,
'is_primary' => 1,
]);
ClientContact::factory()->create([
'user_id' => $this->user->id,
'client_id' => $c1->id,
'company_id' => $this->company->id,
]);
ClientContact::factory()->create([
'user_id' => $this->user->id,
'client_id' => $c1->id,
'company_id' => $this->company->id,
'email' => ''
]);
$this->assertEquals(2, $c->contacts->count());
$this->assertEquals(3, $c1->contacts->count());
$c->service()->merge($c1);
$c = $c->fresh();
nlog($c->contacts->pluck('email'));
$this->assertEquals(4, $c->contacts->count());
}
private function buildLineItems($number = 2)
{
$line_items = [];

View file

@ -15,10 +15,11 @@ use App\Factory\SchedulerFactory;
use App\Models\Client;
use App\Models\RecurringInvoice;
use App\Models\Scheduler;
use App\Services\Scheduler\SchedulerService;
use App\Utils\Traits\MakesHash;
use Carbon\Carbon;
use Illuminate\Database\Eloquent\Model;
use App\DataMapper\Schedule\EmailStatement;
use App\Services\Scheduler\SchedulerService;
use Illuminate\Foundation\Testing\WithoutEvents;
use Illuminate\Routing\Middleware\ThrottleRequests;
use Illuminate\Support\Facades\Session;
@ -77,7 +78,7 @@ class SchedulerTest extends TestCase
'next_run' => now()->format('Y-m-d'),
'template' => 'client_statement',
'parameters' => [
'date_range' => 'previous_month',
'date_range' => EmailStatement::LAST_MONTH,
'show_payments_table' => true,
'show_aging_table' => true,
'status' => 'paid',
@ -143,7 +144,7 @@ class SchedulerTest extends TestCase
'next_run' => now()->format('Y-m-d'),
'template' => 'client_statement',
'parameters' => [
'date_range' => 'previous_month',
'date_range' => EmailStatement::LAST_MONTH,
'show_payments_table' => true,
'show_aging_table' => true,
'status' => 'paid',
@ -176,7 +177,7 @@ class SchedulerTest extends TestCase
'next_run' => now()->addDay()->format('Y-m-d'),
'template' => 'client_statement',
'parameters' => [
'date_range' => 'previous_month',
'date_range' => EmailStatement::LAST_MONTH,
'show_payments_table' => true,
'show_aging_table' => true,
'status' => 'paid',
@ -200,7 +201,7 @@ class SchedulerTest extends TestCase
'next_run' => now()->format('Y-m-d'),
'template' => 'client_statement',
'parameters' => [
'date_range' => 'previous_month',
'date_range' => EmailStatement::LAST_MONTH,
'show_payments_table' => true,
'show_aging_table' => true,
'status' => 'paid',
@ -232,7 +233,7 @@ class SchedulerTest extends TestCase
'next_run' => now()->format('Y-m-d'),
'template' => 'client_statement',
'parameters' => [
'date_range' => 'previous_month',
'date_range' => EmailStatement::LAST_MONTH,
'show_payments_table' => true,
'show_aging_table' => true,
'status' => 'paid',
@ -268,7 +269,7 @@ class SchedulerTest extends TestCase
'next_run' => "2023-01-01",
'template' => 'client_statement',
'parameters' => [
'date_range' => 'previous_month',
'date_range' => EmailStatement::LAST_MONTH,
'show_payments_table' => true,
'show_aging_table' => true,
'status' => 'paid',
@ -287,7 +288,7 @@ class SchedulerTest extends TestCase
$this->assertIsArray($method);
$this->assertEquals('previous_month', $scheduler->parameters['date_range']);
$this->assertEquals(EmailStatement::LAST_MONTH, $scheduler->parameters['date_range']);
$this->assertEqualsCanonicalizing(['2022-12-01','2022-12-31'], $method);
@ -304,7 +305,7 @@ class SchedulerTest extends TestCase
'next_run' => now()->format('Y-m-d'),
'template' => 'client_statement',
'parameters' => [
'date_range' => 'previous_month',
'date_range' => EmailStatement::LAST_MONTH,
'show_payments_table' => true,
'show_aging_table' => true,
'status' => 'paid',
@ -337,13 +338,13 @@ class SchedulerTest extends TestCase
$this->travelTo(Carbon::parse('2023-01-14'));
$this->assertEqualsCanonicalizing(['2023-01-01','2023-01-31'], $this->getDateRange('this_month'));
$this->assertEqualsCanonicalizing(['2023-01-01','2023-03-31'], $this->getDateRange('this_quarter'));
$this->assertEqualsCanonicalizing(['2023-01-01','2023-12-31'], $this->getDateRange('this_year'));
$this->assertEqualsCanonicalizing(['2023-01-01','2023-01-31'], $this->getDateRange(EmailStatement::THIS_MONTH));
$this->assertEqualsCanonicalizing(['2023-01-01','2023-03-31'], $this->getDateRange(EmailStatement::THIS_QUARTER));
$this->assertEqualsCanonicalizing(['2023-01-01','2023-12-31'], $this->getDateRange(EmailStatement::THIS_YEAR));
$this->assertEqualsCanonicalizing(['2022-12-01','2022-12-31'], $this->getDateRange('previous_month'));
$this->assertEqualsCanonicalizing(['2022-10-01','2022-12-31'], $this->getDateRange('previous_quarter'));
$this->assertEqualsCanonicalizing(['2022-01-01','2022-12-31'], $this->getDateRange('previous_year'));
$this->assertEqualsCanonicalizing(['2022-12-01','2022-12-31'], $this->getDateRange(EmailStatement::LAST_MONTH));
$this->assertEqualsCanonicalizing(['2022-10-01','2022-12-31'], $this->getDateRange(EmailStatement::LAST_QUARTER));
$this->assertEqualsCanonicalizing(['2022-01-01','2022-12-31'], $this->getDateRange(EmailStatement::LAST_YEAR));
$this->travelBack();
@ -352,13 +353,17 @@ class SchedulerTest extends TestCase
private function getDateRange($range)
{
return match ($range) {
'this_month' => [now()->firstOfMonth()->format('Y-m-d'), now()->lastOfMonth()->format('Y-m-d')],
'this_quarter' => [now()->firstOfQuarter()->format('Y-m-d'), now()->lastOfQuarter()->format('Y-m-d')],
'this_year' => [now()->firstOfYear()->format('Y-m-d'), now()->lastOfYear()->format('Y-m-d')],
'previous_month' => [now()->subMonth()->firstOfMonth()->format('Y-m-d'), now()->subMonth()->lastOfMonth()->format('Y-m-d')],
'previous_quarter' => [now()->subQuarter()->firstOfQuarter()->format('Y-m-d'), now()->subQuarter()->lastOfQuarter()->format('Y-m-d')],
'previous_year' => [now()->subYear()->firstOfYear()->format('Y-m-d'), now()->subYear()->lastOfYear()->format('Y-m-d')],
'custom_range' => [$this->scheduler->parameters['start_date'], $this->scheduler->parameters['end_date']]
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()->firstOfQuarter()->format('Y-m-d'), now()->startOfDay()->lastOfQuarter()->format('Y-m-d')],
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']],
default => [now()->startOfDay()->firstOfMonth()->format('Y-m-d'), now()->startOfDay()->lastOfMonth()->format('Y-m-d')],
};
}
@ -370,7 +375,7 @@ class SchedulerTest extends TestCase
'next_run' => now()->format('Y-m-d'),
'template' => 'client_statement',
'parameters' => [
'date_range' => 'previous_month',
'date_range' => EmailStatement::LAST_MONTH,
'show_payments_table' => true,
'show_aging_table' => true,
'status' => 'paid',