diff --git a/VERSION.txt b/VERSION.txt index b150ab7535f7..cac426c2230f 100644 --- a/VERSION.txt +++ b/VERSION.txt @@ -1 +1 @@ -5.5.94 \ No newline at end of file +5.5.95 \ No newline at end of file diff --git a/app/Factory/RecurringInvoiceFactory.php b/app/Factory/RecurringInvoiceFactory.php index e246d5cea30a..54fbbc354272 100644 --- a/app/Factory/RecurringInvoiceFactory.php +++ b/app/Factory/RecurringInvoiceFactory.php @@ -53,6 +53,7 @@ class RecurringInvoiceFactory $invoice->remaining_cycles = -1; $invoice->paid_to_date = 0; $invoice->auto_bill_enabled = false; + $invoice->is_proforma = false; $invoice->auto_bill = 'off'; return $invoice; diff --git a/app/Factory/RecurringInvoiceToInvoiceFactory.php b/app/Factory/RecurringInvoiceToInvoiceFactory.php index 3692e458c62e..63b5fa024bec 100644 --- a/app/Factory/RecurringInvoiceToInvoiceFactory.php +++ b/app/Factory/RecurringInvoiceToInvoiceFactory.php @@ -46,6 +46,7 @@ class RecurringInvoiceToInvoiceFactory $invoice->custom_value4 = $recurring_invoice->custom_value4; $invoice->amount = $recurring_invoice->amount; $invoice->uses_inclusive_taxes = $recurring_invoice->uses_inclusive_taxes; + $invoice->is_proforma = $recurring_invoice->is_proforma; $invoice->custom_surcharge1 = $recurring_invoice->custom_surcharge1; $invoice->custom_surcharge2 = $recurring_invoice->custom_surcharge2; diff --git a/app/Http/Controllers/BaseController.php b/app/Http/Controllers/BaseController.php index 9afcc12c7155..86dc368934c1 100644 --- a/app/Http/Controllers/BaseController.php +++ b/app/Http/Controllers/BaseController.php @@ -913,7 +913,6 @@ class BaseController extends Controller * List response * * @param mixed $query - * @return void */ protected function listResponse($query) { @@ -1010,7 +1009,6 @@ class BaseController extends Controller * Item Response * * @param mixed $item - * @return void */ protected function itemResponse($item) { diff --git a/app/Http/Controllers/ClientPortal/PrePaymentController.php b/app/Http/Controllers/ClientPortal/PrePaymentController.php index 9c8070e572d4..874be8a353aa 100644 --- a/app/Http/Controllers/ClientPortal/PrePaymentController.php +++ b/app/Http/Controllers/ClientPortal/PrePaymentController.php @@ -80,6 +80,7 @@ class PrePaymentController extends Controller $invoice = $invoice_repo->save($data, $invoice) ->service() ->markSent() + ->applyNumber() ->fillDefaults() ->save(); @@ -107,8 +108,10 @@ class PrePaymentController extends Controller 'hashed_ids' => $invoices->pluck('hashed_id'), 'total' => $total, 'pre_payment' => true, + 'frequency_id' => $request->frequency_id, + 'remaining_cycles' => $request->remaining_cycles, + 'is_recurring' => $request->is_recurring == 'on' ? true : false, ]; - return $this->render('invoices.payment', $data); diff --git a/app/Http/Controllers/WebhookController.php b/app/Http/Controllers/WebhookController.php index f77fef636efb..f33c3ea0674b 100644 --- a/app/Http/Controllers/WebhookController.php +++ b/app/Http/Controllers/WebhookController.php @@ -12,19 +12,22 @@ namespace App\Http\Controllers; +use App\Models\Webhook; +use Illuminate\Support\Str; +use Illuminate\Http\Response; use App\Factory\WebhookFactory; use App\Filters\WebhookFilters; -use App\Http\Requests\Webhook\CreateWebhookRequest; -use App\Http\Requests\Webhook\DestroyWebhookRequest; -use App\Http\Requests\Webhook\EditWebhookRequest; -use App\Http\Requests\Webhook\ShowWebhookRequest; -use App\Http\Requests\Webhook\StoreWebhookRequest; -use App\Http\Requests\Webhook\UpdateWebhookRequest; -use App\Models\Webhook; +use App\Utils\Traits\MakesHash; +use App\Jobs\Util\WebhookSingle; use App\Repositories\BaseRepository; use App\Transformers\WebhookTransformer; -use App\Utils\Traits\MakesHash; -use Illuminate\Http\Response; +use App\Http\Requests\Webhook\EditWebhookRequest; +use App\Http\Requests\Webhook\ShowWebhookRequest; +use App\Http\Requests\Webhook\RetryWebhookRequest; +use App\Http\Requests\Webhook\StoreWebhookRequest; +use App\Http\Requests\Webhook\CreateWebhookRequest; +use App\Http\Requests\Webhook\UpdateWebhookRequest; +use App\Http\Requests\Webhook\DestroyWebhookRequest; class WebhookController extends BaseController { @@ -487,4 +490,28 @@ class WebhookController extends BaseController return $this->listResponse(Webhook::withTrashed()->whereIn('id', $this->transformKeys($ids))); } + + public function retry(RetryWebhookRequest $request, Webhook $webhook) + { + match($request->entity) { + 'invoice' => $includes ='client', + 'payment' => $includes ='invoices,client', + 'project' => $includes ='client', + 'purchase_order' => $includes ='vendor', + 'quote' => $includes ='client', + default => $includes = '' + }; + + $class = 'App\Models\\'.ucfirst(Str::camel($request->entity)); + + $entity = $class::withTrashed()->where('id', $this->decodePrimaryKey($request->entity_id))->company()->first(); + + if(!$entity){ + return response()->json(['message' => ctrans('texts.record_not_found')], 400); + } + + WebhookSingle::dispatchSync($webhook->id, $entity, auth()->user()->company()->db, $includes); + + return $this->itemResponse($webhook); + } } diff --git a/app/Http/Requests/Webhook/RetryWebhookRequest.php b/app/Http/Requests/Webhook/RetryWebhookRequest.php new file mode 100644 index 000000000000..5b98c06ab233 --- /dev/null +++ b/app/Http/Requests/Webhook/RetryWebhookRequest.php @@ -0,0 +1,35 @@ +user()->isAdmin(); + } + + public function rules() + { + return [ + 'entity' => 'required|bail|in:client,credit,invoice,product,task,payment,quote,purchase_order,expense,project,vendor', + 'entity_id' => 'required|bail|string', + ]; + } +} diff --git a/app/Http/ViewComposers/PortalComposer.php b/app/Http/ViewComposers/PortalComposer.php index 747cc9572adb..3e796d110b5b 100644 --- a/app/Http/ViewComposers/PortalComposer.php +++ b/app/Http/ViewComposers/PortalComposer.php @@ -138,9 +138,9 @@ class PortalComposer $data[] = ['title' => ctrans('texts.subscriptions'), 'url' => 'client.subscriptions.index', 'icon' => 'calendar']; } - if(property_exists($this->settings, 'client_initiated_payments') && $this->settings->client_initiated_payments) { + // if(property_exists($this->settings, 'client_initiated_payments') && $this->settings->client_initiated_payments) { $data[] = ['title' => ctrans('texts.pre_payment'), 'url' => 'client.pre_payments.index', 'icon' => 'dollar-sign']; - } + // } return $data; } diff --git a/app/Jobs/Cron/RecurringExpensesCron.php b/app/Jobs/Cron/RecurringExpensesCron.php index 773a97e26ebe..5b7fb2c33cae 100644 --- a/app/Jobs/Cron/RecurringExpensesCron.php +++ b/app/Jobs/Cron/RecurringExpensesCron.php @@ -40,7 +40,7 @@ class RecurringExpensesCron * * @return void */ - public function handle() : void + public function handle(): void { /* Get all expenses where the send date is less than NOW + 30 minutes() */ nlog('Sending recurring expenses '.Carbon::now()->format('Y-m-d h:i:s')); diff --git a/app/Jobs/Util/ReminderJob.php b/app/Jobs/Util/ReminderJob.php index 2aef984496d4..bf56b28546fe 100644 --- a/app/Jobs/Util/ReminderJob.php +++ b/app/Jobs/Util/ReminderJob.php @@ -11,27 +11,33 @@ namespace App\Jobs\Util; -use App\DataMapper\InvoiceItem; -use App\Events\Invoice\InvoiceWasEmailed; -use App\Jobs\Entity\EmailEntity; -use App\Jobs\Ninja\TransactionLog; -use App\Libraries\MultiDB; -use App\Models\Invoice; -use App\Models\TransactionEvent; use App\Utils\Ninja; -use App\Utils\Traits\MakesDates; -use App\Utils\Traits\MakesReminders; +use App\Models\Invoice; +use App\Libraries\MultiDB; use Illuminate\Bus\Queueable; +use Illuminate\Support\Carbon; +use App\DataMapper\InvoiceItem; +use App\Jobs\Entity\EmailEntity; +use App\Models\TransactionEvent; +use App\Utils\Traits\MakesDates; +use App\Jobs\Ninja\TransactionLog; +use Illuminate\Support\Facades\App; +use App\Utils\Traits\MakesReminders; +use Illuminate\Queue\SerializesModels; +use Illuminate\Queue\InteractsWithQueue; +use App\Events\Invoice\InvoiceWasEmailed; use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Foundation\Bus\Dispatchable; -use Illuminate\Queue\InteractsWithQueue; -use Illuminate\Queue\SerializesModels; -use Illuminate\Support\Carbon; -use Illuminate\Support\Facades\App; +use App\Events\Invoice\InvoiceReminderWasEmailed; class ReminderJob implements ShouldQueue { - use Dispatchable, InteractsWithQueue, Queueable, SerializesModels, MakesReminders, MakesDates; + use Dispatchable; + use InteractsWithQueue; + use Queueable; + use SerializesModels; + use MakesReminders; + use MakesDates; public $tries = 1; @@ -44,7 +50,7 @@ class ReminderJob implements ShouldQueue * * @return void */ - public function handle() :void + public function handle(): void { set_time_limit(0); @@ -73,7 +79,7 @@ class ReminderJob implements ShouldQueue }); } else { //multiDB environment, need to - + foreach (MultiDB::$dbs as $db) { MultiDB::setDB($db); @@ -94,7 +100,7 @@ class ReminderJob implements ShouldQueue }) ->with('invitations')->chunk(50, function ($invoices) { // if ($invoice->refresh() && $invoice->isPayable()) { - + foreach ($invoices as $invoice) { $this->sendReminderForInvoice($invoice); } @@ -125,22 +131,17 @@ class ReminderJob implements ShouldQueue $enabled_reminder = 'enable_reminder_endless'; } - //check if this reminder needs to be emailed - //15-01-2022 - insert addition if block if send_reminders is definitely set if (in_array($reminder_template, ['reminder1', 'reminder2', 'reminder3', 'reminder_endless', 'endless_reminder']) && $invoice->client->getSetting($enabled_reminder) && $invoice->client->getSetting('send_reminders') && (Ninja::isSelfHost() || $invoice->company->account->isPaidHostedClient())) { $invoice->invitations->each(function ($invitation) use ($invoice, $reminder_template) { if ($invitation->contact && !$invitation->contact->trashed() && $invitation->contact->email) { - EmailEntity::dispatch($invitation, $invitation->company, $reminder_template)->delay(now()->addSeconds(3)); + EmailEntity::dispatch($invitation, $invitation->company, $reminder_template); nlog("Firing reminder email for invoice {$invoice->number} - {$reminder_template}"); + $invoice->entityEmailEvent($invitation, $reminder_template); } }); - - if ($invoice->invitations->count() > 0) { - event(new InvoiceWasEmailed($invoice->invitations->first(), $invoice->company, Ninja::eventVars(), $reminder_template)); - } } $invoice->service()->setReminder()->save(); } else { @@ -156,7 +157,7 @@ class ReminderJob implements ShouldQueue * @param string $template * @return Invoice */ - private function calcLateFee($invoice, $template) :Invoice + private function calcLateFee($invoice, $template): Invoice { $late_fee_amount = 0; $late_fee_percent = 0; @@ -196,7 +197,7 @@ class ReminderJob implements ShouldQueue * * @return Invoice */ - private function setLateFee($invoice, $amount, $percent) :Invoice + private function setLateFee($invoice, $amount, $percent): Invoice { App::forgetInstance('translator'); $t = app('translator'); @@ -217,7 +218,7 @@ class ReminderJob implements ShouldQueue $fee += round($invoice->balance * $percent / 100, 2); } - $invoice_item = new InvoiceItem; + $invoice_item = new InvoiceItem(); $invoice_item->type_id = '5'; $invoice_item->product_key = trans('texts.fee'); $invoice_item->notes = ctrans('texts.late_fee_added', ['date' => $this->translateDate(now()->startOfDay(), $invoice->client->date_format(), $invoice->client->locale())]); diff --git a/app/Jobs/Util/WebhookSingle.php b/app/Jobs/Util/WebhookSingle.php index 84398b00ee1a..ab5bd5af1710 100644 --- a/app/Jobs/Util/WebhookSingle.php +++ b/app/Jobs/Util/WebhookSingle.php @@ -104,8 +104,10 @@ class WebhookSingle implements ShouldQueue $resource = new Item($this->entity, $transformer, $this->entity->getEntityType()); $data = $manager->createData($resource)->toArray(); + + $headers = is_array($subscription->headers) ? $subscription->headers : []; - $this->postData($subscription, $data, $subscription->headers); + $this->postData($subscription, $data, $headers); } private function postData($subscription, $data, $headers = []) diff --git a/app/Listeners/Payment/PaymentEmailedActivity.php b/app/Listeners/Payment/PaymentEmailedActivity.php index af6701c4d486..5fcf3e765abd 100644 --- a/app/Listeners/Payment/PaymentEmailedActivity.php +++ b/app/Listeners/Payment/PaymentEmailedActivity.php @@ -11,33 +11,47 @@ namespace App\Listeners\Payment; +use App\Models\Activity; use App\Libraries\MultiDB; -use App\Utils\Traits\Notifications\UserNotifies; +use App\Repositories\ActivityRepository; use Illuminate\Contracts\Queue\ShouldQueue; +use App\Utils\Traits\Notifications\UserNotifies; class PaymentEmailedActivity implements ShouldQueue { - use UserNotifies; + protected $activity_repo; /** * Create the event listener. * - * @return void + * @param ActivityRepository $activity_repo */ - public function __construct() + public function __construct(ActivityRepository $activity_repo) { + $this->activity_repo = $activity_repo; } /** * Handle the event. * * @param object $event - * @return bool */ public function handle($event) { MultiDB::setDb($event->company->db); - $payment = $event->payment; + + $fields = new \stdClass(); + + $user_id = array_key_exists('user_id', $event->event_vars) ? $event->event_vars['user_id'] : $event->payment->user_id; + + $fields->user_id = $user_id; + $fields->client_id = $event->payment->client_id; + $fields->company_id = $event->payment->company_id; + $fields->activity_type_id = Activity::PAYMENT_EMAILED; + $fields->payment_id = $event->payment->id; + + $this->activity_repo->save($fields, $event->payment, $event->event_vars); + } } diff --git a/app/Listeners/Subscription/AppStoreRenewSubscription.php b/app/Listeners/Subscription/AppStoreRenewSubscription.php deleted file mode 100644 index 07e5c493f9b3..000000000000 --- a/app/Listeners/Subscription/AppStoreRenewSubscription.php +++ /dev/null @@ -1,62 +0,0 @@ -getSubscriptionId(); //$subscription_id - - nlog("inapp upgrade processing for = {$inapp_transaction_id}"); - - MultiDB::findAndSetDbByInappTransactionId($inapp_transaction_id); - - $account = Account::where('inapp_transaction_id', $inapp_transaction_id)->first(); - - if (!$account) { - $ninja_company = Company::on('db-ninja-01')->find(config('ninja.ninja_default_company_id')); - $ninja_company->notification(new RenewalFailureNotification("{$inapp_transaction_id}"))->ninja(); - return; - } - - if ($account->plan_term == 'month') { - $account->plan_expires = now()->addMonth(); - } elseif ($account->plan_term == 'year') { - $account->plan_expires = now()->addYear(); - } - - $account->save(); - } -} diff --git a/app/Listeners/Subscription/PlayStoreRenewSubscription.php b/app/Listeners/Subscription/PlayStoreRenewSubscription.php deleted file mode 100644 index 1a3bb1684fa8..000000000000 --- a/app/Listeners/Subscription/PlayStoreRenewSubscription.php +++ /dev/null @@ -1,49 +0,0 @@ -getServerNotification(); - nlog("google"); - nlog($notification); - $in_app_identifier = $event->getSubscriptionIdentifier(); - - $parts = explode("..", $in_app_identifier); - - MultiDB::findAndSetDbByInappTransactionId($parts[0]); - - $expirationTime = $event->getSubscription()->getExpiryTime(); - - $account = Account::where('inapp_transaction_id', 'like', $parts[0]."%")->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; - } - } -} diff --git a/app/Mail/Engine/PaymentEmailEngine.php b/app/Mail/Engine/PaymentEmailEngine.php index 1b274fca2353..215949837570 100644 --- a/app/Mail/Engine/PaymentEmailEngine.php +++ b/app/Mail/Engine/PaymentEmailEngine.php @@ -388,6 +388,13 @@ class PaymentEmailEngine extends BaseEmailEngine */ private function buildViewButton(string $link, string $text): string { + + + if ($this->settings->email_style == 'plain') { + return ''. $text .''; + } + + return '