Skip to content

Commit 3394d83

Browse files
Myeclpay logs (#703)
### Description Please explain the changes you made here. ### Checklist - [ ] Created tests which fail without the change (if possible) - [ ] All tests passing - [ ] Extended the documentation, if necessary --------- Co-authored-by: Armand Didierjean <[email protected]>
1 parent 81d96a8 commit 3394d83

File tree

13 files changed

+348
-60
lines changed

13 files changed

+348
-60
lines changed

.env.template

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,11 @@ CDR_PAYMENT_REDIRECTION_URL: str | None
6666
MYECLPAY_MAXIMUM_WALLET_BALANCE: int | None
6767
#MYECLPAY_DATA_VERIFIER_ACCESS_TOKEN = ""
6868

69+
# S3 configuration for file storage
70+
#S3_MYECLPAY_LOGS_BUCKET_NAME = "hyperion"
71+
#S3_ACCESS_KEY_ID = "realaccesskey"
72+
#S3_SECRET_ACCESS_KEY = "realsecretkey"
73+
6974
# Redis configuration #
7075
REDIS_HOST = "hyperion-redis" #May be left at "" during dev if you don't have a redis server running, in production it should be set to the name of the redis container
7176
REDIS_PORT = 6379

app/core/myeclpay/cruds_myeclpay.py

Lines changed: 11 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010
from app.core.myeclpay import models_myeclpay, schemas_myeclpay
1111
from app.core.myeclpay.types_myeclpay import (
1212
TransactionStatus,
13-
TransactionType,
1413
WalletDeviceStatus,
1514
WalletType,
1615
)
@@ -555,31 +554,24 @@ async def get_user_payment(
555554

556555

557556
async def create_transaction(
558-
transaction_id: UUID,
559-
debited_wallet_id: UUID,
557+
transaction: schemas_myeclpay.Transaction,
560558
debited_wallet_device_id: UUID,
561-
credited_wallet_id: UUID,
562-
transaction_type: TransactionType,
563-
seller_user_id: str | None,
564-
total: int,
565-
creation: datetime,
566-
status: TransactionStatus,
567559
store_note: str | None,
568560
db: AsyncSession,
569561
) -> None:
570-
transaction = models_myeclpay.Transaction(
571-
id=transaction_id,
572-
debited_wallet_id=debited_wallet_id,
562+
transaction_db = models_myeclpay.Transaction(
563+
id=transaction.id,
564+
debited_wallet_id=transaction.debited_wallet_id,
573565
debited_wallet_device_id=debited_wallet_device_id,
574-
credited_wallet_id=credited_wallet_id,
575-
transaction_type=transaction_type,
576-
seller_user_id=seller_user_id,
577-
total=total,
578-
creation=creation,
579-
status=status,
566+
credited_wallet_id=transaction.credited_wallet_id,
567+
transaction_type=transaction.transaction_type,
568+
seller_user_id=transaction.seller_user_id,
569+
total=transaction.total,
570+
creation=transaction.creation,
571+
status=transaction.status,
580572
store_note=store_note,
581573
)
582-
db.add(transaction)
574+
db.add(transaction_db)
583575

584576

585577
async def update_transaction_status(

app/core/myeclpay/endpoints_myeclpay.py

Lines changed: 48 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,12 @@
1717
get_user_active_membership_to_association_membership,
1818
)
1919
from app.core.myeclpay import cruds_myeclpay, schemas_myeclpay
20+
from app.core.myeclpay.integrity_myeclpay import (
21+
format_cancel_log,
22+
format_refund_log,
23+
format_transaction_log,
24+
format_transfer_log,
25+
)
2026
from app.core.myeclpay.models_myeclpay import Store, WalletDevice
2127
from app.core.myeclpay.types_myeclpay import (
2228
HistoryType,
@@ -73,6 +79,7 @@
7379

7480
hyperion_error_logger = logging.getLogger("hyperion.error")
7581
hyperion_security_logger = logging.getLogger("hyperion.security")
82+
hyperion_myeclpay_logger = logging.getLogger("hyperion.myeclpay")
7683

7784

7885
@router.get(
@@ -1674,20 +1681,18 @@ async def add_transfer_by_admin(
16741681
status_code=403,
16751682
detail="Wallet balance would exceed the maximum allowed balance",
16761683
)
1677-
1678-
await cruds_myeclpay.create_transfer(
1679-
db=db,
1680-
transfer=schemas_myeclpay.Transfer(
1681-
id=uuid.uuid4(),
1682-
type=transfer_info.transfer_type,
1683-
approver_user_id=user.id,
1684-
total=transfer_info.amount,
1685-
transfer_identifier="", # TODO: require to provide an identifier
1686-
wallet_id=user_payment.wallet_id,
1687-
creation=datetime.now(UTC),
1688-
confirmed=True,
1689-
),
1684+
creation_date = datetime.now(UTC)
1685+
transfer = schemas_myeclpay.Transfer(
1686+
id=uuid.uuid4(),
1687+
type=transfer_info.transfer_type,
1688+
approver_user_id=user.id,
1689+
total=transfer_info.amount,
1690+
transfer_identifier="", # TODO: require to provide an identifier
1691+
wallet_id=user_payment.wallet_id,
1692+
creation=creation_date,
1693+
confirmed=True,
16901694
)
1695+
await cruds_myeclpay.create_transfer(transfer, db)
16911696
await cruds_myeclpay.increment_wallet_balance(
16921697
wallet_id=user_payment.wallet_id,
16931698
amount=transfer_info.amount,
@@ -1698,6 +1703,7 @@ async def add_transfer_by_admin(
16981703
except Exception:
16991704
await db.rollback()
17001705
raise
1706+
hyperion_myeclpay_logger.info(format_transfer_log(transfer))
17011707

17021708
message = Message(
17031709
title="💳 Paiement - transfert",
@@ -2158,24 +2164,28 @@ async def store_scan_qrcode(
21582164
db=db,
21592165
)
21602166
transaction_id = uuid.uuid4()
2161-
# We create a transaction
2162-
await cruds_myeclpay.create_transaction(
2163-
transaction_id=transaction_id,
2167+
creation_date = datetime.now(UTC)
2168+
transaction = schemas_myeclpay.Transaction(
2169+
id=transaction_id,
21642170
debited_wallet_id=debited_wallet_device.wallet_id,
2165-
debited_wallet_device_id=debited_wallet_device.id,
21662171
credited_wallet_id=store.wallet_id,
21672172
transaction_type=TransactionType.DIRECT,
21682173
seller_user_id=user.id,
21692174
total=scan_info.tot,
2170-
creation=datetime.now(UTC),
2175+
creation=creation_date,
21712176
status=TransactionStatus.CONFIRMED,
2177+
)
2178+
# We create a transaction
2179+
await cruds_myeclpay.create_transaction(
2180+
transaction=transaction,
2181+
debited_wallet_device_id=debited_wallet_device.id,
21722182
store_note=None,
21732183
db=db,
21742184
)
21752185

21762186
await db.commit()
21772187

2178-
# TODO: log the transaction
2188+
hyperion_myeclpay_logger.info(format_transaction_log(transaction))
21792189

21802190
message = Message(
21812191
title=f"💳 Paiement - {store.name}",
@@ -2187,16 +2197,7 @@ async def store_scan_qrcode(
21872197
message=message,
21882198
)
21892199

2190-
return schemas_myeclpay.Transaction(
2191-
id=transaction_id,
2192-
debited_wallet_id=debited_wallet_device.wallet_id,
2193-
credited_wallet_id=store.wallet_id,
2194-
transaction_type=TransactionType.DIRECT,
2195-
seller_user_id=user.id,
2196-
total=scan_info.tot,
2197-
creation=datetime.now(UTC),
2198-
status=TransactionStatus.CONFIRMED,
2199-
)
2200+
return transaction
22002201

22012202

22022203
@router.post(
@@ -2325,18 +2326,21 @@ async def refund_transaction(
23252326
db=db,
23262327
)
23272328

2329+
creation_date = datetime.now(UTC)
2330+
refund = schemas_myeclpay.RefundBase(
2331+
id=uuid.uuid4(),
2332+
transaction_id=transaction_id,
2333+
total=refund_amount,
2334+
seller_user_id=user.id
2335+
if wallet_previously_credited.type == WalletType.STORE
2336+
else None,
2337+
credited_wallet_id=wallet_previously_debited.id,
2338+
debited_wallet_id=wallet_previously_credited.id,
2339+
creation=creation_date,
2340+
)
2341+
23282342
await cruds_myeclpay.create_refund(
2329-
refund=schemas_myeclpay.RefundBase(
2330-
id=uuid.uuid4(),
2331-
transaction_id=transaction_id,
2332-
total=refund_amount,
2333-
seller_user_id=user.id
2334-
if wallet_previously_credited.type == WalletType.STORE
2335-
else None,
2336-
credited_wallet_id=wallet_previously_debited.id,
2337-
debited_wallet_id=wallet_previously_credited.id,
2338-
creation=datetime.now(UTC),
2339-
),
2343+
refund=refund,
23402344
db=db,
23412345
)
23422346

@@ -2355,6 +2359,8 @@ async def refund_transaction(
23552359

23562360
await db.commit()
23572361

2362+
hyperion_myeclpay_logger.info(format_refund_log(refund))
2363+
23582364
if wallet_previously_debited.user is not None:
23592365
message = Message(
23602366
title="💳 Remboursement",
@@ -2499,6 +2505,8 @@ async def cancel_transaction(
24992505

25002506
await db.commit()
25012507

2508+
hyperion_myeclpay_logger.info(format_cancel_log(transaction_id))
2509+
25022510
if debited_wallet.user is not None:
25032511
message = Message(
25042512
title="💳 Paiement annulé",
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
#########################################################################################
2+
#########################################################################################
3+
#### /!\ Warning /!\ /!\ Warning /!\ /!\ Warning /!\ /!\ Warning /!\ /!\ Warning /!\ ####
4+
#### ####
5+
#### Following functions are used to format MyECLPay actions for S3 storage. ####
6+
#### Modifying them will break the verification ####
7+
#### of MyECLPay's integrity via S3 validation. ####
8+
#### ####
9+
#### Please do not modify them without understanding the consequences. ####
10+
#### ####
11+
#### /!\ Warning /!\ /!\ Warning /!\ /!\ Warning /!\ /!\ Warning /!\ /!\ Warning /!\ ####
12+
#########################################################################################
13+
#########################################################################################
14+
15+
16+
from uuid import UUID
17+
18+
from app.core.myeclpay import models_myeclpay, schemas_myeclpay
19+
from app.core.myeclpay.types_myeclpay import ActionType
20+
21+
22+
def format_transfer_log(
23+
transfer: schemas_myeclpay.Transfer | models_myeclpay.Transfer,
24+
):
25+
return f"{ActionType.TRANSFER.name} {transfer.id} {transfer.type.name} {transfer.total} {transfer.wallet_id}"
26+
27+
28+
def format_transaction_log(
29+
transaction: schemas_myeclpay.Transaction,
30+
):
31+
return f"{ActionType.TRANSACTION.name} {transaction.id} {transaction.debited_wallet_id} {transaction.credited_wallet_id} {transaction.total}"
32+
33+
34+
def format_refund_log(
35+
refund: schemas_myeclpay.RefundBase,
36+
):
37+
return (
38+
f"{ActionType.REFUND.name} {refund.id} {refund.transaction_id} {refund.total}"
39+
)
40+
41+
42+
def format_cancel_log(
43+
transaction_id: UUID,
44+
):
45+
return f"{ActionType.CANCEL.name} {transaction_id}"

app/core/myeclpay/types_myeclpay.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,13 @@ class TransferType(str, Enum):
5454
BANK_TRANSFER = "bank_transfer"
5555

5656

57+
class ActionType(str, Enum):
58+
TRANSFER = "transfer"
59+
REFUND = "refund"
60+
CANCEL = "cancel"
61+
TRANSACTION = "transaction"
62+
63+
5764
class UnexpectedError(Exception):
5865
pass
5966

app/core/myeclpay/utils_myeclpay.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
from sqlalchemy.ext.asyncio import AsyncSession
88

99
from app.core.myeclpay import cruds_myeclpay
10+
from app.core.myeclpay.integrity_myeclpay import format_transfer_log
1011
from app.core.myeclpay.models_myeclpay import UserPayment
1112
from app.core.myeclpay.schemas_myeclpay import (
1213
QRCodeContentData,
@@ -19,7 +20,7 @@
1920
from app.core.payment import schemas_payment
2021

2122
hyperion_security_logger = logging.getLogger("hyperion.security")
22-
23+
hyperion_myeclpay_logger = logging.getLogger("hyperion.myeclpay")
2324
hyperion_error_logger = logging.getLogger("hyperion.error")
2425

2526
LATEST_TOS = 1
@@ -112,3 +113,4 @@ async def validate_transfer_callback(
112113
except Exception:
113114
await db.rollback()
114115
raise
116+
hyperion_myeclpay_logger.info(format_transfer_log(transfer))

app/core/utils/config.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,15 @@ class Settings(BaseSettings):
8686
REDIS_LIMIT: int
8787
REDIS_WINDOW: int
8888

89+
####################
90+
# S3 configuration #
91+
####################
92+
# S3 configuration is needed to use the S3 storage for MyECLPay logs
93+
94+
S3_MYECLPAY_LOGS_BUCKET_NAME: str | None = None
95+
S3_ACCESS_KEY_ID: str | None = None
96+
S3_SECRET_ACCESS_KEY: str | None = None
97+
8998
##############
9099
# Google API #
91100
##############

app/core/utils/log.py

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ class console_color:
7474

7575
LOG_FORMAT: str = "%(asctime)s - %(name)s - %(levelname)s - %(message)s"
7676
MATRIX_LOG_FORMAT: str = "%(asctime)s - %(name)s - <code>%(levelname)s</code> - <font color ='green'>%(message)s</font>"
77+
MYECLPAY_LOG_FORMAT: str = "%(message)s" # Do not change at any cost
7778

7879
# Logging config
7980
# See https://docs.python.org/3/library/logging.config.html#logging-config-dictschema
@@ -98,6 +99,9 @@ def get_config_dict(self, settings: Settings):
9899
"format": self.MATRIX_LOG_FORMAT,
99100
"datefmt": "%d-%b-%y %H:%M:%S",
100101
},
102+
"myeclpay": {
103+
"format": self.MYECLPAY_LOG_FORMAT,
104+
},
101105
},
102106
"handlers": {
103107
# Console handler is always active, even in production.
@@ -132,6 +136,16 @@ def get_config_dict(self, settings: Settings):
132136
),
133137
"level": "INFO",
134138
},
139+
"myeclpay_s3": {
140+
"formatter": "myeclpay",
141+
"class": "app.utils.loggers_tools.s3_handler.S3LogHandler",
142+
"failure_logger": "hyperion.myeclpay.fallback",
143+
"s3_bucket_name": settings.S3_MYECLPAY_LOGS_BUCKET_NAME,
144+
"s3_access_key_id": settings.S3_ACCESS_KEY_ID,
145+
"s3_secret_access_key": settings.S3_SECRET_ACCESS_KEY,
146+
"folder": "myeclpay/",
147+
"retention": 365 * 10,
148+
},
135149
# There is a handler per log file #
136150
# They are based on RotatingFileHandler to logs in multiple 1024 bytes files
137151
# https://docs.python.org/3/library/logging.handlers.html#logging.handlers.RotatingFileHandler
@@ -163,6 +177,15 @@ def get_config_dict(self, settings: Settings):
163177
"backupCount": 50,
164178
"level": "INFO",
165179
},
180+
"file_myeclpay": {
181+
# file_myeclpay is there to log all operations related to MyECLPay that failed to be logged in the S3 bucket
182+
"formatter": "default",
183+
"class": "logging.handlers.RotatingFileHandler",
184+
"filename": "logs/myeclpay.log",
185+
"maxBytes": 1024 * 1024 * 40, # ~ 40 MB
186+
"backupCount": 100,
187+
"level": "DEBUG",
188+
},
166189
"file_amap": {
167190
# file_amap should receive informations about amap operation, every operation involving a cash modification.
168191
"formatter": "default",
@@ -221,6 +244,21 @@ def get_config_dict(self, settings: Settings):
221244
],
222245
"level": MINIMUM_LOG_LEVEL,
223246
},
247+
"hyperion.myeclpay.fallback": {
248+
"handlers": [
249+
"file_myeclpay",
250+
"matrix_errors",
251+
"console",
252+
],
253+
"level": "DEBUG",
254+
"propagate": False,
255+
},
256+
"hyperion.myeclpay": {
257+
"handlers": [
258+
"myeclpay_s3",
259+
],
260+
"level": "DEBUG",
261+
},
224262
"hyperion.amap": {
225263
"handlers": [
226264
"file_amap",

0 commit comments

Comments
 (0)