From 534367c80ec51bc845a873f8f216275ad070f559 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Thu, 25 Nov 2021 21:45:52 +1100 Subject: [PATCH 01/20] Fixes for Mollie Direct Debit --- app/PaymentDrivers/GoCardless/DirectDebit.php | 9 +++------ app/PaymentDrivers/GoCardlessPaymentDriver.php | 5 +++-- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/app/PaymentDrivers/GoCardless/DirectDebit.php b/app/PaymentDrivers/GoCardless/DirectDebit.php index fae242949242..2929e081bf7c 100644 --- a/app/PaymentDrivers/GoCardless/DirectDebit.php +++ b/app/PaymentDrivers/GoCardless/DirectDebit.php @@ -152,11 +152,8 @@ class DirectDebit implements MethodInterface public function paymentResponse(PaymentResponseRequest $request) { - $token = ClientGatewayToken::find( - $this->decodePrimaryKey($request->source) - )->firstOrFail(); - $this->go_cardless->ensureMandateIsReady($token); + $this->go_cardless->ensureMandateIsReady($request->source); try { $payment = $this->go_cardless->gateway->payments()->create([ @@ -167,14 +164,14 @@ class DirectDebit implements MethodInterface 'payment_hash' => $this->go_cardless->payment_hash->hash, ], 'links' => [ - 'mandate' => $token->token, + 'mandate' => $request->source, ], ], ]); if ($payment->status === 'pending_submission') { - return $this->processPendingPayment($payment, ['token' => $token->hashed_id]); + return $this->processPendingPayment($payment, ['token' => $request->source]); } return $this->processUnsuccessfulPayment($payment); diff --git a/app/PaymentDrivers/GoCardlessPaymentDriver.php b/app/PaymentDrivers/GoCardlessPaymentDriver.php index c7d890e637d0..721125409090 100644 --- a/app/PaymentDrivers/GoCardlessPaymentDriver.php +++ b/app/PaymentDrivers/GoCardlessPaymentDriver.php @@ -265,10 +265,11 @@ class GoCardlessPaymentDriver extends BaseDriver return response()->json([], 200); } - public function ensureMandateIsReady(ClientGatewayToken $cgt) + public function ensureMandateIsReady($token) { try { - $mandate = $this->gateway->mandates()->get($cgt->token); + $this->init(); + $mandate = $this->gateway->mandates()->get($token); if ($mandate->status !== 'active') { throw new \Exception(ctrans('texts.gocardless_mandate_not_ready')); From 530209ee5270390418d8dfbd4b605b051f343701 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Thu, 25 Nov 2021 22:23:19 +1100 Subject: [PATCH 02/20] Minor fixes for Mollie --- app/PaymentDrivers/BaseDriver.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/PaymentDrivers/BaseDriver.php b/app/PaymentDrivers/BaseDriver.php index 55c472337398..af59a1c69578 100644 --- a/app/PaymentDrivers/BaseDriver.php +++ b/app/PaymentDrivers/BaseDriver.php @@ -226,7 +226,7 @@ class BaseDriver extends AbstractPaymentDriver $_payment = Payment::where('transaction_reference', $data['transaction_reference']) ->where('client_id', $this->client->id) - ->first(); + ->exists(); if($_payment) return $_payment; From dda2f3ab8e1874c9061d65b3d4b4081a7b60080f Mon Sep 17 00:00:00 2001 From: David Bomba Date: Thu, 25 Nov 2021 22:27:02 +1100 Subject: [PATCH 03/20] documentation for Mollie --- app/PaymentDrivers/MolliePaymentDriver.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/PaymentDrivers/MolliePaymentDriver.php b/app/PaymentDrivers/MolliePaymentDriver.php index b256fbdecf83..be77b8bef2b5 100644 --- a/app/PaymentDrivers/MolliePaymentDriver.php +++ b/app/PaymentDrivers/MolliePaymentDriver.php @@ -316,6 +316,10 @@ class MolliePaymentDriver extends BaseDriver nlog($payment); $client = Client::withTrashed()->find($this->decodePrimaryKey($payment->metadata->client_id)); + + // sometimes if the user is not returned to the site with a response from Mollie + // we may not have a payment record - in these cases we need to re-construct the payment + // record from the meta data in the payment hash. } $message = [ From 2e15d3ceb8672087995d14f45548b8804e01e6dc Mon Sep 17 00:00:00 2001 From: David Bomba Date: Fri, 26 Nov 2021 07:08:51 +1100 Subject: [PATCH 04/20] flip order or stripe credentials --- database/seeders/PaymentLibrariesSeeder.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/database/seeders/PaymentLibrariesSeeder.php b/database/seeders/PaymentLibrariesSeeder.php index ab9431bbf0e5..c4d50c57d099 100644 --- a/database/seeders/PaymentLibrariesSeeder.php +++ b/database/seeders/PaymentLibrariesSeeder.php @@ -44,7 +44,7 @@ class PaymentLibrariesSeeder extends Seeder ['id' => 17, 'name' => 'Pin', 'provider' => 'Pin', 'key' => '0749cb92a6b36c88bd9ff8aabd2efcab', 'fields' => '{"secretKey":"","testMode":false}'], ['id' => 18, 'name' => 'SagePay Direct', 'provider' => 'SagePay_Direct', 'key' => '4c8f4e5d0f353a122045eb9a60cc0f2d', 'fields' => '{"vendor":"","testMode":false,"referrerId":""}'], ['id' => 19, 'name' => 'SecurePay DirectPost', 'provider' => 'SecurePay_DirectPost', 'key' => '8036a5aadb2bdaafb23502da8790b6a2', 'fields' => '{"merchantId":"","transactionPassword":"","testMode":false,"enable_ach":"","enable_sofort":"","enable_apple_pay":"","enable_alipay":""}'], - ['id' => 20, 'name' => 'Stripe', 'provider' => 'Stripe', 'sort_order' => 1, 'key' => 'd14dd26a37cecc30fdd65700bfb55b23', 'fields' => '{"apiKey":"", "publishableKey":""}'], + ['id' => 20, 'name' => 'Stripe', 'provider' => 'Stripe', 'sort_order' => 1, 'key' => 'd14dd26a37cecc30fdd65700bfb55b23', 'fields' => '{"publishableKey":"","apiKey":""}'], ['id' => 21, 'name' => 'TargetPay Direct eBanking', 'provider' => 'TargetPay_Directebanking', 'key' => 'd14dd26a37cdcc30fdd65700bfb55b23', 'fields' => '{"subAccountId":""}'], ['id' => 22, 'name' => 'TargetPay Ideal', 'provider' => 'TargetPay_Ideal', 'key' => 'ea3b328bd72d381387281c3bd83bd97c', 'fields' => '{"subAccountId":""}'], ['id' => 23, 'name' => 'TargetPay Mr Cash', 'provider' => 'TargetPay_Mrcash', 'key' => 'a0035fc0d87c4950fb82c73e2fcb825a', 'fields' => '{"subAccountId":""}'], From f6f9e7a7a15501541e19faf1f11a7933176c1c80 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Fri, 26 Nov 2021 07:09:36 +1100 Subject: [PATCH 05/20] New Schema Dump ' --- database/schema/db-ninja-01-schema.dump | 145 +++++++++++++++++++++++- 1 file changed, 144 insertions(+), 1 deletion(-) diff --git a/database/schema/db-ninja-01-schema.dump b/database/schema/db-ninja-01-schema.dump index 87ee5eaa830e..a3ff1e7ba57a 100644 --- a/database/schema/db-ninja-01-schema.dump +++ b/database/schema/db-ninja-01-schema.dump @@ -34,6 +34,9 @@ CREATE TABLE `accounts` ( `updated_at` timestamp(6) NULL DEFAULT NULL, `is_scheduler_running` tinyint(1) NOT NULL DEFAULT '0', `trial_duration` int(10) unsigned DEFAULT NULL, + `is_onboarding` tinyint(1) NOT NULL DEFAULT '0', + `onboarding` mediumtext COLLATE utf8mb4_unicode_ci, + `is_migrated` tinyint(1) NOT NULL DEFAULT '0', PRIMARY KEY (`id`), KEY `accounts_payment_id_index` (`payment_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=8; @@ -66,6 +69,8 @@ CREATE TABLE `activities` ( `quote_id` int(10) unsigned DEFAULT NULL, `subscription_id` int(10) unsigned DEFAULT NULL, `recurring_invoice_id` int(10) unsigned DEFAULT NULL, + `recurring_expense_id` int(10) unsigned DEFAULT NULL, + `recurring_quote_id` int(10) unsigned DEFAULT NULL, PRIMARY KEY (`id`), KEY `activities_vendor_id_company_id_index` (`vendor_id`,`company_id`), KEY `activities_project_id_company_id_index` (`project_id`,`company_id`), @@ -93,6 +98,7 @@ CREATE TABLE `backups` ( `created_at` timestamp(6) NULL DEFAULT NULL, `updated_at` timestamp(6) NULL DEFAULT NULL, `amount` decimal(16,4) NOT NULL, + `filename` text COLLATE utf8mb4_unicode_ci, PRIMARY KEY (`id`), KEY `backups_activity_id_foreign` (`activity_id`), CONSTRAINT `backups_activity_id_foreign` FOREIGN KEY (`activity_id`) REFERENCES `activities` (`id`) ON DELETE CASCADE ON UPDATE CASCADE @@ -378,6 +384,7 @@ CREATE TABLE `companies` ( `markdown_enabled` tinyint(1) NOT NULL DEFAULT '1', `use_comma_as_decimal_place` tinyint(1) NOT NULL DEFAULT '0', `report_include_drafts` tinyint(1) NOT NULL DEFAULT '0', + `client_registration_fields` mediumtext COLLATE utf8mb4_unicode_ci, PRIMARY KEY (`id`), UNIQUE KEY `companies_company_key_unique` (`company_key`), KEY `companies_industry_id_foreign` (`industry_id`), @@ -1371,6 +1378,69 @@ CREATE TABLE `quotes` ( CONSTRAINT `quotes_user_id_foreign` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE ON UPDATE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=8; /*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `recurring_expenses`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `recurring_expenses` ( + `id` int(10) unsigned NOT NULL AUTO_INCREMENT, + `created_at` timestamp(6) NULL DEFAULT NULL, + `updated_at` timestamp(6) NULL DEFAULT NULL, + `deleted_at` timestamp NULL DEFAULT NULL, + `company_id` int(10) unsigned NOT NULL, + `vendor_id` int(10) unsigned DEFAULT NULL, + `user_id` int(10) unsigned NOT NULL, + `status_id` int(10) unsigned NOT NULL, + `invoice_id` int(10) unsigned DEFAULT NULL, + `client_id` int(10) unsigned DEFAULT NULL, + `bank_id` int(10) unsigned DEFAULT NULL, + `project_id` int(10) unsigned DEFAULT NULL, + `payment_type_id` int(10) unsigned DEFAULT NULL, + `recurring_expense_id` int(10) unsigned DEFAULT NULL, + `is_deleted` tinyint(1) NOT NULL DEFAULT '0', + `uses_inclusive_taxes` tinyint(1) NOT NULL DEFAULT '1', + `tax_name1` varchar(191) COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `tax_name2` varchar(191) COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `tax_name3` varchar(191) COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `date` date DEFAULT NULL, + `payment_date` date DEFAULT NULL, + `should_be_invoiced` tinyint(1) NOT NULL DEFAULT '0', + `invoice_documents` tinyint(1) NOT NULL DEFAULT '0', + `transaction_id` varchar(191) COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `custom_value1` varchar(191) COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `custom_value2` varchar(191) COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `custom_value3` varchar(191) COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `custom_value4` varchar(191) COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `category_id` int(10) unsigned DEFAULT NULL, + `calculate_tax_by_amount` tinyint(1) NOT NULL DEFAULT '0', + `tax_amount1` decimal(20,6) DEFAULT NULL, + `tax_amount2` decimal(20,6) DEFAULT NULL, + `tax_amount3` decimal(20,6) DEFAULT NULL, + `tax_rate1` decimal(20,6) DEFAULT NULL, + `tax_rate2` decimal(20,6) DEFAULT NULL, + `tax_rate3` decimal(20,6) DEFAULT NULL, + `amount` decimal(20,6) DEFAULT NULL, + `foreign_amount` decimal(20,6) DEFAULT NULL, + `exchange_rate` decimal(20,6) NOT NULL DEFAULT '1.000000', + `assigned_user_id` int(10) unsigned DEFAULT NULL, + `number` varchar(191) COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `invoice_currency_id` int(10) unsigned DEFAULT NULL, + `currency_id` int(10) unsigned DEFAULT NULL, + `private_notes` text COLLATE utf8mb4_unicode_ci, + `public_notes` text COLLATE utf8mb4_unicode_ci, + `transaction_reference` text COLLATE utf8mb4_unicode_ci, + `frequency_id` int(10) unsigned NOT NULL, + `last_sent_date` datetime DEFAULT NULL, + `next_send_date` datetime DEFAULT NULL, + `remaining_cycles` int(11) DEFAULT NULL, + PRIMARY KEY (`id`), + UNIQUE KEY `recurring_expenses_company_id_number_unique` (`company_id`,`number`), + KEY `recurring_expenses_company_id_deleted_at_index` (`company_id`,`deleted_at`), + KEY `recurring_expenses_user_id_foreign` (`user_id`), + KEY `recurring_expenses_company_id_index` (`company_id`), + CONSTRAINT `recurring_expenses_company_id_foreign` FOREIGN KEY (`company_id`) REFERENCES `companies` (`id`) ON DELETE CASCADE ON UPDATE CASCADE, + CONSTRAINT `recurring_expenses_user_id_foreign` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE ON UPDATE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC; +/*!40101 SET character_set_client = @saved_cs_client */; DROP TABLE IF EXISTS `recurring_invoice_invitations`; /*!40101 SET @saved_cs_client = @@character_set_client */; /*!40101 SET character_set_client = utf8 */; @@ -1481,6 +1551,41 @@ CREATE TABLE `recurring_invoices` ( CONSTRAINT `recurring_invoices_user_id_foreign` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE ON UPDATE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=8; /*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `recurring_quote_invitations`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `recurring_quote_invitations` ( + `id` int(10) unsigned NOT NULL AUTO_INCREMENT, + `company_id` int(10) unsigned NOT NULL, + `user_id` int(10) unsigned NOT NULL, + `client_contact_id` int(10) unsigned NOT NULL, + `recurring_quote_id` int(10) unsigned NOT NULL, + `key` varchar(191) COLLATE utf8mb4_unicode_ci NOT NULL, + `transaction_reference` varchar(191) COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `message_id` varchar(191) COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `email_error` mediumtext COLLATE utf8mb4_unicode_ci, + `signature_base64` text COLLATE utf8mb4_unicode_ci, + `signature_date` datetime DEFAULT NULL, + `sent_date` datetime DEFAULT NULL, + `viewed_date` datetime DEFAULT NULL, + `opened_date` datetime DEFAULT NULL, + `email_status` enum('delivered','bounced','spam') COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `created_at` timestamp(6) NULL DEFAULT NULL, + `updated_at` timestamp(6) NULL DEFAULT NULL, + `deleted_at` timestamp(6) NULL DEFAULT NULL, + PRIMARY KEY (`id`), + UNIQUE KEY `cli_rec_q` (`client_contact_id`,`recurring_quote_id`), + KEY `recurring_quote_invitations_user_id_foreign` (`user_id`), + KEY `recurring_quote_invitations_company_id_foreign` (`company_id`), + KEY `rec_co_del_q` (`deleted_at`,`recurring_quote_id`,`company_id`), + KEY `recurring_quote_invitations_recurring_quote_id_index` (`recurring_quote_id`), + KEY `recurring_quote_invitations_key_index` (`key`), + CONSTRAINT `recurring_quote_invitations_client_contact_id_foreign` FOREIGN KEY (`client_contact_id`) REFERENCES `client_contacts` (`id`) ON DELETE CASCADE ON UPDATE CASCADE, + CONSTRAINT `recurring_quote_invitations_company_id_foreign` FOREIGN KEY (`company_id`) REFERENCES `companies` (`id`) ON DELETE CASCADE ON UPDATE CASCADE, + CONSTRAINT `recurring_quote_invitations_recurring_quote_id_foreign` FOREIGN KEY (`recurring_quote_id`) REFERENCES `recurring_invoices` (`id`) ON DELETE CASCADE ON UPDATE CASCADE, + CONSTRAINT `recurring_quote_invitations_user_id_foreign` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE ON UPDATE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC; +/*!40101 SET character_set_client = @saved_cs_client */; DROP TABLE IF EXISTS `recurring_quotes`; /*!40101 SET @saved_cs_client = @@character_set_client */; /*!40101 SET character_set_client = utf8 */; @@ -1521,13 +1626,29 @@ CREATE TABLE `recurring_quotes` ( `balance` decimal(20,6) NOT NULL DEFAULT '0.000000', `last_viewed` datetime DEFAULT NULL, `frequency_id` int(10) unsigned NOT NULL, - `start_date` date DEFAULT NULL, `last_sent_date` datetime DEFAULT NULL, `next_send_date` datetime DEFAULT NULL, `remaining_cycles` int(10) unsigned DEFAULT NULL, `created_at` timestamp(6) NULL DEFAULT NULL, `updated_at` timestamp(6) NULL DEFAULT NULL, `deleted_at` timestamp(6) NULL DEFAULT NULL, + `auto_bill` varchar(191) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT 'off', + `auto_bill_enabled` tinyint(1) NOT NULL DEFAULT '0', + `paid_to_date` decimal(20,6) NOT NULL DEFAULT '0.000000', + `custom_surcharge1` decimal(20,6) DEFAULT NULL, + `custom_surcharge2` decimal(20,6) DEFAULT NULL, + `custom_surcharge3` decimal(20,6) DEFAULT NULL, + `custom_surcharge4` decimal(20,6) DEFAULT NULL, + `custom_surcharge_tax1` tinyint(1) NOT NULL DEFAULT '0', + `custom_surcharge_tax2` tinyint(1) NOT NULL DEFAULT '0', + `custom_surcharge_tax3` tinyint(1) NOT NULL DEFAULT '0', + `custom_surcharge_tax4` tinyint(1) NOT NULL DEFAULT '0', + `due_date_days` varchar(191) COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `exchange_rate` decimal(13,6) NOT NULL DEFAULT '1.000000', + `partial` decimal(16,4) DEFAULT NULL, + `partial_due_date` date DEFAULT NULL, + `subscription_id` int(10) unsigned DEFAULT NULL, + `uses_inclusive_taxes` tinyint(1) NOT NULL DEFAULT '1', PRIMARY KEY (`id`), KEY `recurring_quotes_company_id_deleted_at_index` (`company_id`,`deleted_at`), KEY `recurring_quotes_user_id_foreign` (`user_id`), @@ -1973,3 +2094,25 @@ INSERT INTO `migrations` VALUES (91,'2021_08_10_034407_add_more_languages',4); INSERT INTO `migrations` VALUES (92,'2021_08_18_220124_use_comma_as_decimal_place_companies_table',4); INSERT INTO `migrations` VALUES (93,'2021_08_24_115919_update_designs',4); INSERT INTO `migrations` VALUES (94,'2021_08_25_093105_report_include_drafts_in_companies_table',5); +INSERT INTO `migrations` VALUES (95,'2021_08_14_054458_square_payment_driver',6); +INSERT INTO `migrations` VALUES (96,'2021_08_23_101529_recurring_expenses_schema',6); +INSERT INTO `migrations` VALUES (97,'2021_09_05_101209_update_braintree_gateway',6); +INSERT INTO `migrations` VALUES (98,'2021_09_20_233053_set_square_test_mode_boolean',6); +INSERT INTO `migrations` VALUES (99,'2021_09_23_100629_add_currencies',6); +INSERT INTO `migrations` VALUES (100,'2021_09_24_201319_add_mollie_bank_transfer_to_payment_types',6); +INSERT INTO `migrations` VALUES (101,'2021_09_24_211504_add_kbc_to_payment_types',6); +INSERT INTO `migrations` VALUES (102,'2021_09_24_213858_add_bancontact_to_payment_types',6); +INSERT INTO `migrations` VALUES (103,'2021_09_28_154647_activate_gocardless_payment_driver',6); +INSERT INTO `migrations` VALUES (104,'2021_09_29_190258_add_required_client_registration_fields',6); +INSERT INTO `migrations` VALUES (105,'2021_10_04_134908_add_ideal_to_payment_types',6); +INSERT INTO `migrations` VALUES (106,'2021_10_06_044800_updated_bold_and_modern_designs',6); +INSERT INTO `migrations` VALUES (107,'2021_10_07_141737_razorpay',6); +INSERT INTO `migrations` VALUES (108,'2021_10_07_155410_add_hosted_page_to_payment_types',6); +INSERT INTO `migrations` VALUES (109,'2021_10_15_00000_stripe_payment_gateways',6); +INSERT INTO `migrations` VALUES (110,'2021_10_16_135200_add_direct_debit_to_payment_types',6); +INSERT INTO `migrations` VALUES (111,'2021_10_19_142200_add_gateway_type_for_direct_debit',6); +INSERT INTO `migrations` VALUES (112,'2021_10_20_005529_add_filename_to_backups_table',6); +INSERT INTO `migrations` VALUES (113,'2021_11_08_131308_onboarding',6); +INSERT INTO `migrations` VALUES (114,'2021_11_09_115919_update_designs',6); +INSERT INTO `migrations` VALUES (115,'2021_11_10_184847_add_is_migrate_column_to_accounts_table',6); +INSERT INTO `migrations` VALUES (116,'2021_11_11_163121_add_instant_bank_transfer',7); From 9086b224ce3b5b3ad81fc5bf9daa53ea053e388c Mon Sep 17 00:00:00 2001 From: David Bomba Date: Fri, 26 Nov 2021 16:33:49 +1100 Subject: [PATCH 06/20] Fixes for payment failure mailers --- app/Jobs/Mail/PaymentFailedMailer.php | 4 +++- app/Jobs/Mail/PaymentFailureMailer.php | 2 +- app/Utils/Traits/Notifications/UserNotifies.php | 6 ++++++ 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/app/Jobs/Mail/PaymentFailedMailer.php b/app/Jobs/Mail/PaymentFailedMailer.php index 87663e159b16..58c6abc1059d 100644 --- a/app/Jobs/Mail/PaymentFailedMailer.php +++ b/app/Jobs/Mail/PaymentFailedMailer.php @@ -83,7 +83,9 @@ class PaymentFailedMailer implements ShouldQueue $this->company->company_users->each(function ($company_user) use($amount, $settings){ //determine if this user has the right permissions - $methods = $this->findCompanyUserNotificationType($company_user, ['payment_failure','all_notifications']); + // $methods = $this->findCompanyUserNotificationType($company_user, ['payment_failure_all','payment_failure','all_notifications']); + + $methods = $this->findUserEntityNotificationType($this->client, $company_user, ['payment_failure_all','payment_failure','all_notifications']); //if mail is a method type -fire mail!! if (($key = array_search('mail', $methods)) !== false) { diff --git a/app/Jobs/Mail/PaymentFailureMailer.php b/app/Jobs/Mail/PaymentFailureMailer.php index c54fb042377a..98a2c2448985 100644 --- a/app/Jobs/Mail/PaymentFailureMailer.php +++ b/app/Jobs/Mail/PaymentFailureMailer.php @@ -80,7 +80,7 @@ class PaymentFailureMailer implements ShouldQueue $this->company->company_users->each(function ($company_user) { //determine if this user has the right permissions - $methods = $this->findCompanyUserNotificationType($company_user, ['payment_failure','all_notifications']); + $methods = $this->findCompanyUserNotificationType($company_user, ['payment_failure_all','payment_failure','all_notifications']); //if mail is a method type -fire mail!! if (($key = array_search('mail', $methods)) !== false) { diff --git a/app/Utils/Traits/Notifications/UserNotifies.php b/app/Utils/Traits/Notifications/UserNotifies.php index 4c9e05420c29..0e1ce5823a8e 100644 --- a/app/Utils/Traits/Notifications/UserNotifies.php +++ b/app/Utils/Traits/Notifications/UserNotifies.php @@ -79,6 +79,12 @@ trait UserNotifies $notifiable_methods = []; $notifications = $company_user->notifications; +nlog($company_user->notifications); +nlog($required_permissions); +nlog(count(array_intersect($required_permissions, ['all_user_notifications']))); +nlog(count(array_intersect($required_permissions, ['all_notifications']))); + +nlog(count(array_intersect($required_permissions, $notifications->email))); //conditional to define whether the company user has the required notification for the MAIL notification TYPE if (count(array_intersect($required_permissions, $notifications->email)) >= 1 || count(array_intersect($required_permissions, ['all_user_notifications'])) >= 1 || count(array_intersect($required_permissions, ['all_notifications'])) >= 1) { array_push($notifiable_methods, 'mail'); From 92001dae7b3aabaef731de802956a4f4287915e7 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Sat, 27 Nov 2021 07:41:13 +1100 Subject: [PATCH 07/20] Fixes for white label licensing --- app/Http/Controllers/LicenseController.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/Http/Controllers/LicenseController.php b/app/Http/Controllers/LicenseController.php index 3d601f43c8ba..3aa8fda69863 100644 --- a/app/Http/Controllers/LicenseController.php +++ b/app/Http/Controllers/LicenseController.php @@ -107,7 +107,7 @@ class LicenseController extends BaseController 'message' => trans('texts.invalid_white_label_license'), 'errors' => new stdClass, ]; - + $account = auth()->user()->account; $account->plan_term = Account::PLAN_TERM_YEARLY; $account->plan_paid = null; $account->plan_expires = null; @@ -116,7 +116,7 @@ class LicenseController extends BaseController return response()->json($error, 400); } else { - $account = auth()->user()->company()->account; + $account = auth()->user()->account; $account->plan_term = Account::PLAN_TERM_YEARLY; $account->plan_paid = $data; @@ -151,7 +151,7 @@ class LicenseController extends BaseController private function checkLicense() { - $account = auth()->user()->company()->account; + $account = auth()->user()->account; if($account->plan == 'white_label' && Carbon::parse($account->plan_expires)->lt(now())){ $account->plan = null; From 8916c57777bd538cb6d905686100490f473a531b Mon Sep 17 00:00:00 2001 From: David Bomba Date: Sat, 27 Nov 2021 11:40:18 +1100 Subject: [PATCH 08/20] Enforce types when checking values of boolean --- app/Services/Invoice/InvoiceService.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/Services/Invoice/InvoiceService.php b/app/Services/Invoice/InvoiceService.php index c02946122db0..153e5fd0bf1a 100644 --- a/app/Services/Invoice/InvoiceService.php +++ b/app/Services/Invoice/InvoiceService.php @@ -138,7 +138,7 @@ class InvoiceService { // $this->invoice = (new UpdateBalance($this->invoice, $balance_adjustment, $is_draft))->run(); - if ($this->invoice->is_deleted) { + if ((bool)$this->invoice->is_deleted !== false) { return $this; } From 3a04c9097d3728f2c5fffebfa9be140721b6e7df Mon Sep 17 00:00:00 2001 From: David Bomba Date: Sat, 27 Nov 2021 11:46:28 +1100 Subject: [PATCH 09/20] Fixes for square token billing --- app/PaymentDrivers/SquarePaymentDriver.php | 1 + 1 file changed, 1 insertion(+) diff --git a/app/PaymentDrivers/SquarePaymentDriver.php b/app/PaymentDrivers/SquarePaymentDriver.php index 5970cfd491bb..9a52c6e0980a 100644 --- a/app/PaymentDrivers/SquarePaymentDriver.php +++ b/app/PaymentDrivers/SquarePaymentDriver.php @@ -136,6 +136,7 @@ class SquarePaymentDriver extends BaseDriver $amount_money->setCurrency($this->client->currency()->code); $body = new \Square\Models\CreatePaymentRequest($cgt->token, \Illuminate\Support\Str::random(32), $amount_money); + $body->setCustomerId($cgt->gateway_customer_reference); /** @var ApiResponse */ $response = $this->square->getPaymentsApi()->createPayment($body); From 706e8cf240d9e1f4a530364af6bd066d58095ff4 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Sat, 27 Nov 2021 12:03:53 +1100 Subject: [PATCH 10/20] logging for user notiifcations --- app/Utils/Traits/Notifications/UserNotifies.php | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/app/Utils/Traits/Notifications/UserNotifies.php b/app/Utils/Traits/Notifications/UserNotifies.php index 0e1ce5823a8e..e62d4d709c86 100644 --- a/app/Utils/Traits/Notifications/UserNotifies.php +++ b/app/Utils/Traits/Notifications/UserNotifies.php @@ -61,6 +61,13 @@ trait UserNotifies array_push($required_permissions, 'all_user_notifications'); } + +nlog($company_user->notifications); +nlog($required_permissions); +nlog(count(array_intersect($required_permissions, ['all_user_notifications']))); +nlog(count(array_intersect($required_permissions, ['all_notifications']))); +nlog(count(array_intersect($required_permissions, $notifications->email))); + if (count(array_intersect($required_permissions, $notifications->email)) >= 1 || count(array_intersect(['all_user_notifications'], $notifications->email)) >= 1 || count(array_intersect(['all_notifications'],$notifications->email)) >= 1) { array_push($notifiable_methods, 'mail'); } @@ -79,12 +86,6 @@ trait UserNotifies $notifiable_methods = []; $notifications = $company_user->notifications; -nlog($company_user->notifications); -nlog($required_permissions); -nlog(count(array_intersect($required_permissions, ['all_user_notifications']))); -nlog(count(array_intersect($required_permissions, ['all_notifications']))); - -nlog(count(array_intersect($required_permissions, $notifications->email))); //conditional to define whether the company user has the required notification for the MAIL notification TYPE if (count(array_intersect($required_permissions, $notifications->email)) >= 1 || count(array_intersect($required_permissions, ['all_user_notifications'])) >= 1 || count(array_intersect($required_permissions, ['all_notifications'])) >= 1) { array_push($notifiable_methods, 'mail'); From dc1fe692a31e6bffc51dcfe80465c8d8c8125415 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Sat, 27 Nov 2021 15:54:49 +1100 Subject: [PATCH 11/20] Adjustments for entity notifications --- app/Jobs/Mail/PaymentFailedMailer.php | 2 +- app/Jobs/Mail/PaymentFailureMailer.php | 2 +- app/PaymentDrivers/BaseDriver.php | 2 +- app/PaymentDrivers/CheckoutCom/CreditCard.php | 6 +++--- app/PaymentDrivers/CheckoutCom/Utilities.php | 5 +++-- app/Utils/Traits/Notifications/UserNotifies.php | 11 ++--------- 6 files changed, 11 insertions(+), 17 deletions(-) diff --git a/app/Jobs/Mail/PaymentFailedMailer.php b/app/Jobs/Mail/PaymentFailedMailer.php index 58c6abc1059d..75c8ef97a568 100644 --- a/app/Jobs/Mail/PaymentFailedMailer.php +++ b/app/Jobs/Mail/PaymentFailedMailer.php @@ -85,7 +85,7 @@ class PaymentFailedMailer implements ShouldQueue //determine if this user has the right permissions // $methods = $this->findCompanyUserNotificationType($company_user, ['payment_failure_all','payment_failure','all_notifications']); - $methods = $this->findUserEntityNotificationType($this->client, $company_user, ['payment_failure_all','payment_failure','all_notifications']); + $methods = $this->findUserEntityNotificationType($this->client, $company_user, ['payment_failure_user','payment_failure_all','payment_failure','all_notifications']); //if mail is a method type -fire mail!! if (($key = array_search('mail', $methods)) !== false) { diff --git a/app/Jobs/Mail/PaymentFailureMailer.php b/app/Jobs/Mail/PaymentFailureMailer.php index 98a2c2448985..c1a3aaee3197 100644 --- a/app/Jobs/Mail/PaymentFailureMailer.php +++ b/app/Jobs/Mail/PaymentFailureMailer.php @@ -80,7 +80,7 @@ class PaymentFailureMailer implements ShouldQueue $this->company->company_users->each(function ($company_user) { //determine if this user has the right permissions - $methods = $this->findCompanyUserNotificationType($company_user, ['payment_failure_all','payment_failure','all_notifications']); + $methods = $this->findCompanyUserNotificationType($company_user, ['payment_failure_all','payment_failure', 'payment_failure_user', 'all_notifications']); //if mail is a method type -fire mail!! if (($key = array_search('mail', $methods)) !== false) { diff --git a/app/PaymentDrivers/BaseDriver.php b/app/PaymentDrivers/BaseDriver.php index af59a1c69578..bd29febe3044 100644 --- a/app/PaymentDrivers/BaseDriver.php +++ b/app/PaymentDrivers/BaseDriver.php @@ -440,7 +440,7 @@ class BaseDriver extends AbstractPaymentDriver $invoices->first()->invitations->each(function ($invitation) use ($nmo) { - if ($invitation->contact->email) { + if ((bool)$invitation->contact->send_email !== false && $invitation->contact->email) { $nmo->to_user = $invitation->contact; NinjaMailerJob::dispatch($nmo); diff --git a/app/PaymentDrivers/CheckoutCom/CreditCard.php b/app/PaymentDrivers/CheckoutCom/CreditCard.php index cd00111dc892..89cebc3da19d 100644 --- a/app/PaymentDrivers/CheckoutCom/CreditCard.php +++ b/app/PaymentDrivers/CheckoutCom/CreditCard.php @@ -213,10 +213,10 @@ class CreditCard implements MethodInterface if ($response->status == 'Declined') { $this->checkout->unWindGatewayFees($this->checkout->payment_hash); - $this->checkout->sendFailureMail($response->response_summary); - + // $this->checkout->sendFailureMail($response->response_summary); + //@todo - this will double up the checkout . com failed mails - $this->checkout->clientPaymentFailureMailer($response->status); + // $this->checkout->clientPaymentFailureMailer($response->status); return $this->processUnsuccessfulPayment($response); } diff --git a/app/PaymentDrivers/CheckoutCom/Utilities.php b/app/PaymentDrivers/CheckoutCom/Utilities.php index ca4c544d75b4..438453050124 100644 --- a/app/PaymentDrivers/CheckoutCom/Utilities.php +++ b/app/PaymentDrivers/CheckoutCom/Utilities.php @@ -84,8 +84,9 @@ trait Utilities public function processUnsuccessfulPayment(Payment $_payment, $throw_exception = true) { - $this->getParent()->sendFailureMail($_payment->status . " " . optional($_payment)->response_summary); - + $this->getParent()->sendFailureMail($_payment->response_summary); + $this->getParent()->clientPaymentFailureMailer($_payment->status); + $message = [ 'server_response' => $_payment, 'data' => $this->getParent()->payment_hash->data, diff --git a/app/Utils/Traits/Notifications/UserNotifies.php b/app/Utils/Traits/Notifications/UserNotifies.php index e62d4d709c86..979c937a5270 100644 --- a/app/Utils/Traits/Notifications/UserNotifies.php +++ b/app/Utils/Traits/Notifications/UserNotifies.php @@ -61,18 +61,11 @@ trait UserNotifies array_push($required_permissions, 'all_user_notifications'); } - -nlog($company_user->notifications); -nlog($required_permissions); -nlog(count(array_intersect($required_permissions, ['all_user_notifications']))); -nlog(count(array_intersect($required_permissions, ['all_notifications']))); -nlog(count(array_intersect($required_permissions, $notifications->email))); - - if (count(array_intersect($required_permissions, $notifications->email)) >= 1 || count(array_intersect(['all_user_notifications'], $notifications->email)) >= 1 || count(array_intersect(['all_notifications'],$notifications->email)) >= 1) { + if (count(array_intersect($required_permissions, $notifications->email)) >= 1 || count(array_intersect(['all_notifications'],$notifications->email)) >= 1) { array_push($notifiable_methods, 'mail'); } - +nlog($notifiable_methods); return $notifiable_methods; } From 94fa01091d50eb66f01084a613a8479fa20e6e9e Mon Sep 17 00:00:00 2001 From: David Bomba Date: Sat, 27 Nov 2021 19:59:55 +1100 Subject: [PATCH 12/20] Fixes for user notifications --- app/Jobs/Mail/PaymentFailedMailer.php | 13 +++-- app/PaymentDrivers/CheckoutCom/Utilities.php | 2 +- .../Traits/Notifications/UserNotifies.php | 56 ++++++++++++++++++- 3 files changed, 61 insertions(+), 10 deletions(-) diff --git a/app/Jobs/Mail/PaymentFailedMailer.php b/app/Jobs/Mail/PaymentFailedMailer.php index 75c8ef97a568..da316645ae98 100644 --- a/app/Jobs/Mail/PaymentFailedMailer.php +++ b/app/Jobs/Mail/PaymentFailedMailer.php @@ -20,6 +20,7 @@ use App\Mail\Admin\EntityNotificationMailer; use App\Mail\Admin\PaymentFailureObject; use App\Models\Client; use App\Models\Company; +use App\Models\Invoice; use App\Models\PaymentHash; use App\Models\User; use App\Utils\Traits\Notifications\UserNotifies; @@ -75,17 +76,17 @@ class PaymentFailedMailer implements ShouldQueue $settings = $this->client->getMergedSettings(); $amount = 0; + $invoice = false; - if($this->payment_hash) + if($this->payment_hash){ $amount = array_sum(array_column($this->payment_hash->invoices(), 'amount')) + $this->payment_hash->fee_total; + $invoice = Invoice::whereIn('id', $this->transformKeys(array_column($payment_hash->invoices(), 'invoice_id')))->withTrashed()->first(); + } //iterate through company_users - $this->company->company_users->each(function ($company_user) use($amount, $settings){ + $this->company->company_users->each(function ($company_user) use($amount, $settings, $invoice){ - //determine if this user has the right permissions - // $methods = $this->findCompanyUserNotificationType($company_user, ['payment_failure_all','payment_failure','all_notifications']); - - $methods = $this->findUserEntityNotificationType($this->client, $company_user, ['payment_failure_user','payment_failure_all','payment_failure','all_notifications']); + $methods = $this->findUserEntityNotificationType($invoice ?: $this->client, $company_user, ['payment_failure_user', 'payment_failure_all', 'payment_failure', 'all_notifications']); //if mail is a method type -fire mail!! if (($key = array_search('mail', $methods)) !== false) { diff --git a/app/PaymentDrivers/CheckoutCom/Utilities.php b/app/PaymentDrivers/CheckoutCom/Utilities.php index 438453050124..85b7bf0c5da9 100644 --- a/app/PaymentDrivers/CheckoutCom/Utilities.php +++ b/app/PaymentDrivers/CheckoutCom/Utilities.php @@ -85,7 +85,7 @@ trait Utilities public function processUnsuccessfulPayment(Payment $_payment, $throw_exception = true) { $this->getParent()->sendFailureMail($_payment->response_summary); - $this->getParent()->clientPaymentFailureMailer($_payment->status); + // $this->getParent()->clientPaymentFailureMailer($_payment->status); $message = [ 'server_response' => $_payment, diff --git a/app/Utils/Traits/Notifications/UserNotifies.php b/app/Utils/Traits/Notifications/UserNotifies.php index 979c937a5270..24a7b72e8dee 100644 --- a/app/Utils/Traits/Notifications/UserNotifies.php +++ b/app/Utils/Traits/Notifications/UserNotifies.php @@ -11,6 +11,11 @@ namespace App\Utils\Traits\Notifications; +use App\Models\Client; +use App\Models\Invoice; +use App\Models\Payment; +use App\Models\Quote; + /** * Class UserNotifies. * @@ -31,7 +36,7 @@ trait UserNotifies //if a user owns this record or is assigned to it, they are attached the permission for notification. if ($invitation->{$entity_name}->user_id == $company_user->_user_id || $invitation->{$entity_name}->assigned_user_id == $company_user->user_id) { - array_push($required_permissions, 'all_user_notifications'); + $required_permissions = $this->addSpecialUserPermissionForEntity($invitation->{$entity_name}, $required_permissions); } if (count(array_intersect($required_permissions, $notifications->email)) >= 1 || count(array_intersect(['all_user_notifications'], $notifications->email)) >= 1 || count(array_intersect(['all_notifications'],$notifications->email)) >= 1) { @@ -58,17 +63,62 @@ trait UserNotifies } if ($entity->user_id == $company_user->_user_id || $entity->assigned_user_id == $company_user->user_id) { - array_push($required_permissions, 'all_user_notifications'); + $required_permissions = $this->addSpecialUserPermissionForEntity($entity, $required_permissions); + } + else{ + $required_permissions = $this->removeSpecialUserPermissionForEntity($entity, $required_permissions); } if (count(array_intersect($required_permissions, $notifications->email)) >= 1 || count(array_intersect(['all_notifications'],$notifications->email)) >= 1) { array_push($notifiable_methods, 'mail'); } -nlog($notifiable_methods); return $notifiable_methods; } + private function addSpecialUserPermissionForEntity($entity, $required_permissions) + { + switch ($entity) { + case ($entity instanceof Payment || $entity instanceof Client): //we pass client also as this is the proxy for Payment Failures (ie, there is no payment) + return array_push($required_permissions, ["all_user_notifications","payment_failure_user","payment_success_user"]); + break; + case ($entity instanceof Invoice): + return array_push($required_permissions, ["all_user_notifications","invoice_created_user","invoice_sent_user","invoice_viewed_user","invoice_late_user"]); + break; + case ($entity instanceof Quote): + return array_push($required_permissions, ["all_user_notifications","quote_created_user","quote_sent_user","quote_viewed_user","quote_approved_user","quote_expired_user"]); + break; + case ($entity instanceof Credit): + return array_push($required_permissions, ["all_user_notifications","credit_created_user","credit_sent_user","credit_viewed_user"]); + break; + default: + // code... + break; + } + } + + private function removeSpecialUserPermissionForEntity($entity, $required_permissions) + { + switch ($entity) { + case ($entity instanceof Payment || $entity instanceof Client): //we pass client also as this is the proxy for Payment Failures (ie, there is no payment) + return array_diff($required_permissions, ["all_user_notifications","payment_failure_user","payment_success_user"]); + break; + case ($entity instanceof Invoice): + return array_diff($required_permissions, ["all_user_notifications","invoice_created_user","invoice_sent_user","invoice_viewed_user","invoice_late_user"]); + break; + case ($entity instanceof Quote): + return array_diff($required_permissions, ["all_user_notifications","quote_created_user","quote_sent_user","quote_viewed_user","quote_approved_user","quote_expired_user"]); + break; + case ($entity instanceof Credit): + return array_diff($required_permissions, ["all_user_notifications","credit_created_user","credit_sent_user","credit_viewed_user"]); + break; + default: + // code... + break; + } + } + + public function findCompanyUserNotificationType($company_user, $required_permissions) :array { From 08d2250ca85b52a6722cca01e1d01abd53c7f703 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Sat, 27 Nov 2021 20:24:31 +1100 Subject: [PATCH 13/20] Fixes for notifications --- app/Listeners/Payment/PaymentNotification.php | 7 +++- .../Traits/Notifications/UserNotifies.php | 37 ++++++++++--------- 2 files changed, 25 insertions(+), 19 deletions(-) diff --git a/app/Listeners/Payment/PaymentNotification.php b/app/Listeners/Payment/PaymentNotification.php index ca9bb0d3bf48..afe1d40571e5 100644 --- a/app/Listeners/Payment/PaymentNotification.php +++ b/app/Listeners/Payment/PaymentNotification.php @@ -59,7 +59,12 @@ class PaymentNotification implements ShouldQueue foreach ($payment->company->company_users as $company_user) { $user = $company_user->user; - $methods = $this->findUserEntityNotificationType($payment, $company_user, ['payment_success', 'payment_success_all', 'all_notifications']); + $methods = $this->findUserEntityNotificationType($payment, $company_user, [ + 'payment_success', + 'payment_success_all', + 'payment_success_user', + 'all_notifications'] + ); if (($key = array_search('mail', $methods)) !== false) { unset($methods[$key]); diff --git a/app/Utils/Traits/Notifications/UserNotifies.php b/app/Utils/Traits/Notifications/UserNotifies.php index 24a7b72e8dee..701c71d951c7 100644 --- a/app/Utils/Traits/Notifications/UserNotifies.php +++ b/app/Utils/Traits/Notifications/UserNotifies.php @@ -38,27 +38,23 @@ trait UserNotifies if ($invitation->{$entity_name}->user_id == $company_user->_user_id || $invitation->{$entity_name}->assigned_user_id == $company_user->user_id) { $required_permissions = $this->addSpecialUserPermissionForEntity($invitation->{$entity_name}, $required_permissions); } - - if (count(array_intersect($required_permissions, $notifications->email)) >= 1 || count(array_intersect(['all_user_notifications'], $notifications->email)) >= 1 || count(array_intersect(['all_notifications'],$notifications->email)) >= 1) { - array_push($notifiable_methods, 'mail'); + else{ + $required_permissions = $this->removeSpecialUserPermissionForEntity($invitation->{$entity_name}, $required_permissions); } - // if(count(array_intersect($required_permissions, $notifications->slack)) >=1) - // array_push($notifiable_methods, 'slack'); + if (count(array_intersect($required_permissions, $notifications->email)) >= 1) { + array_push($notifiable_methods, 'mail'); + } return $notifiable_methods; } - public function findUserEntityNotificationType($entity, $company_user, $required_permissions) :array + public function findUserEntityNotificationType($entity, $company_user, array $required_permissions) :array { - if ($company_user->company->is_disabled) { - return []; - } - $notifiable_methods = []; $notifications = $company_user->notifications; - if (! $notifications) { + if ($company_user->company->is_disabled || ! $notifications) { return []; } @@ -69,36 +65,41 @@ trait UserNotifies $required_permissions = $this->removeSpecialUserPermissionForEntity($entity, $required_permissions); } - if (count(array_intersect($required_permissions, $notifications->email)) >= 1 || count(array_intersect(['all_notifications'],$notifications->email)) >= 1) { + if (count(array_intersect($required_permissions, $notifications->email)) >= 1) { array_push($notifiable_methods, 'mail'); } return $notifiable_methods; } - private function addSpecialUserPermissionForEntity($entity, $required_permissions) + private function addSpecialUserPermissionForEntity($entity, array $required_permissions) :array { + + array_push($required_permissions, ["all_notifications"]); + switch ($entity) { case ($entity instanceof Payment || $entity instanceof Client): //we pass client also as this is the proxy for Payment Failures (ie, there is no payment) - return array_push($required_permissions, ["all_user_notifications","payment_failure_user","payment_success_user"]); + return array_merge($required_permissions, ["all_notifications","all_user_notifications","payment_failure_user","payment_success_user"]); break; case ($entity instanceof Invoice): - return array_push($required_permissions, ["all_user_notifications","invoice_created_user","invoice_sent_user","invoice_viewed_user","invoice_late_user"]); + return array_merge($required_permissions, ["all_notifications","all_user_notifications","invoice_created_user","invoice_sent_user","invoice_viewed_user","invoice_late_user"]); break; case ($entity instanceof Quote): - return array_push($required_permissions, ["all_user_notifications","quote_created_user","quote_sent_user","quote_viewed_user","quote_approved_user","quote_expired_user"]); + return array_merge($required_permissions, ["all_notifications","all_user_notifications","quote_created_user","quote_sent_user","quote_viewed_user","quote_approved_user","quote_expired_user"]); break; case ($entity instanceof Credit): - return array_push($required_permissions, ["all_user_notifications","credit_created_user","credit_sent_user","credit_viewed_user"]); + return array_merge($required_permissions, ["all_notifications","all_user_notifications","credit_created_user","credit_sent_user","credit_viewed_user"]); break; default: - // code... + return []; break; } } private function removeSpecialUserPermissionForEntity($entity, $required_permissions) { + array_merge($required_permissions, ["all_notifications"]); + switch ($entity) { case ($entity instanceof Payment || $entity instanceof Client): //we pass client also as this is the proxy for Payment Failures (ie, there is no payment) return array_diff($required_permissions, ["all_user_notifications","payment_failure_user","payment_success_user"]); From 7376702748760c07212c6278469d1df7bb39f8fc Mon Sep 17 00:00:00 2001 From: David Bomba Date: Sat, 27 Nov 2021 20:25:27 +1100 Subject: [PATCH 14/20] minor fixes --- app/Utils/Traits/Notifications/UserNotifies.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/Utils/Traits/Notifications/UserNotifies.php b/app/Utils/Traits/Notifications/UserNotifies.php index 701c71d951c7..c60b17441807 100644 --- a/app/Utils/Traits/Notifications/UserNotifies.php +++ b/app/Utils/Traits/Notifications/UserNotifies.php @@ -75,7 +75,7 @@ trait UserNotifies private function addSpecialUserPermissionForEntity($entity, array $required_permissions) :array { - array_push($required_permissions, ["all_notifications"]); + array_merge($required_permissions, ["all_notifications"]); switch ($entity) { case ($entity instanceof Payment || $entity instanceof Client): //we pass client also as this is the proxy for Payment Failures (ie, there is no payment) From 489e02649eb5199fa98436c39ed75b4a82a01580 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Sun, 28 Nov 2021 10:58:54 +1100 Subject: [PATCH 15/20] fixes for the ninja portal --- .../ClientPortal/NinjaPlanController.php | 16 +++++++++------- app/Http/ViewComposers/PortalComposer.php | 3 ++- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/app/Http/Controllers/ClientPortal/NinjaPlanController.php b/app/Http/Controllers/ClientPortal/NinjaPlanController.php index e41fb872a6ef..c9047f7ba68b 100644 --- a/app/Http/Controllers/ClientPortal/NinjaPlanController.php +++ b/app/Http/Controllers/ClientPortal/NinjaPlanController.php @@ -52,12 +52,15 @@ class NinjaPlanController extends Controller Auth::guard('contact')->login($client_contact,true); - /* Current paid users get pushed straight to subscription overview page*/ - if($account->isPaidHostedClient()) - return redirect('/client/dashboard'); + // /* Current paid users get pushed straight to subscription overview page*/ + // if($account->isPaidHostedClient()) + // return redirect('/client/dashboard'); - /* Users that are not paid get pushed to a custom purchase page */ - return $this->render('subscriptions.ninja_plan', ['settings' => $client_contact->company->settings]); + // /* Users that are not paid get pushed to a custom purchase page */ + // return $this->render('subscriptions.ninja_plan', ['settings' => $client_contact->company->settings]); + + return $this->plan(); + } return redirect()->route('client.catchall'); @@ -137,8 +140,7 @@ class NinjaPlanController extends Controller } else - return redirect()->route('client.catchall'); - + return redirect('/client/dashboard'); } } diff --git a/app/Http/ViewComposers/PortalComposer.php b/app/Http/ViewComposers/PortalComposer.php index ca8472aaa496..e6b79e6f5a83 100644 --- a/app/Http/ViewComposers/PortalComposer.php +++ b/app/Http/ViewComposers/PortalComposer.php @@ -113,7 +113,6 @@ class PortalComposer $data[] = ['title' => ctrans('texts.payment_methods'), 'url' => 'client.payment_methods.index', 'icon' => 'shield']; $data[] = ['title' => ctrans('texts.documents'), 'url' => 'client.documents.index', 'icon' => 'download']; - $data[] = ['title' => ctrans('texts.subscriptions'), 'url' => 'client.subscriptions.index', 'icon' => 'calendar']; if (auth('contact')->user()->client->getSetting('enable_client_portal_tasks')) { $data[] = ['title' => ctrans('texts.tasks'), 'url' => 'client.tasks.index', 'icon' => 'clock']; @@ -123,6 +122,8 @@ class PortalComposer if(Ninja::isHosted() && auth('contact')->user()->company->id == config('ninja.ninja_default_company_id')) $data[] = ['title' => ctrans('texts.plan'), 'url' => 'client.plan', 'icon' => 'credit-card']; + else + $data[] = ['title' => ctrans('texts.subscriptions'), 'url' => 'client.subscriptions.index', 'icon' => 'calendar']; return $data; From c3c09764d87bca9b7b339074a9fd01e8f78da113 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Sun, 28 Nov 2021 11:53:58 +1100 Subject: [PATCH 16/20] Fixes for credit tests --- tests/Feature/CreditTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Feature/CreditTest.php b/tests/Feature/CreditTest.php index 0562f2fd16a7..9a6e078d4ac7 100644 --- a/tests/Feature/CreditTest.php +++ b/tests/Feature/CreditTest.php @@ -104,7 +104,7 @@ class CreditTest extends TestCase 'number' => 'dfdfd', 'discount' => 0, 'is_amount_discount' => 1, - 'number' => '3434343', + 'number' => '34343xx43', 'public_notes' => 'notes', 'is_deleted' => 0, 'custom_value1' => 0, From 6d9b4dbbca29fcf61a27cc3b78cb0779a12795dc Mon Sep 17 00:00:00 2001 From: David Bomba Date: Sun, 28 Nov 2021 12:19:25 +1100 Subject: [PATCH 17/20] Upgrade to PHP 8.1 --- .github/workflows/phpunit.yml | 2 +- composer.json | 2 +- composer.lock | 78 ++++++++++++++++++----------------- tests/Feature/CreditTest.php | 2 +- 4 files changed, 43 insertions(+), 41 deletions(-) diff --git a/.github/workflows/phpunit.yml b/.github/workflows/phpunit.yml index 559591bf7489..ef17569537a7 100644 --- a/.github/workflows/phpunit.yml +++ b/.github/workflows/phpunit.yml @@ -13,7 +13,7 @@ jobs: strategy: matrix: operating-system: ['ubuntu-18.04', 'ubuntu-20.04'] - php-versions: ['7.4','8.0'] + php-versions: ['7.4','8.0','8.1'] phpunit-versions: ['latest'] env: diff --git a/composer.json b/composer.json index 3d687fb3697c..877931817fe1 100644 --- a/composer.json +++ b/composer.json @@ -26,7 +26,7 @@ ], "type": "project", "require": { - "php": "^7.4|^8.0", + "php": "^7.4|^8", "ext-dom": "*", "ext-json": "*", "ext-libxml": "*", diff --git a/composer.lock b/composer.lock index b5973768c638..85f86f3316f1 100644 --- a/composer.lock +++ b/composer.lock @@ -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": "da1e6c59711334fd5dca75d2adb884d8", + "content-hash": "cd912a40faea3a658298daa4b17a7f25", "packages": [ { "name": "apimatic/jsonmapper", @@ -323,16 +323,16 @@ }, { "name": "aws/aws-sdk-php", - "version": "3.204.5", + "version": "3.204.6", "source": { "type": "git", "url": "https://github.com/aws/aws-sdk-php.git", - "reference": "1f690db4dfd66d0c729f4f8db12431bb047b4900" + "reference": "59d4d6a58ed7da541aa0ed75cc1944f8d6ca2d1c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/1f690db4dfd66d0c729f4f8db12431bb047b4900", - "reference": "1f690db4dfd66d0c729f4f8db12431bb047b4900", + "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/59d4d6a58ed7da541aa0ed75cc1944f8d6ca2d1c", + "reference": "59d4d6a58ed7da541aa0ed75cc1944f8d6ca2d1c", "shasum": "" }, "require": { @@ -408,9 +408,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.204.5" + "source": "https://github.com/aws/aws-sdk-php/tree/3.204.6" }, - "time": "2021-11-24T19:13:34+00:00" + "time": "2021-11-26T19:18:52+00:00" }, { "name": "bacon/bacon-qr-code", @@ -1735,36 +1735,38 @@ }, { "name": "doctrine/dbal", - "version": "3.1.4", + "version": "3.2.0", "source": { "type": "git", "url": "https://github.com/doctrine/dbal.git", - "reference": "821b4f01a36ce63ed36c090ea74767b72db367e9" + "reference": "5d54f63541d7bed1156cb5c9b79274ced61890e4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/dbal/zipball/821b4f01a36ce63ed36c090ea74767b72db367e9", - "reference": "821b4f01a36ce63ed36c090ea74767b72db367e9", + "url": "https://api.github.com/repos/doctrine/dbal/zipball/5d54f63541d7bed1156cb5c9b79274ced61890e4", + "reference": "5d54f63541d7bed1156cb5c9b79274ced61890e4", "shasum": "" }, "require": { "composer/package-versions-deprecated": "^1.11.99", - "doctrine/cache": "^1.0|^2.0", + "doctrine/cache": "^1.11|^2.0", "doctrine/deprecations": "^0.5.3", "doctrine/event-manager": "^1.0", - "php": "^7.3 || ^8.0" + "php": "^7.3 || ^8.0", + "psr/cache": "^1|^2|^3", + "psr/log": "^1|^2|^3" }, "require-dev": { "doctrine/coding-standard": "9.0.0", "jetbrains/phpstorm-stubs": "2021.1", - "phpstan/phpstan": "1.1.1", - "phpstan/phpstan-strict-rules": "^1", + "phpstan/phpstan": "1.2.0", + "phpstan/phpstan-strict-rules": "^1.1", "phpunit/phpunit": "9.5.10", "psalm/plugin-phpunit": "0.16.1", "squizlabs/php_codesniffer": "3.6.1", "symfony/cache": "^5.2|^6.0", "symfony/console": "^2.0.5|^3.0|^4.0|^5.0|^6.0", - "vimeo/psalm": "4.12.0" + "vimeo/psalm": "4.13.0" }, "suggest": { "symfony/console": "For helpful console commands such as SQL execution and import of files." @@ -1824,7 +1826,7 @@ ], "support": { "issues": "https://github.com/doctrine/dbal/issues", - "source": "https://github.com/doctrine/dbal/tree/3.1.4" + "source": "https://github.com/doctrine/dbal/tree/3.2.0" }, "funding": [ { @@ -1840,7 +1842,7 @@ "type": "tidelift" } ], - "time": "2021-11-15T16:44:33+00:00" + "time": "2021-11-26T21:00:12+00:00" }, { "name": "doctrine/deprecations", @@ -4589,16 +4591,16 @@ }, { "name": "league/flysystem", - "version": "1.1.6", + "version": "1.1.7", "source": { "type": "git", "url": "https://github.com/thephpleague/flysystem.git", - "reference": "627be7fcde84c71aa0f15097fcf48fd5f2be5287" + "reference": "3ca8f158ee21efa4bbd4f74bea5730c9b9261e2d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/flysystem/zipball/627be7fcde84c71aa0f15097fcf48fd5f2be5287", - "reference": "627be7fcde84c71aa0f15097fcf48fd5f2be5287", + "url": "https://api.github.com/repos/thephpleague/flysystem/zipball/3ca8f158ee21efa4bbd4f74bea5730c9b9261e2d", + "reference": "3ca8f158ee21efa4bbd4f74bea5730c9b9261e2d", "shasum": "" }, "require": { @@ -4671,7 +4673,7 @@ ], "support": { "issues": "https://github.com/thephpleague/flysystem/issues", - "source": "https://github.com/thephpleague/flysystem/tree/1.1.6" + "source": "https://github.com/thephpleague/flysystem/tree/1.1.7" }, "funding": [ { @@ -4679,7 +4681,7 @@ "type": "other" } ], - "time": "2021-11-21T11:04:36+00:00" + "time": "2021-11-25T19:40:58+00:00" }, { "name": "league/flysystem-aws-s3-v3", @@ -6427,16 +6429,16 @@ }, { "name": "php-http/client-common", - "version": "2.4.0", + "version": "2.5.0", "source": { "type": "git", "url": "https://github.com/php-http/client-common.git", - "reference": "29e0c60d982f04017069483e832b92074d0a90b2" + "reference": "d135751167d57e27c74de674d6a30cef2dc8e054" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-http/client-common/zipball/29e0c60d982f04017069483e832b92074d0a90b2", - "reference": "29e0c60d982f04017069483e832b92074d0a90b2", + "url": "https://api.github.com/repos/php-http/client-common/zipball/d135751167d57e27c74de674d6a30cef2dc8e054", + "reference": "d135751167d57e27c74de674d6a30cef2dc8e054", "shasum": "" }, "require": { @@ -6447,14 +6449,14 @@ "psr/http-client": "^1.0", "psr/http-factory": "^1.0", "psr/http-message": "^1.0", - "symfony/options-resolver": "^2.6 || ^3.4.20 || ~4.0.15 || ~4.1.9 || ^4.2.1 || ^5.0", + "symfony/options-resolver": "~4.0.15 || ~4.1.9 || ^4.2.1 || ^5.0 || ^6.0", "symfony/polyfill-php80": "^1.17" }, "require-dev": { "doctrine/instantiator": "^1.1", "guzzlehttp/psr7": "^1.4", "nyholm/psr7": "^1.2", - "phpspec/phpspec": "^5.1 || ^6.0", + "phpspec/phpspec": "^5.1 || ^6.3 || ^7.1", "phpspec/prophecy": "^1.10.2", "phpunit/phpunit": "^7.5.15 || ^8.5 || ^9.3" }, @@ -6496,9 +6498,9 @@ ], "support": { "issues": "https://github.com/php-http/client-common/issues", - "source": "https://github.com/php-http/client-common/tree/2.4.0" + "source": "https://github.com/php-http/client-common/tree/2.5.0" }, - "time": "2021-07-05T08:19:25+00:00" + "time": "2021-11-26T15:01:24+00:00" }, { "name": "php-http/discovery", @@ -12585,16 +12587,16 @@ }, { "name": "facade/ignition", - "version": "2.17.0", + "version": "2.17.1", "source": { "type": "git", "url": "https://github.com/facade/ignition.git", - "reference": "28d12b473ffcbe326959385772fd5125c73bc974" + "reference": "317f6110c1977b50e06365bbb155fbe5079035ec" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/facade/ignition/zipball/28d12b473ffcbe326959385772fd5125c73bc974", - "reference": "28d12b473ffcbe326959385772fd5125c73bc974", + "url": "https://api.github.com/repos/facade/ignition/zipball/317f6110c1977b50e06365bbb155fbe5079035ec", + "reference": "317f6110c1977b50e06365bbb155fbe5079035ec", "shasum": "" }, "require": { @@ -12659,7 +12661,7 @@ "issues": "https://github.com/facade/ignition/issues", "source": "https://github.com/facade/ignition" }, - "time": "2021-11-24T08:47:21+00:00" + "time": "2021-11-25T10:26:30+00:00" }, { "name": "facade/ignition-contracts", @@ -15611,7 +15613,7 @@ "prefer-stable": true, "prefer-lowest": false, "platform": { - "php": "^7.4|^8.0", + "php": "^7.4|^8", "ext-dom": "*", "ext-json": "*", "ext-libxml": "*" diff --git a/tests/Feature/CreditTest.php b/tests/Feature/CreditTest.php index 9a6e078d4ac7..372602ec8669 100644 --- a/tests/Feature/CreditTest.php +++ b/tests/Feature/CreditTest.php @@ -71,7 +71,7 @@ class CreditTest extends TestCase public function testCreditRESTEndPoints() { $response = $this->withHeaders([ - 'X-API-SECRET' => config('ninja.api_secret'), + 'X-API-SECRET' => config('ninja.api_secret'), 'X-API-TOKEN' => $this->token, ])->get('/api/v1/credits/'.$this->encodePrimaryKey($this->credit->id)); From d3d5429015eedec9dae932ae7a1c94547686d9d6 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Sun, 28 Nov 2021 14:56:39 +1100 Subject: [PATCH 18/20] change from ->get() to ->cursor() for client statements --- app/Services/Client/Statement.php | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/app/Services/Client/Statement.php b/app/Services/Client/Statement.php index 4bd2131182d8..1c26d19324d4 100644 --- a/app/Services/Client/Statement.php +++ b/app/Services/Client/Statement.php @@ -30,6 +30,7 @@ use App\Utils\PhantomJS\Phantom; use App\Utils\Traits\Pdf\PdfMaker as PdfMakerTrait; use Illuminate\Database\Eloquent\Collection; use Illuminate\Support\Facades\DB; +use Illuminate\Support\LazyCollection; class Statement { @@ -217,7 +218,7 @@ class Statement * * @return Invoice[]|\Illuminate\Database\Eloquent\Collection */ - protected function getInvoices(): Collection + protected function getInvoices(): LazyCollection { return Invoice::withTrashed() ->where('is_deleted', false) @@ -226,7 +227,7 @@ class Statement ->whereIn('status_id', [Invoice::STATUS_SENT, Invoice::STATUS_PARTIAL, Invoice::STATUS_PAID]) ->whereBetween('date', [$this->options['start_date'], $this->options['end_date']]) ->orderBy('number', 'ASC') - ->get(); + ->cursor(); } /** @@ -234,7 +235,7 @@ class Statement * * @return Payment[]|\Illuminate\Database\Eloquent\Collection */ - protected function getPayments(): Collection + protected function getPayments(): LazyCollection { return Payment::withTrashed() ->with('client.country','invoices') @@ -244,7 +245,7 @@ class Statement ->whereIn('status_id', [Payment::STATUS_COMPLETED, Payment::STATUS_PARTIALLY_REFUNDED, Payment::STATUS_REFUNDED]) ->whereBetween('date', [$this->options['start_date'], $this->options['end_date']]) ->orderBy('number', 'ASC') - ->get(); + ->cursor(); } /** From 08963d7cd69f7ae5ceba7ad6ec1c60c0f60b5315 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Sun, 28 Nov 2021 15:05:59 +1100 Subject: [PATCH 19/20] Fixes for types in user notifies --- app/Utils/Traits/Notifications/UserNotifies.php | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/app/Utils/Traits/Notifications/UserNotifies.php b/app/Utils/Traits/Notifications/UserNotifies.php index c60b17441807..5b8d312c843b 100644 --- a/app/Utils/Traits/Notifications/UserNotifies.php +++ b/app/Utils/Traits/Notifications/UserNotifies.php @@ -12,6 +12,7 @@ namespace App\Utils\Traits\Notifications; use App\Models\Client; +use App\Models\Credit; use App\Models\Invoice; use App\Models\Payment; use App\Models\Quote; @@ -27,13 +28,14 @@ trait UserNotifies { public function findUserNotificationTypes($invitation, $company_user, $entity_name, $required_permissions) :array { - if ($company_user->company->is_disabled) { - return []; - } $notifiable_methods = []; $notifications = $company_user->notifications; + if ($company_user->company->is_disabled && is_array($notifications->email)) { + return []; + } + //if a user owns this record or is assigned to it, they are attached the permission for notification. if ($invitation->{$entity_name}->user_id == $company_user->_user_id || $invitation->{$entity_name}->assigned_user_id == $company_user->user_id) { $required_permissions = $this->addSpecialUserPermissionForEntity($invitation->{$entity_name}, $required_permissions); From 0c44ceb80d435f420d0c6faf569714b7fbaa2cea Mon Sep 17 00:00:00 2001 From: David Bomba Date: Sun, 28 Nov 2021 16:41:16 +1100 Subject: [PATCH 20/20] minor fixes for phpunit --- .github/workflows/phpunit.yml | 3 ++- phpunit.xml | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/phpunit.yml b/.github/workflows/phpunit.yml index ef17569537a7..3ad6fd8a9006 100644 --- a/.github/workflows/phpunit.yml +++ b/.github/workflows/phpunit.yml @@ -106,7 +106,8 @@ jobs: vendor/bin/phpunit --testdox env: DB_PORT: ${{ job.services.mysql.ports[3306] }} - + PHP_CS_FIXER_IGNORE_ENV: true + - name: Run php-cs-fixer run: | vendor/bin/php-cs-fixer fix diff --git a/phpunit.xml b/phpunit.xml index e1ef466e8b20..ec8019ee3005 100644 --- a/phpunit.xml +++ b/phpunit.xml @@ -18,7 +18,7 @@ - +