From ae550997a5eb382384af146fdc0ab2eafbd496fa Mon Sep 17 00:00:00 2001 From: Pedro Crespo-Valero <32402063+pcrespov@users.noreply.github.com> Date: Tue, 21 Nov 2023 10:20:20 +0100 Subject: [PATCH 1/7] gateway example --- services/payments/{scripts => gateway}/Makefile | 6 +++--- .../example_payment_gateway.py} | 0 .../simcore_service_payments/services/payments_gateway.py | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) rename services/payments/{scripts => gateway}/Makefile (62%) rename services/payments/{scripts/fake_payment_gateway.py => gateway/example_payment_gateway.py} (100%) diff --git a/services/payments/scripts/Makefile b/services/payments/gateway/Makefile similarity index 62% rename from services/payments/scripts/Makefile rename to services/payments/gateway/Makefile index 166c0763f9d..1a1a00087f1 100644 --- a/services/payments/scripts/Makefile +++ b/services/payments/gateway/Makefile @@ -3,12 +3,12 @@ include ../../../scripts/common.Makefile .PHONY: run-devel -run-devel: ## runs fake_payment_gateway server +run-devel: ## runs example_payment_gateway server # SEE http://127.0.0.1:8000/docs set -o allexport; source .env-secret; set +o allexport; \ - uvicorn fake_payment_gateway:the_app --reload + uvicorn example_payment_gateway:the_app --reload openapi.json: ## creates OAS @set -o allexport; source .env-secret; set +o allexport; \ - python fake_payment_gateway.py openapi > $@ + python example_payment_gateway.py openapi > $@ diff --git a/services/payments/scripts/fake_payment_gateway.py b/services/payments/gateway/example_payment_gateway.py similarity index 100% rename from services/payments/scripts/fake_payment_gateway.py rename to services/payments/gateway/example_payment_gateway.py diff --git a/services/payments/src/simcore_service_payments/services/payments_gateway.py b/services/payments/src/simcore_service_payments/services/payments_gateway.py index 7dd2b47de76..41d0e8d7bd6 100644 --- a/services/payments/src/simcore_service_payments/services/payments_gateway.py +++ b/services/payments/src/simcore_service_payments/services/payments_gateway.py @@ -1,7 +1,7 @@ """ Interface to communicate with the payment's gateway - httpx client with base_url to PAYMENTS_GATEWAY_URL -- Fake gateway service in services/payments/scripts/fake_payment_gateway.py +- Fake gateway service in services/payments/scripts/example_payment_gateway.py """ From ddfa3cebcf7fe4c718be97e6571a65c8d7c0c2da Mon Sep 17 00:00:00 2001 From: Pedro Crespo-Valero <32402063+pcrespov@users.noreply.github.com> Date: Tue, 21 Nov 2023 10:30:32 +0100 Subject: [PATCH 2/7] adds openapi for gateway --- .gitignore | 1 - services/payments/README.md | 12 +- services/payments/gateway/openapi.json | 751 +++++++++++++++++++++++++ 3 files changed, 760 insertions(+), 4 deletions(-) create mode 100644 services/payments/gateway/openapi.json diff --git a/.gitignore b/.gitignore index 9836532c4c9..ec92564a31c 100644 --- a/.gitignore +++ b/.gitignore @@ -178,6 +178,5 @@ Untitled* # service settings.schemas.json services/**/settings-schema.json -services/payments/scripts/openapi.json tests/public-api/osparc_python_wheels/* diff --git a/services/payments/README.md b/services/payments/README.md index 0bedf5869ee..0dec186398d 100644 --- a/services/payments/README.md +++ b/services/payments/README.md @@ -1,5 +1,11 @@ -# payments +# payments service - ![[doc/payments.drawio.svg]] +Payment service acts as intermediary between osparc and a `payments-gateway` connected to an external payment system (e.g. stripe, ...). Therefore the +`payments-gateway` acts as a common interface with the finaly payment system to make osparc independent of that decision. The communication +is implemented using http in two directions. This service communicates with a `payments-gateway` service using an API with this specifications [gateway/openapi.json](gateway/openapi.json) +and the latter is configured to acknoledge back to this service (i.e. web-hook) onto this API with the following specs [openapi.json](openapi.json). - - SEE https://github.com/ITISFoundation/osparc-simcore/issues/4657 +Here is a diagram of how this service interacts with the rest of internal and external services +![[doc/payments.drawio.svg]] + +- Further details on the use case and requirements in https://github.com/ITISFoundation/osparc-simcore/issues/4657 diff --git a/services/payments/gateway/openapi.json b/services/payments/gateway/openapi.json new file mode 100644 index 00000000000..1376a0a11cc --- /dev/null +++ b/services/payments/gateway/openapi.json @@ -0,0 +1,751 @@ +{ + "openapi": "3.1.0", + "info": { + "title": "fake-payment-gateway", + "version": "0.3.0" + }, + "paths": { + "/init": { + "post": { + "tags": [ + "payment" + ], + "summary": "Init Payment", + "operationId": "init_payment", + "parameters": [ + { + "required": false, + "schema": { + "type": "string", + "title": "X-Init-Api-Secret" + }, + "name": "x-init-api-secret", + "in": "header" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/InitPayment" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PaymentInitiated" + } + } + } + }, + "4XX": { + "description": "Client Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorModel" + } + } + } + } + } + } + }, + "/pay": { + "get": { + "tags": [ + "payment" + ], + "summary": "Get Payment Form", + "operationId": "get_payment_form", + "parameters": [ + { + "required": true, + "schema": { + "type": "string", + "maxLength": 50, + "minLength": 1, + "title": "Id" + }, + "name": "id", + "in": "query" + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": { + "text/html": { + "schema": { + "type": "string" + } + } + } + }, + "4XX": { + "description": "Client Error", + "content": { + "text/html": { + "schema": { + "type": "string" + } + } + } + } + } + } + }, + "/cancel": { + "post": { + "tags": [ + "payment" + ], + "summary": "Cancel Payment", + "operationId": "cancel_payment", + "parameters": [ + { + "required": false, + "schema": { + "type": "string", + "title": "X-Init-Api-Secret" + }, + "name": "x-init-api-secret", + "in": "header" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PaymentInitiated" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PaymentCancelled" + } + } + } + }, + "4XX": { + "description": "Client Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorModel" + } + } + } + } + } + } + }, + "/payment-methods:init": { + "post": { + "tags": [ + "payment-method" + ], + "summary": "Init Payment Method", + "operationId": "init_payment_method", + "parameters": [ + { + "required": false, + "schema": { + "type": "string", + "title": "X-Init-Api-Secret" + }, + "name": "x-init-api-secret", + "in": "header" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/InitPaymentMethod" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PaymentMethodInitiated" + } + } + } + }, + "4XX": { + "description": "Client Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorModel" + } + } + } + } + } + } + }, + "/payment-methods/form": { + "get": { + "tags": [ + "payment-method" + ], + "summary": "Get Form Payment Method", + "operationId": "get_form_payment_method", + "parameters": [ + { + "required": true, + "schema": { + "type": "string", + "maxLength": 50, + "minLength": 1, + "title": "Id" + }, + "name": "id", + "in": "query" + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": { + "text/html": { + "schema": { + "type": "string" + } + } + } + }, + "4XX": { + "description": "Client Error", + "content": { + "text/html": { + "schema": { + "type": "string" + } + } + } + } + } + } + }, + "/payment-methods:batchGet": { + "post": { + "tags": [ + "payment-method" + ], + "summary": "Batch Get Payment Methods", + "operationId": "batch_get_payment_methods", + "parameters": [ + { + "required": false, + "schema": { + "type": "string", + "title": "X-Init-Api-Secret" + }, + "name": "x-init-api-secret", + "in": "header" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BatchGetPaymentMethods" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PaymentMethodsBatch" + } + } + } + }, + "4XX": { + "description": "Client Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorModel" + } + } + } + } + } + } + }, + "/payment-methods/{id}": { + "get": { + "tags": [ + "payment-method" + ], + "summary": "Get Payment Method", + "operationId": "get_payment_method", + "parameters": [ + { + "required": true, + "schema": { + "type": "string", + "maxLength": 50, + "minLength": 1, + "title": "Id" + }, + "name": "id", + "in": "path" + }, + { + "required": false, + "schema": { + "type": "string", + "title": "X-Init-Api-Secret" + }, + "name": "x-init-api-secret", + "in": "header" + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GetPaymentMethod" + } + } + } + }, + "4XX": { + "description": "Client Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorModel" + } + } + } + } + } + }, + "delete": { + "tags": [ + "payment-method" + ], + "summary": "Delete Payment Method", + "operationId": "delete_payment_method", + "parameters": [ + { + "required": true, + "schema": { + "type": "string", + "maxLength": 50, + "minLength": 1, + "title": "Id" + }, + "name": "id", + "in": "path" + }, + { + "required": false, + "schema": { + "type": "string", + "title": "X-Init-Api-Secret" + }, + "name": "x-init-api-secret", + "in": "header" + } + ], + "responses": { + "204": { + "description": "Successful Response" + }, + "4XX": { + "description": "Client Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorModel" + } + } + } + } + } + } + }, + "/payment-methods/{id}:pay": { + "post": { + "tags": [ + "payment-method" + ], + "summary": "Pay With Payment Method", + "operationId": "pay_with_payment_method", + "parameters": [ + { + "required": true, + "schema": { + "type": "string", + "maxLength": 50, + "minLength": 1, + "title": "Id" + }, + "name": "id", + "in": "path" + }, + { + "required": false, + "schema": { + "type": "string", + "title": "X-Init-Api-Secret" + }, + "name": "x-init-api-secret", + "in": "header" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/InitPayment" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AckPaymentWithPaymentMethod" + } + } + } + }, + "4XX": { + "description": "Client Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorModel" + } + } + } + } + } + } + } + }, + "components": { + "schemas": { + "AckPaymentWithPaymentMethod": { + "properties": { + "success": { + "type": "boolean", + "title": "Success" + }, + "message": { + "type": "string", + "title": "Message" + }, + "provider_payment_id": { + "type": "string", + "maxLength": 50, + "minLength": 1, + "title": "Provider Payment Id", + "description": "Payment ID from the provider (e.g. stripe payment ID)" + }, + "invoice_url": { + "type": "string", + "maxLength": 2083, + "minLength": 1, + "format": "uri", + "title": "Invoice Url", + "description": "Link to invoice is required when success=true" + }, + "payment_id": { + "type": "string", + "maxLength": 50, + "minLength": 1, + "title": "Payment Id", + "description": "Payment ID from the gateway" + } + }, + "type": "object", + "required": [ + "success" + ], + "title": "AckPaymentWithPaymentMethod", + "example": { + "success": true, + "provider_payment_id": "pi_123ABC", + "invoice_url": "https://invoices.com/id=12345", + "payment_id": "D19EE68B-B007-4B61-A8BC-32B7115FB244" + } + }, + "BatchGetPaymentMethods": { + "properties": { + "payment_methods_ids": { + "items": { + "type": "string", + "maxLength": 50, + "minLength": 1 + }, + "type": "array", + "title": "Payment Methods Ids" + } + }, + "type": "object", + "required": [ + "payment_methods_ids" + ], + "title": "BatchGetPaymentMethods" + }, + "ErrorModel": { + "properties": { + "message": { + "type": "string", + "title": "Message" + }, + "exception": { + "type": "string", + "title": "Exception" + }, + "file": { + "anyOf": [ + { + "type": "string", + "format": "path" + }, + { + "type": "string" + } + ], + "title": "File" + }, + "line": { + "type": "integer", + "title": "Line" + }, + "trace": { + "items": {}, + "type": "array", + "title": "Trace" + } + }, + "type": "object", + "required": [ + "message" + ], + "title": "ErrorModel" + }, + "GetPaymentMethod": { + "properties": { + "id": { + "type": "string", + "maxLength": 50, + "minLength": 1, + "title": "Id" + }, + "card_holder_name": { + "type": "string", + "title": "Card Holder Name" + }, + "card_number_masked": { + "type": "string", + "title": "Card Number Masked" + }, + "card_type": { + "type": "string", + "title": "Card Type" + }, + "expiration_month": { + "type": "integer", + "title": "Expiration Month" + }, + "expiration_year": { + "type": "integer", + "title": "Expiration Year" + }, + "created": { + "type": "string", + "format": "date-time", + "title": "Created" + } + }, + "type": "object", + "required": [ + "id", + "created" + ], + "title": "GetPaymentMethod" + }, + "InitPayment": { + "properties": { + "amount_dollars": { + "type": "number", + "exclusiveMaximum": true, + "exclusiveMinimum": true, + "title": "Amount Dollars", + "maximum": 1000000.0, + "minimum": 0.0 + }, + "credits": { + "type": "number", + "exclusiveMaximum": true, + "exclusiveMinimum": true, + "title": "Credits", + "maximum": 1000000.0, + "minimum": 0.0 + }, + "user_name": { + "type": "string", + "maxLength": 50, + "minLength": 1, + "title": "User Name" + }, + "user_email": { + "type": "string", + "format": "email", + "title": "User Email" + }, + "wallet_name": { + "type": "string", + "maxLength": 50, + "minLength": 1, + "title": "Wallet Name" + } + }, + "additionalProperties": false, + "type": "object", + "required": [ + "amount_dollars", + "credits", + "user_name", + "user_email", + "wallet_name" + ], + "title": "InitPayment" + }, + "InitPaymentMethod": { + "properties": { + "method": { + "type": "string", + "enum": [ + "CC" + ], + "title": "Method", + "default": "CC" + }, + "user_name": { + "type": "string", + "maxLength": 50, + "minLength": 1, + "title": "User Name" + }, + "user_email": { + "type": "string", + "format": "email", + "title": "User Email" + }, + "wallet_name": { + "type": "string", + "maxLength": 50, + "minLength": 1, + "title": "Wallet Name" + } + }, + "additionalProperties": false, + "type": "object", + "required": [ + "user_name", + "user_email", + "wallet_name" + ], + "title": "InitPaymentMethod" + }, + "PaymentCancelled": { + "properties": { + "message": { + "type": "string", + "title": "Message" + } + }, + "type": "object", + "title": "PaymentCancelled" + }, + "PaymentInitiated": { + "properties": { + "payment_id": { + "type": "string", + "maxLength": 50, + "minLength": 1, + "title": "Payment Id" + } + }, + "type": "object", + "required": [ + "payment_id" + ], + "title": "PaymentInitiated" + }, + "PaymentMethodInitiated": { + "properties": { + "payment_method_id": { + "type": "string", + "maxLength": 50, + "minLength": 1, + "title": "Payment Method Id" + } + }, + "type": "object", + "required": [ + "payment_method_id" + ], + "title": "PaymentMethodInitiated" + }, + "PaymentMethodsBatch": { + "properties": { + "items": { + "items": { + "$ref": "#/components/schemas/GetPaymentMethod" + }, + "type": "array", + "title": "Items" + } + }, + "type": "object", + "required": [ + "items" + ], + "title": "PaymentMethodsBatch" + } + } + } +} From c38efb83e3f136da2324df03aff3fcde2fd02f1f Mon Sep 17 00:00:00 2001 From: Pedro Crespo-Valero <32402063+pcrespov@users.noreply.github.com> Date: Tue, 21 Nov 2023 10:56:14 +0100 Subject: [PATCH 3/7] updates oas for gateway --- services/payments/gateway/Makefile | 2 +- .../payments/gateway/example_payment_gateway.py | 11 +++++++++-- services/payments/gateway/openapi.json | 14 ++++++++++++-- 3 files changed, 22 insertions(+), 5 deletions(-) diff --git a/services/payments/gateway/Makefile b/services/payments/gateway/Makefile index 1a1a00087f1..87709160533 100644 --- a/services/payments/gateway/Makefile +++ b/services/payments/gateway/Makefile @@ -8,7 +8,7 @@ run-devel: ## runs example_payment_gateway server set -o allexport; source .env-secret; set +o allexport; \ uvicorn example_payment_gateway:the_app --reload - +.PHONY: openapi.json openapi.json: ## creates OAS @set -o allexport; source .env-secret; set +o allexport; \ python example_payment_gateway.py openapi > $@ diff --git a/services/payments/gateway/example_payment_gateway.py b/services/payments/gateway/example_payment_gateway.py index 0df5e7b76f2..c20f428964c 100644 --- a/services/payments/gateway/example_payment_gateway.py +++ b/services/payments/gateway/example_payment_gateway.py @@ -295,7 +295,13 @@ def batch_get_payment_methods( @router.get( "/{id}", response_model=GetPaymentMethod, - responses=ERROR_RESPONSES, + responses={ + "404": { + "model": ErrorModel, + "description": "Payment method not found: It was not added or incomplete (i.e. create flow failed or canceled)", + }, + **ERROR_RESPONSES, + }, ) def get_payment_method( id: PaymentMethodID, @@ -346,11 +352,12 @@ async def _app_lifespan(app: FastAPI): def create_app(): app = FastAPI( - title="fake-payment-gateway", + title="osparc-compliant payment-gateway", version="0.3.0", lifespan=_app_lifespan, debug=True, ) + app.openapi_version = "3.0.0" # NOTE: small hack to allow current version of `42Crunch.vscode-openapi` to work with openapi override_fastapi_openapi_method(app) app.state.payments = {} diff --git a/services/payments/gateway/openapi.json b/services/payments/gateway/openapi.json index 1376a0a11cc..ecc63c61c0f 100644 --- a/services/payments/gateway/openapi.json +++ b/services/payments/gateway/openapi.json @@ -1,7 +1,7 @@ { - "openapi": "3.1.0", + "openapi": "3.0.0", "info": { - "title": "fake-payment-gateway", + "title": "osparc-compliant payment-gateway", "version": "0.3.0" }, "paths": { @@ -341,6 +341,16 @@ } } }, + "404": { + "description": "Payment method not found: It was not added or incomplete (i.e. create flow failed or canceled)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorModel" + } + } + } + }, "4XX": { "description": "Client Error", "content": { From 58dbd9ddeffbd15bd1163b1ee4a5e9e649c9cf16 Mon Sep 17 00:00:00 2001 From: Pedro Crespo-Valero <32402063+pcrespov@users.noreply.github.com> Date: Tue, 21 Nov 2023 11:04:06 +0100 Subject: [PATCH 4/7] adds doc --- services/payments/gateway/example_payment_gateway.py | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/services/payments/gateway/example_payment_gateway.py b/services/payments/gateway/example_payment_gateway.py index c20f428964c..cec6a7e5eb9 100644 --- a/services/payments/gateway/example_payment_gateway.py +++ b/services/payments/gateway/example_payment_gateway.py @@ -1,3 +1,9 @@ +""" This is a simply example of a payments-gateway service + + - Mainly used to create the openapi specs (SEE `openapi.json`) that the payments service expects with + - Also used as a fake payment-gateway for manual exploratory testing +""" + import argparse import json import logging @@ -48,6 +54,10 @@ logging.basicConfig(level=logging.INFO) +# NOTE: please change every time there is a change in the specs +PAYMENTS_GATEWAY_SPECS_VERSION = "0.3.0" + + class Settings(BaseCustomSettings): PAYMENTS_SERVICE_API_BASE_URL: HttpUrl = "http://replace-with-ack-service.io" PAYMENTS_USERNAME: str = "replace-with_username" @@ -353,7 +363,7 @@ async def _app_lifespan(app: FastAPI): def create_app(): app = FastAPI( title="osparc-compliant payment-gateway", - version="0.3.0", + version=PAYMENTS_GATEWAY_SPECS_VERSION, lifespan=_app_lifespan, debug=True, ) From a0fa83dfd2e5a5be633bafe6d65b8363070a3070 Mon Sep 17 00:00:00 2001 From: Pedro Crespo-Valero <32402063+pcrespov@users.noreply.github.com> Date: Tue, 21 Nov 2023 14:46:06 +0100 Subject: [PATCH 5/7] fixes issue#16 --- .../services/payments_gateway.py | 2 ++ .../tests/unit/test_services_payments_gateway.py | 14 ++++++++++++++ 2 files changed, 16 insertions(+) diff --git a/services/payments/src/simcore_service_payments/services/payments_gateway.py b/services/payments/src/simcore_service_payments/services/payments_gateway.py index 41d0e8d7bd6..3004a6709c6 100644 --- a/services/payments/src/simcore_service_payments/services/payments_gateway.py +++ b/services/payments/src/simcore_service_payments/services/payments_gateway.py @@ -162,6 +162,8 @@ def get_form_payment_method_url(self, id_: PaymentMethodID) -> URL: async def get_many_payment_methods( self, ids_: list[PaymentMethodID] ) -> list[GetPaymentMethod]: + if not ids_: + return [] response = await self.client.post( "/payment-methods:batchGet", json=jsonable_encoder(BatchGetPaymentMethods(payment_methods_ids=ids_)), diff --git a/services/payments/tests/unit/test_services_payments_gateway.py b/services/payments/tests/unit/test_services_payments_gateway.py index ce2a858cc52..8d525e15510 100644 --- a/services/payments/tests/unit/test_services_payments_gateway.py +++ b/services/payments/tests/unit/test_services_payments_gateway.py @@ -219,3 +219,17 @@ async def _go(): assert isinstance(err, PaymentsGatewayError) assert "curl -X POST" in err.get_detailed_message() + + +async def test_payments_gateway_get_batch_with_no_items( + app: FastAPI, + mock_payments_gateway_service_or_none: MockRouter | None, +): + payments_gateway_api: PaymentsGatewayApi = PaymentsGatewayApi.get_from_app_state( + app + ) + assert payments_gateway_api + + # tests issue found in https://github.com/ITISFoundation/appmotion-exchange/issues/16 + empty_list = [] + assert not await payments_gateway_api.get_many_payment_methods(empty_list) From d9d02ff78b64bcf99141b5737dea0106811d6b7f Mon Sep 17 00:00:00 2001 From: Pedro Crespo-Valero <32402063+pcrespov@users.noreply.github.com> Date: Tue, 21 Nov 2023 16:19:41 +0100 Subject: [PATCH 6/7] Update services/payments/gateway/example_payment_gateway.py Co-authored-by: Sylvain <35365065+sanderegg@users.noreply.github.com> --- services/payments/gateway/example_payment_gateway.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/payments/gateway/example_payment_gateway.py b/services/payments/gateway/example_payment_gateway.py index cec6a7e5eb9..d13e4ef6026 100644 --- a/services/payments/gateway/example_payment_gateway.py +++ b/services/payments/gateway/example_payment_gateway.py @@ -1,4 +1,4 @@ -""" This is a simply example of a payments-gateway service +""" This is a simple example of a payments-gateway service - Mainly used to create the openapi specs (SEE `openapi.json`) that the payments service expects with - Also used as a fake payment-gateway for manual exploratory testing From effe99f038ca5f2652beb63b8eabd4292aa3acba Mon Sep 17 00:00:00 2001 From: Pedro Crespo-Valero <32402063+pcrespov@users.noreply.github.com> Date: Tue, 21 Nov 2023 16:19:47 +0100 Subject: [PATCH 7/7] Update services/payments/gateway/example_payment_gateway.py Co-authored-by: Sylvain <35365065+sanderegg@users.noreply.github.com> --- services/payments/gateway/example_payment_gateway.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/payments/gateway/example_payment_gateway.py b/services/payments/gateway/example_payment_gateway.py index d13e4ef6026..e43df1d6596 100644 --- a/services/payments/gateway/example_payment_gateway.py +++ b/services/payments/gateway/example_payment_gateway.py @@ -1,6 +1,6 @@ """ This is a simple example of a payments-gateway service - - Mainly used to create the openapi specs (SEE `openapi.json`) that the payments service expects with + - Mainly used to create the openapi specs (SEE `openapi.json`) that the payments service expects - Also used as a fake payment-gateway for manual exploratory testing """