diff --git a/.env.example b/.env.example index a32c499ac..0331f9628 100644 --- a/.env.example +++ b/.env.example @@ -257,3 +257,11 @@ L5_SWAGGER_CONST_TOKEN_URL=${IDP_TOKEN_ENDPOINT} MEMCACHED_SERVER_HOST=127.0.0.1 MEMCACHED_SERVER_PORT=11211 + +# PAYMENT SERVICE + +PAYMENTS_SERVICE_BASE_URL= +# CLIENT SHOULD BE CONFIGURED with SECRET POST at IDP +PAYMENTS_SERVICE_OAUTH2_CLIENT_ID= +PAYMENTS_SERVICE_OAUTH2_CLIENT_SECRET= +PAYMENTS_SERVICE_OAUTH2_SCOPES=payment-profile/read diff --git a/app/Console/Commands/SetupPaymentServiceMessageBrokerCommand.php b/app/Console/Commands/SetupPaymentServiceMessageBrokerCommand.php new file mode 100644 index 000000000..ddc566e47 --- /dev/null +++ b/app/Console/Commands/SetupPaymentServiceMessageBrokerCommand.php @@ -0,0 +1,114 @@ +argument('exchange_name'); + + if (empty($exchange_name)) + throw new \InvalidArgumentException("exchange_name is required"); + + $exchange_type = $this->argument('exchange_type'); + + if (empty($exchange_type)) + throw new \InvalidArgumentException("exchange_type is required"); + + if (!$host_settings) { + throw new \InvalidArgumentException("Host setting not found at {$host_settings_path}"); + } + $queue_settings = Config::get($queue_settings_path); + + $host = $host_settings['host']; + $port = $host_settings['port']; + $user = $host_settings['user']; + $password = $host_settings['password']; + $vhost = $host_settings['vhost']; + + $queue = $queue_settings['queue']; + + $routingKeys = [ + EventTypes::PAYMENT_PROFILE_UPDATED, + EventTypes::PAYMENT_PROFILE_CREATED, + EventTypes::PAYMENT_PROFILE_DELETED, + ]; + + try { + $connection = new AMQPStreamConnection($host, $port, $user, $password, $vhost); + $channel = $connection->channel(); + + // Exchange + $channel->exchange_declare($exchange_name, $exchange_type, false, true, false); + + // Queue + $channel->queue_declare($queue, false, true, false, false); + + // Bindings + foreach ($routingKeys as $key) { + $channel->queue_bind($queue, $exchange_name, $key); + echo "Binding created: $queue ← $exchange_name ($key)\n"; + } + + $channel->close(); + $connection->close(); + echo "Done.\n"; + + } catch (Exception $ex) { + echo "Error: " . $ex->getMessage() . "\n"; + Log::error($ex); + exit(1); + } + } +} diff --git a/app/Console/Kernel.php b/app/Console/Kernel.php index 3fc457e65..f9672e759 100644 --- a/app/Console/Kernel.php +++ b/app/Console/Kernel.php @@ -53,6 +53,7 @@ class Kernel extends ConsoleKernel \App\Console\Commands\PurgeSummitsMarkAsDeletedCommand::class, \App\Console\Commands\IngestSummitOrderPaymentInfoCommand::class, \App\Console\Commands\SetupSponsorServiceMessageBrokerCommand::class, + \App\Console\Commands\SetupPaymentServiceMessageBrokerCommand::class, ]; /** @@ -112,4 +113,4 @@ protected function schedule(Schedule $schedule) $schedule->command('summit:registration-orders-payment-info-ingest')->everySixHours()->withoutOverlapping()->onOneServer(); } -} \ No newline at end of file +} diff --git a/app/Jobs/Payments/CreatePaymentProfileMQJob.php b/app/Jobs/Payments/CreatePaymentProfileMQJob.php new file mode 100644 index 000000000..23504f215 --- /dev/null +++ b/app/Jobs/Payments/CreatePaymentProfileMQJob.php @@ -0,0 +1,85 @@ +summit_repository = $summit_repository; + $this->service = $service; + $this->payments_api = $payments_api; + } + + public function handle(PaymentsMQJob $job): void{ + try { + $payload = $job->payload(); + $json = json_encode($payload); + Log::debug("CreatePaymentProfileMQJob::handle", ['payload' => $json ]); + $data = $payload['data']; + $id = intval($data['id']); + $summit_id = intval($data['summit_id']); + $application_type = $data['application_type']; + if(!in_array($application_type, IPaymentConstants::ValidApplicationTypes)){ + Log::warning("CreatePaymentProfileMQJob::handle Application Type $application_type is not valid."); + return; + } + $response = $this->payments_api->getPaymentProfile($summit_id, $id); + Log::debug("CreatePaymentProfileMQJob::handle", ['response' => $response]); + $summit = $this->summit_repository->getById($summit_id); + if($summit instanceof Summit) { + // mappings + $response['external_id'] = $id; + $response['active'] = $response['is_active'] ?? false; + Log::debug("CreatePaymentProfileMQJob::handle creating payment profile", ['response' => $response ]); + $this->service->addPaymentProfile($summit, $response); + } + $job->delete(); + } catch (\Exception $ex) { + Log::error($ex); + throw $ex; + } + } +} diff --git a/app/Jobs/Payments/DeletePaymentProfileMQJob.php b/app/Jobs/Payments/DeletePaymentProfileMQJob.php new file mode 100644 index 000000000..fea8301e7 --- /dev/null +++ b/app/Jobs/Payments/DeletePaymentProfileMQJob.php @@ -0,0 +1,82 @@ +summit_repository = $summit_repository; + $this->payment_gateway_profile_repository = $payment_gateway_profile_repository; + $this->service = $service; + } + + public function handle(PaymentsMQJob $job): void{ + try { + $payload = $job->payload(); + $json = json_encode($payload); + Log::debug("DeletePaymentProfileMQJob::handle", ['payload' => $json ]); + + $data = $payload['data']; + + $id = intval($data['id']); + $summit_id = intval($data['summit_id']); + $application_type = $data['application_type']; + if(!in_array($application_type, IPaymentConstants::ValidApplicationTypes)){ + Log::warning("DeletePaymentProfileMQJob::handle Application Type $application_type is not valid."); + return; + } + + $summit = $this->summit_repository->getById($summit_id); + $local_payment_profile = $this->payment_gateway_profile_repository->getByExternalId($id); + + if($summit instanceof Summit && $local_payment_profile instanceof PaymentGatewayProfile){ + $local_payment_profile_id = $local_payment_profile->getId(); + Log::warning("DeletePaymentProfileMQJob::handle deleting payment profile", ['local_payment_profile_id' => $local_payment_profile_id ]); + $this->service->deletePaymentProfile($summit, $local_payment_profile_id); + } + $job->delete(); + } catch (\Exception $ex) { + Log::error($ex); + throw $ex; + } + } +} + diff --git a/app/Jobs/Payments/EventTypes.php b/app/Jobs/Payments/EventTypes.php new file mode 100644 index 000000000..63bb4d6e4 --- /dev/null +++ b/app/Jobs/Payments/EventTypes.php @@ -0,0 +1,24 @@ +getRabbitMQMessage()->getRoutingKey(); + Log::debug("PaymentsMQJob::payload processing job", ['routing_key' => $routing_key]); + switch ($routing_key) { + case EventTypes::PAYMENT_PROFILE_CREATED: + $job = 'App\Jobs\Payments\CreatePaymentProfileMQJob@handle'; + break; + case EventTypes::PAYMENT_PROFILE_UPDATED: + $job = 'App\Jobs\Payments\UpdatePaymentProfileMQJob@handle'; + break; + case EventTypes::PAYMENT_PROFILE_DELETED: + $job = 'App\Jobs\Payments\DeletePaymentProfileMQJob@handle'; + break; + default: + Log::warning('Received an unknown routing key', ['routing_key' => $routing_key, 'message' => $this->getRawBody()]); + return []; + } + return [ + 'job' => $job, + 'data' => json_decode($this->getRawBody(), true) + ]; + } +} diff --git a/app/Jobs/Payments/UpdatePaymentProfileMQJob.php b/app/Jobs/Payments/UpdatePaymentProfileMQJob.php new file mode 100644 index 000000000..5e4a641fd --- /dev/null +++ b/app/Jobs/Payments/UpdatePaymentProfileMQJob.php @@ -0,0 +1,95 @@ +summit_repository = $summit_repository; + $this->payment_gateway_profile_repository = $payment_gateway_profile_repository; + $this->service = $service; + $this->payments_api = $payments_api; + } + + public function handle(PaymentsMQJob $job): void{ + try { + $payload = $job->payload(); + $json = json_encode($payload); + Log::debug("UpdatePaymentProfileMQJob::handle", ['payload' => $json ]); + + $data = $payload['data']; + $id = intval($data['id']); + $summit_id = intval($data['summit_id']); + $application_type = $data['application_type']; + + if(!in_array($application_type, IPaymentConstants::ValidApplicationTypes)){ + Log::warning("UpdatePaymentProfileMQJob::handle Application Type $application_type is not valid."); + return; + } + $response = $this->payments_api->getPaymentProfile($summit_id, $id); + Log::debug("UpdatePaymentProfileMQJob::handle", ['response' => $response]); + $summit = $this->summit_repository->getById($summit_id); + $local_payment_profile =$this->payment_gateway_profile_repository->getByExternalId($id); + if($summit instanceof Summit && $local_payment_profile instanceof PaymentGatewayProfile) { + $local_payment_profile_id = $local_payment_profile->getId(); + // mappings + $response['external_id'] = $id; + $response['active'] = $response['is_active'] ?? false; + Log::debug("UpdatePaymentProfileMQJob::handle updating local profile", ['local_payment_profile_id' => $local_payment_profile_id]); + $this->service->updatePaymentProfile($summit, $local_payment_profile_id, $response); + } + $job->delete(); + } catch (\Exception $ex) { + Log::error($ex); + throw $ex; + } + } +} diff --git a/app/Models/Foundation/Summit/Factories/PaymentGatewayProfileFactory.php b/app/Models/Foundation/Summit/Factories/PaymentGatewayProfileFactory.php index 4f28cb2e9..d733545ba 100644 --- a/app/Models/Foundation/Summit/Factories/PaymentGatewayProfileFactory.php +++ b/app/Models/Foundation/Summit/Factories/PaymentGatewayProfileFactory.php @@ -12,6 +12,7 @@ * limitations under the License. **/ +use Illuminate\Support\Facades\Log; use models\exceptions\ValidationException; /** * Class PaymentGatewayProfileFactory @@ -27,6 +28,7 @@ final class PaymentGatewayProfileFactory */ public static function build(string $provider, array $params): ?PaymentGatewayProfile { + Log::debug("PaymentGatewayProfileFactory::build()", ['provider' => $provider, 'params' => $params]); $profile = null; if ($provider == IPaymentConstants::ProviderStripe) { $profile = static::populate(new StripePaymentProfile, $params); @@ -58,6 +60,14 @@ public static function populate(PaymentGatewayProfile $profile, array $params): $profile->setSummit($params['summit']); } + // common properties + if (isset($params['application_type'])) + $profile->setApplicationType($params['application_type']); + + if(isset($params['external_id'])){ + $profile->setExternalId(trim($params['external_id'])); + } + $profile->setTestKeys([ 'publishable_key' => $test_publishable_key, 'secret_key' => $test_secret_key @@ -98,10 +108,6 @@ public static function populate(PaymentGatewayProfile $profile, array $params): } } - // common properties - if (isset($params['application_type'])) - $profile->setApplicationType($params['application_type']); - if (isset($params['active'])) { if(boolval($params['active']) == true) $profile->activate(); @@ -111,4 +117,4 @@ public static function populate(PaymentGatewayProfile $profile, array $params): return $profile; } -} \ No newline at end of file +} diff --git a/app/Models/Foundation/Summit/Registration/Payment/PaymentGatewayProfile.php b/app/Models/Foundation/Summit/Registration/Payment/PaymentGatewayProfile.php index 6b23bfe98..a1fad4307 100644 --- a/app/Models/Foundation/Summit/Registration/Payment/PaymentGatewayProfile.php +++ b/app/Models/Foundation/Summit/Registration/Payment/PaymentGatewayProfile.php @@ -12,7 +12,6 @@ * limitations under the License. **/ use App\Services\Apis\IPaymentGatewayAPI; -use App\Services\Apis\PaymentGateways\StripeApi; use Illuminate\Support\Facades\Log; use models\exceptions\ValidationException; use models\utils\SilverstripeBaseModel; @@ -37,6 +36,12 @@ abstract class PaymentGatewayProfile extends SilverstripeBaseModel #[ORM\Column(name: 'IsActive', type: 'boolean')] protected $active; + /** + * @var string + */ + #[ORM\Column(name: 'ExternalId', type: 'string')] + protected $external_id; + /** * @var string */ @@ -324,4 +329,12 @@ public function setTestMode(): void abstract public function buildWebHook(): void; abstract protected function clearWebHooks():void; -} \ No newline at end of file + + public function setExternalId(string $external_id): void{ + $this->external_id = $external_id; + } + + public function getExternalId(): ?string{ + return $this->external_id; + } +} diff --git a/app/Models/Foundation/Summit/Registration/Payment/StripePaymentProfile.php b/app/Models/Foundation/Summit/Registration/Payment/StripePaymentProfile.php index 932b7d25b..b87bfc99a 100644 --- a/app/Models/Foundation/Summit/Registration/Payment/StripePaymentProfile.php +++ b/app/Models/Foundation/Summit/Registration/Payment/StripePaymentProfile.php @@ -221,10 +221,12 @@ public function buildWebHook(): void try { if (!$this->existsWebHook() && $this->hasSecretKey() && $this->hasSummit()) { $api = new StripeApi($this->createConfiguration()); + $application_type = $this->getApplicationType(); + Log::debug("StripePaymentProfile::buildWebHook", ['id' => $this->getId(), 'application_type' => $application_type]); // create it $info = $api->createWebHook(action('PaymentGatewayWebHookController@confirm', [ 'id' => $this->summit->getId(), - 'application_name' => $this->getApplicationType() + 'application_name' => $application_type ])); // and set web hook info $this->setWebHookInfo($info); @@ -312,4 +314,4 @@ public function setSendEmailReceipt(bool $send_email_receipt): void $this->send_email_receipt = $send_email_receipt; } -} \ No newline at end of file +} diff --git a/app/Models/Foundation/Summit/Repositories/IPaymentGatewayProfileRepository.php b/app/Models/Foundation/Summit/Repositories/IPaymentGatewayProfileRepository.php index 044a2afe3..59b6e94c2 100644 --- a/app/Models/Foundation/Summit/Repositories/IPaymentGatewayProfileRepository.php +++ b/app/Models/Foundation/Summit/Repositories/IPaymentGatewayProfileRepository.php @@ -11,6 +11,8 @@ * See the License for the specific language governing permissions and * limitations under the License. **/ + +use models\summit\PaymentGatewayProfile; use models\utils\IBaseRepository; /** * Interface IPaymentGatewayProfileRepository @@ -18,5 +20,9 @@ */ interface IPaymentGatewayProfileRepository extends IBaseRepository { - -} \ No newline at end of file + /** + * @param $external_id + * @return PaymentGatewayProfile|null + */ + public function getByExternalId($external_id):?PaymentGatewayProfile; +} diff --git a/app/Repositories/Summit/DoctrinePaymentGatewayProfileRepository.php b/app/Repositories/Summit/DoctrinePaymentGatewayProfileRepository.php index a08d7a121..699867508 100644 --- a/app/Repositories/Summit/DoctrinePaymentGatewayProfileRepository.php +++ b/app/Repositories/Summit/DoctrinePaymentGatewayProfileRepository.php @@ -54,4 +54,15 @@ protected function getOrderMappings() 'application_type' => 'e.application_type', ]; } -} \ No newline at end of file + + /** + * @param $external_id + * @return PaymentGatewayProfile|null + */ + public function getByExternalId($external_id): ?PaymentGatewayProfile + { + return $this->findOneBy([ + 'external_id' => $external_id + ]); + } +} diff --git a/app/Services/Apis/IPaymentsApi.php b/app/Services/Apis/IPaymentsApi.php new file mode 100644 index 000000000..c0167914f --- /dev/null +++ b/app/Services/Apis/IPaymentsApi.php @@ -0,0 +1,23 @@ +push(GuzzleRetryMiddleware::factory()); + + $this->client = new Client([ + 'handler' => $stack, + 'base_uri' => Config::get('payments_api.base_url') ?? '', + 'timeout' => Config::get('curl.timeout', 60), + 'allow_redirects' => Config::get('curl.allow_redirects', false), + 'verify' => Config::get('curl.verify_ssl_cert', true), + ]); + } + + const AppName = 'PAYMENTS_SERVICE'; + + /** + * @return string + */ + public function getAppName(): string + { + return self::AppName; + } + + /** + * @return array + */ + public function getAppConfig(): array + { + return [ + 'client_id' => Config::get("payments_api.service_client_id"), + 'client_secret' => Config::get("payments_api.service_client_secret"), + 'scopes' => Config::get("payments_api.service_client_scopes") + ]; + } + + + /** + * @param int $summit_id + * @param int $id + * @return mixed|null + * @throws \Exception + */ + public function getPaymentProfile(int $summit_id, int $id) + { + Log::debug("PaymentsApi::getPaymentProfile", ['summit_id' => $summit_id, 'id' => $id]); + + return $this->invokeWithRetry(function () use ($summit_id, $id) { + $query = [ + 'access_token' => $this->getAccessToken(), + ]; + + $response = $this->client->get(sprintf('/api/v1/summits/%s/payment-profiles/%s', $summit_id, $id), + [ + 'headers' => [ + 'Accept' => 'application/json', + 'Cache-Control' => 'no-cache, no-store, max-age=0, must-revalidate', + 'Pragma' => 'no-cache', + ], + 'query' => $query, + ] + ); + + return json_decode($response->getBody()->getContents(), true); + + }); + } + +} diff --git a/app/Services/BaseServicesProvider.php b/app/Services/BaseServicesProvider.php index 6eafa4211..79c7d93be 100644 --- a/app/Services/BaseServicesProvider.php +++ b/app/Services/BaseServicesProvider.php @@ -20,10 +20,11 @@ use App\Services\Apis\IMailApi; use App\Services\Apis\IMUXApi; use App\Services\Apis\IPasswordlessAPI; +use App\Services\Apis\IPaymentsApi; use App\Services\Apis\MailApi; use App\Services\Apis\MUXApi; -use App\Services\Apis\MuxCredentials; use App\Services\Apis\PasswordlessAPI; +use App\Services\Apis\PaymentsApi; use App\Services\Apis\Samsung\ISamsungRegistrationAPI; use App\Services\Apis\Samsung\SamsungRegistrationAPI; use App\Services\Model\FolderService; @@ -123,6 +124,11 @@ public function register() ExternalUserApi::class ); + App::singleton( + IPaymentsApi::class, + PaymentsApi::class + ); + App::singleton ( IFolderService::class, @@ -194,4 +200,4 @@ public function provides() IMarketingAPI::class ]; } -} \ No newline at end of file +} diff --git a/app/Services/Model/Imp/PaymentGatewayProfileService.php b/app/Services/Model/Imp/PaymentGatewayProfileService.php index d650cd4d7..b8d813094 100644 --- a/app/Services/Model/Imp/PaymentGatewayProfileService.php +++ b/app/Services/Model/Imp/PaymentGatewayProfileService.php @@ -12,14 +12,15 @@ * limitations under the License. **/ -use Illuminate\Support\Facades\Log; -use models\summit\PaymentGatewayProfileFactory; use App\Services\Model\AbstractService; use App\Services\Model\IPaymentGatewayProfileService; +use Illuminate\Support\Facades\Log; use models\exceptions\EntityNotFoundException; use models\exceptions\ValidationException; use models\summit\PaymentGatewayProfile; +use models\summit\PaymentGatewayProfileFactory; use models\summit\Summit; + /** * Class PaymentGatewayProfileService * @package App\Services\Model\Imp @@ -34,19 +35,20 @@ final class PaymentGatewayProfileService */ public function addPaymentProfile(Summit $summit, array $payload): ?PaymentGatewayProfile { - return $this->tx_service->transaction(function() use($summit, $payload){ + return $this->tx_service->transaction(function () use ($summit, $payload) { + Log::debug("PaymentGatewayProfileService::addPaymentProfilee", ["summit" => $summit->getId(), 'payload' => $payload]); $payload['summit'] = $summit; $profile = PaymentGatewayProfileFactory::build($payload['provider'], $payload); $formerProfile = $summit->getPaymentGateWayProfilePerApp($profile->getApplicationType()); - if($profile->isActive() && !is_null($formerProfile) && $formerProfile->isActive()){ + if ($profile->isActive() && !is_null($formerProfile) && $formerProfile->isActive()) { throw new ValidationException ( sprintf("There is already an active Payment Profile for application type %s,", $formerProfile->getApplicationType()) ); } $summit->addPaymentProfile($profile); - if(isset($payload['active']) && boolval($payload['active']) == true){ - // force activation ( rebuild web hook) + if (isset($payload['active']) && boolval($payload['active']) == true) { + // force activation ( rebuild web hook ) $profile->activate(); } return $profile; @@ -58,9 +60,11 @@ public function addPaymentProfile(Summit $summit, array $payload): ?PaymentGatew */ public function deletePaymentProfile(Summit $summit, int $child_id): void { - $this->tx_service->transaction(function() use($summit, $child_id){ + $this->tx_service->transaction(function () use ($summit, $child_id) { + Log::debug("PaymentGatewayProfileService::deletePaymentProfile", ["summit" => $summit->getId(), "profile_id" => $child_id]); + $profile = $summit->getPaymentProfileById($child_id); - if(is_null($profile)) + if (is_null($profile)) throw new EntityNotFoundException(); $summit->removePaymentProfile($profile); }); @@ -71,28 +75,17 @@ public function deletePaymentProfile(Summit $summit, int $child_id): void */ public function updatePaymentProfile(Summit $summit, int $child_id, array $payload): ?PaymentGatewayProfile { - return $this->tx_service->transaction(function() use($summit, $child_id, $payload){ - - Log::debug - ( - sprintf - ( - "PaymentGatewayProfileService::updatePaymentProfile summit %s profile %s payload %s", - $summit->getId(), - $child_id, - json_encode($payload) - ) - ); - + return $this->tx_service->transaction(function () use ($summit, $child_id, $payload) { + Log::debug("PaymentGatewayProfileService::updatePaymentProfile", ["summit" => $summit->getId(), "profile_id" => $child_id, "payload" => $payload]); $profile = $summit->getPaymentProfileById($child_id); - if(is_null($profile)) + if (is_null($profile)) throw new EntityNotFoundException(); $formerProfile = $summit->getPaymentGateWayProfilePerApp($profile->getApplicationType()); // if we are activating this profile, check if there is not already one activated - if(isset($payload['active']) && boolval($payload['active']) == true && + if (isset($payload['active']) && boolval($payload['active']) == true && !is_null($formerProfile) && $formerProfile->getId() != $profile->getId() - && $formerProfile->isActive()){ + && $formerProfile->isActive()) { throw new ValidationException ( sprintf("There is already an active Payment Profile for application type %s.", $formerProfile->getApplicationType()) @@ -102,4 +95,4 @@ public function updatePaymentProfile(Summit $summit, int $child_id, array $paylo return PaymentGatewayProfileFactory::populate($profile, $payload); }); } -} \ No newline at end of file +} diff --git a/config/payments_api.php b/config/payments_api.php new file mode 100644 index 000000000..3ef9fb1ed --- /dev/null +++ b/config/payments_api.php @@ -0,0 +1,8 @@ + env('PAYMENTS_SERVICE_BASE_URL', null), + 'service_client_id' => env('PAYMENTS_SERVICE_OAUTH2_CLIENT_ID', null), + 'service_client_secret' => env('PAYMENTS_SERVICE_OAUTH2_CLIENT_SECRET', null), + 'service_client_scopes' => env('PAYMENTS_SERVICE_OAUTH2_SCOPES', null), +]; diff --git a/config/queue.php b/config/queue.php index a987534ac..38d8546bb 100644 --- a/config/queue.php +++ b/config/queue.php @@ -118,6 +118,36 @@ ], ], ], + 'payments_sync_consumer' => [ + 'driver' => 'rabbitmq', + 'queue' => env('PAYMENTS_QUEUE', 'payments'), + 'connection' => $rabbit_connection, + 'hosts' => [ + [ + 'host' => env('RABBITMQ_HOST', '127.0.0.1'), + 'port' => $rabbit_port, + 'user' => env('RABBITMQ_LOGIN', 'guest'), + 'password' => env('RABBITMQ_PASSWORD', 'guest'), + 'vhost' => env('RABBITMQ_VHOST', '/'), + ], + ], + 'options' => [ + 'ssl_options' => [ + // @see https://www.php.net/manual/en/context.ssl.php + 'cafile' => env('RABBITMQ_SSL_CAFILE', null), + 'local_cert' => env('RABBITMQ_SSL_LOCALCERT', null), + 'local_pk' => env('RABBITMQ_SSL_LOCALKEY', null), + 'verify_peer' => env('RABBITMQ_SSL_VERIFY_PEER', true), + 'passphrase' => env('RABBITMQ_SSL_PASSPHRASE', null), + ], + 'queue' => [ + 'passive' => env('RABBITMQ_QUEUE_PASSIVE', false), + 'durable' => env('RABBITMQ_QUEUE_DURABLE', true), + 'exclusive' => env('RABBITMQ_QUEUE_EXCLUSIVE', false), + 'job' => \App\Jobs\Payments\PaymentsMQJob::class, + ], + ], + ], 'domain_events_message_broker' => [ 'driver' => 'rabbitmq', diff --git a/database/migrations/model/Version20251106013928.php b/database/migrations/model/Version20251106013928.php new file mode 100644 index 000000000..57708141a --- /dev/null +++ b/database/migrations/model/Version20251106013928.php @@ -0,0 +1,53 @@ +hasTable("PaymentGatewayProfile") && !$builder->hasColumn("PaymentGatewayProfile", "ExternalId")) { + $builder->table("PaymentGatewayProfile", function (Table $table) { + $table->string("ExternalId", )->setNotnull(false)->setDefault('NULL'); + $table->unique(["ExternalId"], "PaymentGatewayProfile_ExternalId_Unique"); + }); + } + } + + public function down(Schema $schema): void + { + $builder = new Builder($schema); + if($schema->hasTable("PaymentGatewayProfile") && $builder->hasColumn("PaymentGatewayProfile", "ExternalId")) { + $builder->table("PaymentGatewayProfile", function (Table $table) { + $table->dropColumn('ExternalId'); + }); + } + } +} diff --git a/database/migrations/model/Version20251119201347.php b/database/migrations/model/Version20251119201347.php new file mode 100644 index 000000000..89298fe2f --- /dev/null +++ b/database/migrations/model/Version20251119201347.php @@ -0,0 +1,36 @@ +addSql($sql); + + } + + public function down(Schema $schema): void + { + // this down() migration is auto-generated, please modify it to your needs + + } +} diff --git a/readme.md b/readme.md index b31bc3a36..32422a535 100644 --- a/readme.md +++ b/readme.md @@ -25,10 +25,10 @@ run following commands on root folder * php artisan route:cache * give proper rights to storage folder (775 and proper users) * chmod 777 vendor/ezyang/htmlpurifier/library/HTMLPurifier/DefinitionCache/Serializer - + ## Permissions -Laravel may require some permissions to be configured: folders within storage and vendor require write access by the web server. +Laravel may require some permissions to be configured: folders within storage and vendor require write access by the web server. ## create SS schema @@ -60,16 +60,22 @@ php artisan doctrine:migrations:generate --connection=model --create=