Merge branch 'develop' into feature-NEWDWH2021-1158
This commit is contained in:
commit
7898d7e5fc
@ -51,7 +51,13 @@ def update_batch_processing_flag_in_processing() -> None:
|
||||
BatchOperationException: DB操作の何らかのエラー
|
||||
"""
|
||||
db = Database.get_instance()
|
||||
sql = 'UPDATE src05.hdke_tbl SET bch_actf = :in_processing'
|
||||
sql = """\
|
||||
UPDATE src05.hdke_tbl
|
||||
SET
|
||||
bch_actf = :in_processing,
|
||||
updater = CURRENT_USER(),
|
||||
update_date = NOW()
|
||||
"""
|
||||
try:
|
||||
db.connect()
|
||||
db.execute(sql, {'in_processing': constants.BATCH_ACTF_BATCH_IN_PROCESSING})
|
||||
@ -75,7 +81,9 @@ def update_batch_process_complete() -> None:
|
||||
SET
|
||||
bch_actf = :batch_complete,
|
||||
dump_sts_kbn = :dump_unprocessed,
|
||||
syor_date = DATE_FORMAT((src05.get_syor_date() + interval 1 day), '%Y%m%d') -- +1日
|
||||
syor_date = DATE_FORMAT((src05.get_syor_date() + interval 1 day), '%Y%m%d'), -- +1日
|
||||
updater = CURRENT_USER(),
|
||||
update_date = NOW()
|
||||
"""
|
||||
try:
|
||||
db.connect()
|
||||
|
||||
@ -9,12 +9,11 @@ from src.batch.common.batch_context import BatchContext
|
||||
from src.batch.common.calendar_file import CalendarFile
|
||||
from src.batch.dcf_inst_merge import create_dcf_inst_merge
|
||||
from src.batch.laundering import mst_inst_laundering
|
||||
from src.batch.ultmarc import ultmarc_process
|
||||
from src.batch.ultmarc import output_vjsk_inst_pharm_data, ultmarc_process
|
||||
from src.batch.vjsk import vjsk_importer
|
||||
from src.error.exceptions import BatchOperationException
|
||||
from src.logging.get_logger import get_logger
|
||||
from src.system_var import constants
|
||||
from src.batch.ultmarc import output_vjsk_inst_pharm_data
|
||||
|
||||
logger = get_logger('日次処理コントロール')
|
||||
|
||||
@ -46,7 +45,7 @@ def exec():
|
||||
# バッチ共通設定に処理日を追加
|
||||
batch_context.syor_date = syor_date
|
||||
|
||||
# 稼働日かかどうかを、V実消化非稼働日ファイルをダウンロードして判定
|
||||
# 稼働日かどうかを、V実消化非稼働日ファイルをダウンロードして判定
|
||||
try:
|
||||
holiday_list_file_path = ConfigBucket().download_holiday_list()
|
||||
holiday_calendar = CalendarFile(holiday_list_file_path)
|
||||
|
||||
12
ecs/jskult-batch-laundering/.dockerignore
Normal file
12
ecs/jskult-batch-laundering/.dockerignore
Normal file
@ -0,0 +1,12 @@
|
||||
tests/*
|
||||
.coverage
|
||||
.env
|
||||
.env.example
|
||||
.report/*
|
||||
.vscode/*
|
||||
.pytest_cache/*
|
||||
*/__pychache__/*
|
||||
Dockerfile
|
||||
pytest.ini
|
||||
README.md
|
||||
*.sql
|
||||
16
ecs/jskult-batch-laundering/.env.example
Normal file
16
ecs/jskult-batch-laundering/.env.example
Normal file
@ -0,0 +1,16 @@
|
||||
DB_HOST=************
|
||||
DB_PORT=3306
|
||||
DB_USERNAME=************
|
||||
DB_PASSWORD=************
|
||||
DB_SCHEMA=src05
|
||||
|
||||
LOG_LEVEL=INFO
|
||||
DB_CONNECTION_MAX_RETRY_ATTEMPT=************
|
||||
DB_CONNECTION_RETRY_INTERVAL_INIT=************
|
||||
DB_CONNECTION_RETRY_INTERVAL_MIN_SECONDS=************
|
||||
DB_CONNECTION_RETRY_INTERVAL_MAX_SECONDS=************
|
||||
|
||||
# 連携データ抽出期間
|
||||
SALES_LAUNDERING_EXTRACT_DATE_PERIOD=7
|
||||
# 洗替対象テーブル名
|
||||
SALES_LAUNDERING_TARGET_TABLE_NAME=sales_lau_all
|
||||
10
ecs/jskult-batch-laundering/.gitignore
vendored
Normal file
10
ecs/jskult-batch-laundering/.gitignore
vendored
Normal file
@ -0,0 +1,10 @@
|
||||
.vscode/settings.json
|
||||
.env
|
||||
|
||||
# python
|
||||
__pycache__
|
||||
|
||||
# python test
|
||||
.pytest_cache
|
||||
.coverage
|
||||
.report/
|
||||
16
ecs/jskult-batch-laundering/.vscode/launch.json
vendored
Normal file
16
ecs/jskult-batch-laundering/.vscode/launch.json
vendored
Normal file
@ -0,0 +1,16 @@
|
||||
{
|
||||
// IntelliSense を使用して利用可能な属性を学べます。
|
||||
// 既存の属性の説明をホバーして表示します。
|
||||
// 詳細情報は次を確認してください: https://go.microsoft.com/fwlink/?linkid=830387
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"name": "(DEBUG)jskult batch laundering",
|
||||
"type": "python",
|
||||
"request": "launch",
|
||||
"program": "entrypoint.py",
|
||||
"console": "integratedTerminal",
|
||||
"justMyCode": true
|
||||
}
|
||||
]
|
||||
}
|
||||
31
ecs/jskult-batch-laundering/.vscode/recommended_settings.json
vendored
Normal file
31
ecs/jskult-batch-laundering/.vscode/recommended_settings.json
vendored
Normal file
@ -0,0 +1,31 @@
|
||||
{
|
||||
"[python]": {
|
||||
"editor.defaultFormatter": null,
|
||||
"editor.formatOnSave": true,
|
||||
"editor.codeActionsOnSave": {
|
||||
"source.organizeImports": true
|
||||
}
|
||||
},
|
||||
// 自身の環境に合わせて変えてください
|
||||
"python.defaultInterpreterPath": "<pythonインタプリターのパス>",
|
||||
"python.linting.lintOnSave": true,
|
||||
"python.linting.enabled": true,
|
||||
"python.linting.pylintEnabled": false,
|
||||
"python.linting.flake8Enabled": true,
|
||||
"python.linting.flake8Args": [
|
||||
"--max-line-length=200",
|
||||
"--ignore=F541"
|
||||
],
|
||||
"python.formatting.provider": "autopep8",
|
||||
"python.formatting.autopep8Path": "autopep8",
|
||||
"python.formatting.autopep8Args": [
|
||||
"--max-line-length", "200",
|
||||
"--ignore=F541"
|
||||
],
|
||||
"python.testing.pytestArgs": [
|
||||
"tests/batch/ultmarc"
|
||||
],
|
||||
|
||||
"python.testing.unittestEnabled": false,
|
||||
"python.testing.pytestEnabled": true
|
||||
}
|
||||
20
ecs/jskult-batch-laundering/Dockerfile
Normal file
20
ecs/jskult-batch-laundering/Dockerfile
Normal file
@ -0,0 +1,20 @@
|
||||
FROM python:3.9
|
||||
|
||||
ENV TZ="Asia/Tokyo"
|
||||
|
||||
WORKDIR /usr/src/app
|
||||
COPY Pipfile Pipfile.lock ./
|
||||
RUN \
|
||||
apt update -y && \
|
||||
# パッケージのセキュリティアップデートのみを適用するコマンド
|
||||
apt install -y unattended-upgrades && \
|
||||
unattended-upgrades && \
|
||||
pip install --upgrade pip wheel setuptools && \
|
||||
pip install pipenv --no-cache-dir && \
|
||||
pipenv install --system --deploy && \
|
||||
pip uninstall -y pipenv virtualenv-clone virtualenv
|
||||
|
||||
COPY src ./src
|
||||
COPY entrypoint.py entrypoint.py
|
||||
|
||||
CMD ["python", "entrypoint.py"]
|
||||
19
ecs/jskult-batch-laundering/Pipfile
Normal file
19
ecs/jskult-batch-laundering/Pipfile
Normal file
@ -0,0 +1,19 @@
|
||||
[[source]]
|
||||
url = "https://pypi.org/simple"
|
||||
verify_ssl = true
|
||||
name = "pypi"
|
||||
|
||||
[packages]
|
||||
sqlalchemy = "*"
|
||||
tenacity = "*"
|
||||
pymysql = "*"
|
||||
|
||||
[dev-packages]
|
||||
autopep8 = "*"
|
||||
flake8 = "*"
|
||||
|
||||
[requires]
|
||||
python_version = "3.9"
|
||||
|
||||
[pipenv]
|
||||
allow_prereleases = true
|
||||
206
ecs/jskult-batch-laundering/Pipfile.lock
generated
Normal file
206
ecs/jskult-batch-laundering/Pipfile.lock
generated
Normal file
@ -0,0 +1,206 @@
|
||||
{
|
||||
"_meta": {
|
||||
"hash": {
|
||||
"sha256": "e2e2efd7ebd6ad719931983f277105dd94c4ebb6363f7c00e75dd8ca05523713"
|
||||
},
|
||||
"pipfile-spec": 6,
|
||||
"requires": {
|
||||
"python_version": "3.9"
|
||||
},
|
||||
"sources": [
|
||||
{
|
||||
"name": "pypi",
|
||||
"url": "https://pypi.org/simple",
|
||||
"verify_ssl": true
|
||||
}
|
||||
]
|
||||
},
|
||||
"default": {
|
||||
"greenlet": {
|
||||
"hashes": [
|
||||
"sha256:0a9dfcadc1d79696e90ccb1275c30ad4ec5fd3d1ab3ae6671286fac78ef33435",
|
||||
"sha256:0f313771cb8ee0a04dfdf586b7d4076180d80c94be09049daeea018089b5b957",
|
||||
"sha256:17503397bf6cbb5e364217143b6150c540020c51a3f6b08f9a20cd67c25e2ca8",
|
||||
"sha256:180ec55cb127bc745669eddc9793ffab6e0cf7311e67e1592f183d6ca00d88c1",
|
||||
"sha256:1b3f3568478bc21b85968e8038c4f98f4bf0039a692791bc324b5e0d1522f4b1",
|
||||
"sha256:1bd4ea36f0aeb14ca335e0c9594a5aaefa1ac4e2db7d86ba38f0be96166b3102",
|
||||
"sha256:21ebcb570e0d8501457d6a2695a44c5af3b6c2143dc6644ec73574beba067c90",
|
||||
"sha256:24071eee113d75fedebaeb86264d94f04b5a24e311c5ba3e8003c07d00112a7e",
|
||||
"sha256:270432cfdd6a50016b8259b3bbf398a3f7c06a06f2c68c7b93e49f53bc193bcf",
|
||||
"sha256:271ed380389d2f7e4c1545b6e0837986e62504ab561edbaff05da9c9f3f98f96",
|
||||
"sha256:2840187a94e258445e62ff1545e34f0b1a14aef4d0078e5c88246688d2b6515e",
|
||||
"sha256:2cda110faee67613fed221f90467003f477088ef1cc84c8fc88537785a5b4de9",
|
||||
"sha256:2e160a65cc6023a237be870f2072513747d512a1d018efa083acce0b673cccc0",
|
||||
"sha256:2fcf7af83516db35af3d0ed5d182dea8585eddd891977adff1b74212f4bfd2fd",
|
||||
"sha256:36cebce1f30964d5672fd956860e7e7b69772da69658d5743cb676b442eeff36",
|
||||
"sha256:42bfe67824a9b53e73f568f982f0d1d4c7ac0f587d2e702a23f8a7b505d7b7c2",
|
||||
"sha256:450a7e52a515402fd110ba807f1a7d464424bfa703be4effbcb97e1dfbfcc621",
|
||||
"sha256:463d63ca5d8c236788284a9a44b9715372a64d5318a6b5eee36815df1ea0ba3d",
|
||||
"sha256:4d0c0ffd732466ff324ced144fad55ed5deca36f6036c1d8f04cec69b084c9d6",
|
||||
"sha256:4ff2a765f4861fc018827eab4df1992f7508d06c62de5d2fe8a6ac2233d4f1d0",
|
||||
"sha256:53abf19b7dc62795c67b8d0a3d8ef866db166b21017632fff2624cf8fbf3481c",
|
||||
"sha256:5552d7be37d878e9b6359bbffa0512d857bb9703616a4c0656b49c10739d5971",
|
||||
"sha256:585810056a8adacd3152945ebfcd25deb58335d41f16ae4e0f3d768918957f9a",
|
||||
"sha256:5942b1d6ba447cff1ec23a21ec525dde2288f00464950bc647f4e0f03bd537d1",
|
||||
"sha256:5c355c99be5bb23e85d899b059a4f22fdf8a0741c57e7029425ee63eb436f689",
|
||||
"sha256:5f61df4fe07864561f49b45c8bd4d2c42e3f03d2872ed05c844902a58b875028",
|
||||
"sha256:665942d3a954c3e4c976581715f57fb3b86f4cf6bae3ac30b133f8ff777ac6c7",
|
||||
"sha256:68368e908f14887fb202a81960bfbe3a02d97e6d3fa62b821556463084ffb131",
|
||||
"sha256:6aac94ff957b5dea0216af71ab59c602e1b947b394e4f5e878a5a65643090038",
|
||||
"sha256:889934aa8d72b6bfc46babd1dc4b817a56c97ec0f4a10ae7551fb60ab1f96fae",
|
||||
"sha256:a00550757fca1b9cbc479f8eb1cf3514dbc0103b3f76eae46341c26ddcca67a9",
|
||||
"sha256:a4a2d6ed0515c05afd5cc435361ced0baabd9ba4536ddfe8ad9a95bcb702c8ce",
|
||||
"sha256:a8dd92fd76a61af2abc8ccad0c6c6069b3c4ebd4727ecc9a7c33aae37651c8c7",
|
||||
"sha256:ab81f9ff3e3c2ca65e824454214c10985a846cd9bee5f4d04e15cd875d9fe13b",
|
||||
"sha256:ac10196b8cde7a082e4e371ff171407270d3337c8d57ed43030094eb01d9c95c",
|
||||
"sha256:b767930af686551dc96a5eb70af3736709d547ffa275c11a5e820bfb3ae61d8d",
|
||||
"sha256:b9a1f4d256b81f59ba87bb7a29b9b38b1c018e052dba60a543cb0ddb5062d159",
|
||||
"sha256:ba94c08321b5d345100fc64eb1ab235f42faf9aabba805cface55ebe677f1c2c",
|
||||
"sha256:bab71f73001cd15723c4e2ca398f2f48e0a3f584c619eefddb1525e8986e06eb",
|
||||
"sha256:bce5cf2b0f0b29680396c5c98ab39a011bd70f2dfa8b8a6811a69ee6d920cf9f",
|
||||
"sha256:c02e514c72e745e49a3ae7e672a1018ba9b68460c21e0361054e956e5d595bc6",
|
||||
"sha256:c3fb459ced6c5e3b2a895f23f1400f93e9b24d85c30fbe2d637d4f7706a1116b",
|
||||
"sha256:cd31ab223e43ac64fd23f8f5dad249addadac2a459f040546200acbf7e84e353",
|
||||
"sha256:ce70aa089ec589b5d5fab388af9f8c9f9dfe8fe4ad844820a92eb240d8628ddf",
|
||||
"sha256:d47b2e1ad1429da9aa459ef189fbcd8a74ec28a16bc4c3f5f3cf3f88e36535eb",
|
||||
"sha256:d61bad421c1f496f9fb6114dbd7c30a1dac0e9ff90e9be06f4472cbd8f7a1704",
|
||||
"sha256:d7ba2e5cb119eddbc10874b41047ad99525e39e397f7aef500e6da0d6f46ab91",
|
||||
"sha256:dde0ab052c7a1deee8d13d72c37f2afecee30ebdf6eb139790157eaddf04dd61",
|
||||
"sha256:df34b52aa50a38d7a79f3abc9fda7e400791447aa0400ed895f275f6d8b0bb1f",
|
||||
"sha256:e0fc20e6e6b298861035a5fc5dcf9fbaa0546318e8bda81112591861a7dcc28f",
|
||||
"sha256:e20d5e8dc76b73db9280464d6e81bea05e51a99f4d4dd29c5f78dc79f294a5d3",
|
||||
"sha256:e31d1a33dc9006b278f72cb0aacfe397606c2693aa2fdc0c2f2dcddbad9e0b53",
|
||||
"sha256:e3a99f890f2cc5535e1b3a90049c6ca9ff9da9ec251cc130c8d269997f9d32ee",
|
||||
"sha256:e7b192c3df761d0fdd17c2d42d41c28460f124f5922e8bd524018f1d35610682",
|
||||
"sha256:ed0f4fad4c3656e34d20323a789b6a2d210a6bb82647d9c86dded372f55c58a1",
|
||||
"sha256:f34ec09702be907727fd479046193725441aaaf7ed4636ca042734f469bb7451",
|
||||
"sha256:f3530c0ec1fc98c43d5b7061781a8c55bd0db44f789f8152e19d9526cbed6021",
|
||||
"sha256:f5672082576d0e9f52fa0fa732ff57254d65faeb4a471bc339fe54b58b3e79d2",
|
||||
"sha256:ffb9f8969789771e95d3c982a36be81f0adfaa7302a1d56e29f168ca15e284b8"
|
||||
],
|
||||
"markers": "platform_machine == 'aarch64' or (platform_machine == 'ppc64le' or (platform_machine == 'x86_64' or (platform_machine == 'amd64' or (platform_machine == 'AMD64' or (platform_machine == 'win32' or platform_machine == 'WIN32')))))",
|
||||
"version": "==3.0.0a1"
|
||||
},
|
||||
"pymysql": {
|
||||
"hashes": [
|
||||
"sha256:4f13a7df8bf36a51e81dd9f3605fede45a4878fe02f9236349fd82a3f0612f96",
|
||||
"sha256:8969ec6d763c856f7073c4c64662882675702efcb114b4bcbb955aea3a069fa7"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==1.1.0"
|
||||
},
|
||||
"sqlalchemy": {
|
||||
"hashes": [
|
||||
"sha256:024d2f67fb3ec697555e48caeb7147cfe2c08065a4f1a52d93c3d44fc8e6ad1c",
|
||||
"sha256:0bf0fd65b50a330261ec7fe3d091dfc1c577483c96a9fa1e4323e932961aa1b5",
|
||||
"sha256:16a310f5bc75a5b2ce7cb656d0e76eb13440b8354f927ff15cbaddd2523ee2d1",
|
||||
"sha256:1d90ccc15ba1baa345796a8fb1965223ca7ded2d235ccbef80a47b85cea2d71a",
|
||||
"sha256:22bafb1da60c24514c141a7ff852b52f9f573fb933b1e6b5263f0daa28ce6db9",
|
||||
"sha256:2c69ce70047b801d2aba3e5ff3cba32014558966109fecab0c39d16c18510f15",
|
||||
"sha256:2e7b69d9ced4b53310a87117824b23c509c6fc1f692aa7272d47561347e133b6",
|
||||
"sha256:314145c1389b021a9ad5aa3a18bac6f5d939f9087d7fc5443be28cba19d2c972",
|
||||
"sha256:3afa8a21a9046917b3a12ffe016ba7ebe7a55a6fc0c7d950beb303c735c3c3ad",
|
||||
"sha256:430614f18443b58ceb9dedec323ecddc0abb2b34e79d03503b5a7579cd73a531",
|
||||
"sha256:43699eb3f80920cc39a380c159ae21c8a8924fe071bccb68fc509e099420b148",
|
||||
"sha256:539010665c90e60c4a1650afe4ab49ca100c74e6aef882466f1de6471d414be7",
|
||||
"sha256:57d100a421d9ab4874f51285c059003292433c648df6abe6c9c904e5bd5b0828",
|
||||
"sha256:5831138f0cc06b43edf5f99541c64adf0ab0d41f9a4471fd63b54ae18399e4de",
|
||||
"sha256:584f66e5e1979a7a00f4935015840be627e31ca29ad13f49a6e51e97a3fb8cae",
|
||||
"sha256:5d6afc41ca0ecf373366fd8e10aee2797128d3ae45eb8467b19da4899bcd1ee0",
|
||||
"sha256:61ada5831db36d897e28eb95f0f81814525e0d7927fb51145526c4e63174920b",
|
||||
"sha256:6b54d1ad7a162857bb7c8ef689049c7cd9eae2f38864fc096d62ae10bc100c7d",
|
||||
"sha256:7351c05db355da112e056a7b731253cbeffab9dfdb3be1e895368513c7d70106",
|
||||
"sha256:77a14fa20264af73ddcdb1e2b9c5a829b8cc6b8304d0f093271980e36c200a3f",
|
||||
"sha256:851a37898a8a39783aab603c7348eb5b20d83c76a14766a43f56e6ad422d1ec8",
|
||||
"sha256:89bc2b374ebee1a02fd2eae6fd0570b5ad897ee514e0f84c5c137c942772aa0c",
|
||||
"sha256:8e712cfd2e07b801bc6b60fdf64853bc2bd0af33ca8fa46166a23fe11ce0dbb0",
|
||||
"sha256:8f9eb4575bfa5afc4b066528302bf12083da3175f71b64a43a7c0badda2be365",
|
||||
"sha256:8fc05b59142445a4efb9c1fd75c334b431d35c304b0e33f4fa0ff1ea4890f92e",
|
||||
"sha256:96f0463573469579d32ad0c91929548d78314ef95c210a8115346271beeeaaa2",
|
||||
"sha256:9deaae357edc2091a9ed5d25e9ee8bba98bcfae454b3911adeaf159c2e9ca9e3",
|
||||
"sha256:a752b7a9aceb0ba173955d4f780c64ee15a1a991f1c52d307d6215c6c73b3a4c",
|
||||
"sha256:ae7473a67cd82a41decfea58c0eac581209a0aa30f8bc9190926fbf628bb17f7",
|
||||
"sha256:b15afbf5aa76f2241184c1d3b61af1a72ba31ce4161013d7cb5c4c2fca04fd6e",
|
||||
"sha256:c896d4e6ab2eba2afa1d56be3d0b936c56d4666e789bfc59d6ae76e9fcf46145",
|
||||
"sha256:cb4e688f6784427e5f9479d1a13617f573de8f7d4aa713ba82813bcd16e259d1",
|
||||
"sha256:cda283700c984e699e8ef0fcc5c61f00c9d14b6f65a4f2767c97242513fcdd84",
|
||||
"sha256:cf7b5e3856cbf1876da4e9d9715546fa26b6e0ba1a682d5ed2fc3ca4c7c3ec5b",
|
||||
"sha256:d6894708eeb81f6d8193e996257223b6bb4041cb05a17cd5cf373ed836ef87a2",
|
||||
"sha256:d8f2afd1aafded7362b397581772c670f20ea84d0a780b93a1a1529da7c3d369",
|
||||
"sha256:dd4d410a76c3762511ae075d50f379ae09551d92525aa5bb307f8343bf7c2c12",
|
||||
"sha256:eb60699de43ba1a1f77363f563bb2c652f7748127ba3a774f7cf2c7804aa0d3d",
|
||||
"sha256:f469f15068cd8351826df4080ffe4cc6377c5bf7d29b5a07b0e717dddb4c7ea2",
|
||||
"sha256:f82c310ddf97b04e1392c33cf9a70909e0ae10a7e2ddc1d64495e3abdc5d19fb",
|
||||
"sha256:fa51ce4aea583b0c6b426f4b0563d3535c1c75986c4373a0987d84d22376585b"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==2.0.19"
|
||||
},
|
||||
"tenacity": {
|
||||
"hashes": [
|
||||
"sha256:2f277afb21b851637e8f52e6a613ff08734c347dc19ade928e519d7d2d8569b0",
|
||||
"sha256:43af037822bd0029025877f3b2d97cc4d7bb0c2991000a3d59d71517c5c969e0"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==8.2.2"
|
||||
},
|
||||
"typing-extensions": {
|
||||
"hashes": [
|
||||
"sha256:440d5dd3af93b060174bf433bccd69b0babc3b15b1a8dca43789fd7f61514b36",
|
||||
"sha256:b75ddc264f0ba5615db7ba217daeb99701ad295353c45f9e95963337ceeeffb2"
|
||||
],
|
||||
"markers": "python_version >= '3.7'",
|
||||
"version": "==4.7.1"
|
||||
}
|
||||
},
|
||||
"develop": {
|
||||
"autopep8": {
|
||||
"hashes": [
|
||||
"sha256:86e9303b5e5c8160872b2f5ef611161b2893e9bfe8ccc7e2f76385947d57a2f1",
|
||||
"sha256:f9849cdd62108cb739dbcdbfb7fdcc9a30d1b63c4cc3e1c1f893b5360941b61c"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==2.0.2"
|
||||
},
|
||||
"flake8": {
|
||||
"hashes": [
|
||||
"sha256:3833794e27ff64ea4e9cf5d410082a8b97ff1a06c16aa3d2027339cd0f1195c7",
|
||||
"sha256:c61007e76655af75e6785a931f452915b371dc48f56efd765247c8fe68f2b181"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==6.0.0"
|
||||
},
|
||||
"mccabe": {
|
||||
"hashes": [
|
||||
"sha256:348e0240c33b60bbdf4e523192ef919f28cb2c3d7d5c7794f74009290f236325",
|
||||
"sha256:6c2d30ab6be0e4a46919781807b4f0d834ebdd6c6e3dca0bda5a15f863427b6e"
|
||||
],
|
||||
"markers": "python_version >= '3.6'",
|
||||
"version": "==0.7.0"
|
||||
},
|
||||
"pycodestyle": {
|
||||
"hashes": [
|
||||
"sha256:347187bdb476329d98f695c213d7295a846d1152ff4fe9bacb8a9590b8ee7053",
|
||||
"sha256:8a4eaf0d0495c7395bdab3589ac2db602797d76207242c17d470186815706610"
|
||||
],
|
||||
"markers": "python_version >= '3.6'",
|
||||
"version": "==2.10.0"
|
||||
},
|
||||
"pyflakes": {
|
||||
"hashes": [
|
||||
"sha256:ec55bf7fe21fff7f1ad2f7da62363d749e2a470500eab1b555334b67aa1ef8cf",
|
||||
"sha256:ec8b276a6b60bd80defed25add7e439881c19e64850afd9b346283d4165fd0fd"
|
||||
],
|
||||
"markers": "python_version >= '3.6'",
|
||||
"version": "==3.0.1"
|
||||
},
|
||||
"tomli": {
|
||||
"hashes": [
|
||||
"sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc",
|
||||
"sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"
|
||||
],
|
||||
"markers": "python_version < '3.11'",
|
||||
"version": "==2.0.1"
|
||||
}
|
||||
}
|
||||
}
|
||||
73
ecs/jskult-batch-laundering/README.md
Normal file
73
ecs/jskult-batch-laundering/README.md
Normal file
@ -0,0 +1,73 @@
|
||||
# 実消化&アルトマーク実績全件洗替処理
|
||||
|
||||
## 概要
|
||||
|
||||
実績全件洗替処理の週次バッチ処理。
|
||||
|
||||
## 環境情報
|
||||
|
||||
- Python 3.9
|
||||
- MySQL 8.23
|
||||
- VSCode
|
||||
|
||||
## 環境構築
|
||||
|
||||
- Python の構築
|
||||
|
||||
- Merck_NewDWH 開発 2021 の Wiki、[Python 環境構築](https://nds-tyo.backlog.com/alias/wiki/1874930)を参照
|
||||
- 「Pipenv の導入」までを行っておくこと
|
||||
- 構築完了後、プロジェクト配下で以下のコマンドを実行し、Python の仮想環境を作成する
|
||||
- `pipenv install --dev --python <pyenvでインストールしたpythonバージョン>`
|
||||
- この手順で出力される仮想環境のパスは、後述する VSCode の設定手順で使用するため、控えておく
|
||||
|
||||
- MySQL の環境構築
|
||||
- Windows の場合、以下のリンクからダウンロードする
|
||||
- <https://dev.mysql.com/downloads/installer/>
|
||||
- Docker を利用する場合、「newsdwh-tools」リポジトリの MySQL 設定を使用すると便利
|
||||
- 「crm-table-to-ddl」フォルダ内で以下のコマンドを実行すると
|
||||
- `docker-compose up -d`
|
||||
- Docker の構築手順は、[Docker のセットアップ手順](https://nds-tyo.backlog.com/alias/wiki/1754332)を参照のこと
|
||||
- データを投入する
|
||||
- 立ち上げたデータベースに「src05」スキーマを作成する
|
||||
- [ローカル開発用データ](https://ndstokyo.sharepoint.com/:f:/r/sites/merck-new-dwh-team/Shared%20Documents/03.NewDWH%E6%A7%8B%E7%AF%89%E3%83%95%E3%82%A7%E3%83%BC%E3%82%BA3/02.%E9%96%8B%E7%99%BA/90.%E9%96%8B%E7%99%BA%E5%85%B1%E6%9C%89/%E3%83%AD%E3%83%BC%E3%82%AB%E3%83%AB%E9%96%8B%E7%99%BA%E7%94%A8%E3%83%87%E3%83%BC%E3%82%BF?csf=1&web=1&e=VVcRUs)をダウンロードし、mysql コマンドを使用して復元する
|
||||
- `mysql -h <ホスト名> -P <ポート> -u <ユーザー名> -p src05 < src05_dump.sql`
|
||||
- 環境変数の設定
|
||||
- 「.env.example」ファイルをコピーし、「.env」ファイルを作成する
|
||||
- 環境変数を設定する。設定内容は PRJ メンバーより共有を受けてください
|
||||
- VSCode の設定
|
||||
- 「.vscode/recommended_settings.json」ファイルをコピーし、「settings.json」ファイルを作成する
|
||||
- 「python.defaultInterpreterPath」を、Python の構築手順で作成した仮想環境のパスに変更する
|
||||
|
||||
## 実行
|
||||
|
||||
- VSCode 上で「F5」キーを押下すると、バッチ処理が起動する。
|
||||
- 「entrypoint.py」が、バッチ処理のエントリーポイント。
|
||||
- 実際の処理は、「src/jobctrl_laundering.py」で行っている。
|
||||
|
||||
|
||||
## フォルダ構成
|
||||
├── .env.example -- ローカル実行用の環境変数のサンプル値。
|
||||
├── .dockerignore -- docker build時のコンテキストに含めるファイルの抑制リスト
|
||||
├── .gitignore -- Git差分管理除外リスト
|
||||
├── Dockerfile -- Dockerイメージを作成するためのファイル
|
||||
├── Pipfile -- Pythonモジュールの依存関係を管理するファイル
|
||||
├── Pipfile.lock -- Pythonモジュールの依存関係バージョン固定用ファイル
|
||||
├── README.md -- 当ファイル
|
||||
├── entrypoint.py -- バッチ処理のエントリーポイントになるpythonファイル
|
||||
└── src -- ソースコードの保管場所
|
||||
├── batch -- バッチ処理関連ソース置き場
|
||||
│ ├── batch_functions.py -- バッチ処理共通関数置き場
|
||||
│ └── laundering -- 実績全件洗替関連処理
|
||||
│ ├── create_inst_merge_for_laundering.py -- 洗替用マスタ作成処理
|
||||
│ └── sales_results_laundering.py -- 卸販売実績全件洗替処理
|
||||
├── db
|
||||
│ └── database.py -- データベース操作共通処理
|
||||
├── error
|
||||
│ └── exceptions.py -- カスタム例外
|
||||
├── jobctrl_laundering.py -- 実績全件洗替処理のエントリーポイント。「entrypoint.py」 から呼ばれる。
|
||||
├── logging
|
||||
│ └── get_logger.py -- ログ出力の共通処理
|
||||
└── system_var
|
||||
├── constants.py -- 定数ファイル
|
||||
└── environment.py -- 環境変数ファイル
|
||||
|
||||
10
ecs/jskult-batch-laundering/entrypoint.py
Normal file
10
ecs/jskult-batch-laundering/entrypoint.py
Normal file
@ -0,0 +1,10 @@
|
||||
"""実績全件洗替処理のエントリーポイント"""
|
||||
from src import jobctrl_laundering
|
||||
|
||||
if __name__ == '__main__':
|
||||
try:
|
||||
exit(jobctrl_laundering.exec())
|
||||
except Exception:
|
||||
# エラーが起きても、正常系のコードで返す。
|
||||
# エラーが起きた事実はbatch_process内でログを出す。
|
||||
exit(0)
|
||||
0
ecs/jskult-batch-laundering/src/__init__.py
Normal file
0
ecs/jskult-batch-laundering/src/__init__.py
Normal file
48
ecs/jskult-batch-laundering/src/batch/batch_functions.py
Normal file
48
ecs/jskult-batch-laundering/src/batch/batch_functions.py
Normal file
@ -0,0 +1,48 @@
|
||||
"""バッチ処理の共通関数"""
|
||||
import logging
|
||||
import textwrap
|
||||
|
||||
from src.db.database import Database
|
||||
from src.error.exceptions import BatchOperationException, DBException
|
||||
|
||||
|
||||
def get_batch_statuses() -> tuple[str, str]:
|
||||
"""日付テーブルから、以下を取得して返す。
|
||||
- バッチ処理中フラグ
|
||||
- dump取得状況区分
|
||||
|
||||
Raises:
|
||||
BatchOperationException: 日付テーブルが取得できないとき、何らかのエラーが発生したとき
|
||||
|
||||
Returns:
|
||||
tuple[str, str]: [0]バッチ処理中フラグ,[1]dump取得状況区分
|
||||
"""
|
||||
db = Database.get_instance()
|
||||
sql = 'SELECT bch_actf, dump_sts_kbn FROM src05.hdke_tbl'
|
||||
try:
|
||||
db.connect()
|
||||
hdke_tbl_result = db.execute_select(sql)
|
||||
except DBException as e:
|
||||
raise BatchOperationException(e)
|
||||
finally:
|
||||
db.disconnect()
|
||||
|
||||
if len(hdke_tbl_result) == 0:
|
||||
raise BatchOperationException('日付テーブルが取得できませんでした')
|
||||
|
||||
# 必ず1件取れる
|
||||
hdke_tbl_record = hdke_tbl_result[0]
|
||||
batch_processing_flag = hdke_tbl_record['bch_actf']
|
||||
dump_status_kbn = hdke_tbl_record['dump_sts_kbn']
|
||||
|
||||
return batch_processing_flag, dump_status_kbn
|
||||
|
||||
|
||||
def logging_sql(logger: logging.Logger, sql: str) -> None:
|
||||
"""SQL文をデバッグログで出力する
|
||||
|
||||
Args:
|
||||
logger (logging.Logger): ロガー
|
||||
sql (str): SQL文
|
||||
"""
|
||||
logger.debug(f'\n{"-" * 15}\n{textwrap.dedent(sql)[1:-1]}\n{"-" * 15}')
|
||||
@ -0,0 +1,31 @@
|
||||
from src.db.database import Database
|
||||
from src.error.exceptions import BatchOperationException
|
||||
from src.logging.get_logger import get_logger
|
||||
|
||||
logger = get_logger('洗替用マスタ作成')
|
||||
|
||||
|
||||
def exec():
|
||||
db = Database.get_instance()
|
||||
|
||||
try:
|
||||
db.connect()
|
||||
|
||||
logger.debug('処理開始')
|
||||
call_v_inst_merge_t_create(db)
|
||||
call_inst_merge_t_create(db)
|
||||
logger.debug('処理終了')
|
||||
except Exception as e:
|
||||
raise BatchOperationException(e)
|
||||
finally:
|
||||
db.disconnect()
|
||||
|
||||
|
||||
def call_v_inst_merge_t_create(db: Database):
|
||||
db.execute('CALL src05.v_inst_merge_t_create()')
|
||||
return
|
||||
|
||||
|
||||
def call_inst_merge_t_create(db: Database):
|
||||
db.execute('CALL src05.inst_merge_t_create()')
|
||||
return
|
||||
@ -0,0 +1,153 @@
|
||||
from src.batch.batch_functions import logging_sql
|
||||
from src.db.database import Database
|
||||
from src.error.exceptions import BatchOperationException
|
||||
from src.logging.get_logger import get_logger
|
||||
from src.system_var import environment
|
||||
|
||||
|
||||
logger = get_logger('卸販売実績全件洗替')
|
||||
|
||||
|
||||
def exec():
|
||||
db = Database.get_instance()
|
||||
try:
|
||||
db.connect()
|
||||
logger.debug('処理開始')
|
||||
# 卸販売実績テーブル(洗替後)作成
|
||||
_call_sales_lau_upsert(db)
|
||||
# 1:卸組織洗替
|
||||
_call_whs_org_laundering(db)
|
||||
# 3:HCO施設コードの洗替
|
||||
_update_sales_lau_from_vop_hco_merge_v(db)
|
||||
# 4:メルク施設コードの洗替
|
||||
_update_mst_inst_laundering(db)
|
||||
logger.debug('処理終了')
|
||||
except Exception as e:
|
||||
raise BatchOperationException(e)
|
||||
finally:
|
||||
db.disconnect()
|
||||
|
||||
|
||||
def _call_sales_lau_upsert(db: Database):
|
||||
# 卸販売実績テーブル(洗替後)作成
|
||||
logger.info('sales_lau_upsert(プロシージャ―) 開始')
|
||||
db.execute(f"""
|
||||
CALL src05.sales_lau_upsert(
|
||||
'{environment.SALES_LAUNDERING_TARGET_TABLE_NAME}',
|
||||
(src05.get_syor_date() - interval {environment.SALES_LAUNDERING_EXTRACT_DATE_PERIOD} day),
|
||||
src05.get_syor_date()
|
||||
)
|
||||
""")
|
||||
logger.info('sales_lau_upsert(プロシージャ―) 終了')
|
||||
return
|
||||
|
||||
|
||||
def _call_whs_org_laundering(db: Database):
|
||||
# 卸組織洗替
|
||||
logger.info('whs_org_laundering(プロシージャ―) 開始')
|
||||
db.execute(f"""
|
||||
CALL src05.whs_org_laundering(
|
||||
'{environment.SALES_LAUNDERING_TARGET_TABLE_NAME}'
|
||||
)
|
||||
""")
|
||||
logger.info('whs_org_laundering(プロシージャ―) 終了')
|
||||
return
|
||||
|
||||
|
||||
def _update_sales_lau_from_vop_hco_merge_v(db: Database):
|
||||
# HCO施設コードの洗替
|
||||
if _count_v_inst_merge_t(db) == 0:
|
||||
logger.info('V施設統合マスタ(洗替処理一時テーブル)にデータは存在しません')
|
||||
return
|
||||
|
||||
_call_v_inst_merge_laundering(db)
|
||||
return
|
||||
|
||||
|
||||
def _count_v_inst_merge_t(db: Database) -> int:
|
||||
# V施設統合マスタ(洗替処理一時テーブル)のデータ件数の取得
|
||||
try:
|
||||
sql = """
|
||||
SELECT
|
||||
COUNT(v_inst_cd) AS cnt
|
||||
FROM
|
||||
internal05.v_inst_merge_t
|
||||
"""
|
||||
result = db.execute_select(sql)
|
||||
logging_sql(logger, sql)
|
||||
logger.info('V施設統合マスタ(洗替処理一時テーブル)のデータ件数の取得 成功')
|
||||
except Exception as e:
|
||||
logger.debug('V施設統合マスタ(洗替処理一時テーブル)のデータ件数の取得 失敗')
|
||||
raise e
|
||||
|
||||
return result[0]['cnt']
|
||||
|
||||
|
||||
def _call_v_inst_merge_laundering(db: Database):
|
||||
# HCO施設コードの洗替(プロシージャ―の呼び出し)
|
||||
logger.info('v_inst_merge_laundering(プロシージャ―) 開始')
|
||||
db.execute(f"""
|
||||
CALL src05.v_inst_merge_laundering(
|
||||
'{environment.SALES_LAUNDERING_TARGET_TABLE_NAME}'
|
||||
)
|
||||
""")
|
||||
logger.info('v_inst_merge_laundering(プロシージャ―) 終了')
|
||||
return
|
||||
|
||||
|
||||
def _update_mst_inst_laundering(db: Database):
|
||||
# メルク施設コードの洗替
|
||||
_call_hco_to_mdb_laundering(db)
|
||||
_update_sales_lau_from_dcf_inst_merge(db)
|
||||
|
||||
|
||||
def _call_hco_to_mdb_laundering(db: Database):
|
||||
# A:医療機関のデータはMDB変換表からHCO⇒DCFへ変換
|
||||
logger.info('hco_to_mdb_laundering(プロシージャ―) 開始')
|
||||
db.execute(f"""
|
||||
CALL src05.hco_to_mdb_laundering(
|
||||
'{environment.SALES_LAUNDERING_TARGET_TABLE_NAME}'
|
||||
)
|
||||
""")
|
||||
logger.info('hco_to_mdb_laundering(プロシージャ―) 終了')
|
||||
return
|
||||
|
||||
|
||||
def _update_sales_lau_from_dcf_inst_merge(db: Database):
|
||||
# B:DCF施設統合マスタがある場合は、コードを変換し、住所等をSETする
|
||||
if _count_inst_merge_t(db) == 0:
|
||||
logger.info('アルトマーク施設統合マスタ(洗替処理一時テーブル)にデータは存在しません')
|
||||
return
|
||||
_call_inst_merge_laundering(db)
|
||||
return
|
||||
|
||||
|
||||
def _count_inst_merge_t(db: Database) -> int:
|
||||
# アルトマーク施設統合マスタ(洗替処理一時テーブル)のデータ件数の取得
|
||||
try:
|
||||
sql = """
|
||||
SELECT
|
||||
COUNT(dcf_dsf_inst_cd) AS cnt
|
||||
FROM
|
||||
internal05.inst_merge_t
|
||||
"""
|
||||
result = db.execute_select(sql)
|
||||
logging_sql(logger, sql)
|
||||
logger.info('アルトマーク施設統合マスタ(洗替処理一時テーブル)のデータ件数の取得 成功')
|
||||
except Exception as e:
|
||||
logger.debug('アルトマーク施設統合マスタ(洗替処理一時テーブル)のデータ件数の取得 失敗')
|
||||
raise e
|
||||
|
||||
return result[0]['cnt']
|
||||
|
||||
|
||||
def _call_inst_merge_laundering(db: Database):
|
||||
# B:DCF施設統合マスタがある場合は、コードを変換し、住所等をSETする(プロシージャ―の呼び出し)
|
||||
logger.info('inst_merge_laundering(プロシージャ―) 開始')
|
||||
db.execute(f"""
|
||||
CALL src05.inst_merge_laundering(
|
||||
'{environment.SALES_LAUNDERING_TARGET_TABLE_NAME}'
|
||||
)
|
||||
""")
|
||||
logger.info('inst_merge_laundering(プロシージャ―) 終了')
|
||||
return
|
||||
0
ecs/jskult-batch-laundering/src/db/__init__.py
Normal file
0
ecs/jskult-batch-laundering/src/db/__init__.py
Normal file
192
ecs/jskult-batch-laundering/src/db/database.py
Normal file
192
ecs/jskult-batch-laundering/src/db/database.py
Normal file
@ -0,0 +1,192 @@
|
||||
from sqlalchemy import (Connection, CursorResult, Engine, QueuePool,
|
||||
create_engine, text)
|
||||
from sqlalchemy.engine.url import URL
|
||||
from tenacity import retry, stop_after_attempt, wait_exponential
|
||||
|
||||
from src.error.exceptions import DBException
|
||||
from src.logging.get_logger import get_logger
|
||||
from src.system_var import environment
|
||||
|
||||
logger = get_logger(__name__)
|
||||
|
||||
|
||||
class Database:
|
||||
"""データベース操作クラス"""
|
||||
__connection: Connection = None
|
||||
__transactional_engine: Engine = None
|
||||
__autocommit_engine: Engine = None
|
||||
__host: str = None
|
||||
__port: str = None
|
||||
__username: str = None
|
||||
__password: str = None
|
||||
__schema: str = None
|
||||
__autocommit: bool = None
|
||||
__connection_string: str = None
|
||||
|
||||
def __init__(self, username: str, password: str, host: str, port: int, schema: str, autocommit: bool = False) -> None:
|
||||
"""このクラスの新たなインスタンスを初期化します
|
||||
|
||||
Args:
|
||||
username (str): DBユーザー名
|
||||
password (str): DBパスワード
|
||||
host (str): DBホスト名
|
||||
port (int): DBポート
|
||||
schema (str): DBスキーマ名
|
||||
autocommit(bool): 自動コミットモードで接続するかどうか(Trueの場合、トランザクションの有無に限らず即座にコミットされる). Defaults to False.
|
||||
"""
|
||||
self.__username = username
|
||||
self.__password = password
|
||||
self.__host = host
|
||||
self.__port = int(port)
|
||||
self.__schema = schema
|
||||
self.__autocommit = autocommit
|
||||
|
||||
self.__connection_string = URL.create(
|
||||
drivername='mysql+pymysql',
|
||||
username=self.__username,
|
||||
password=self.__password,
|
||||
host=self.__host,
|
||||
port=self.__port,
|
||||
database=self.__schema,
|
||||
query={"charset": "utf8mb4", "local_infile": "1"},
|
||||
)
|
||||
|
||||
self.__transactional_engine = create_engine(
|
||||
self.__connection_string,
|
||||
pool_timeout=5,
|
||||
poolclass=QueuePool
|
||||
)
|
||||
|
||||
self.__autocommit_engine = self.__transactional_engine.execution_options(isolation_level='AUTOCOMMIT')
|
||||
|
||||
@classmethod
|
||||
def get_instance(cls, autocommit=False):
|
||||
"""インスタンスを取得します
|
||||
|
||||
Args:
|
||||
autocommit (bool, optional): 自動コミットモードで接続するかどうか(Trueの場合、トランザクションの有無に限らず即座にコミットされる). Defaults to False.
|
||||
Returns:
|
||||
Database: DB操作クラスインスタンス
|
||||
"""
|
||||
return cls(
|
||||
username=environment.DB_USERNAME,
|
||||
password=environment.DB_PASSWORD,
|
||||
host=environment.DB_HOST,
|
||||
port=environment.DB_PORT,
|
||||
schema=environment.DB_SCHEMA,
|
||||
autocommit=autocommit
|
||||
)
|
||||
|
||||
@retry(
|
||||
wait=wait_exponential(
|
||||
multiplier=environment.DB_CONNECTION_RETRY_INTERVAL_INIT,
|
||||
min=environment.DB_CONNECTION_RETRY_INTERVAL_MIN_SECONDS,
|
||||
max=environment.DB_CONNECTION_RETRY_INTERVAL_MAX_SECONDS
|
||||
),
|
||||
stop=stop_after_attempt(environment.DB_CONNECTION_MAX_RETRY_ATTEMPT),
|
||||
retry_error_cls=DBException
|
||||
)
|
||||
def connect(self):
|
||||
"""
|
||||
DBに接続します。接続に失敗した場合、リトライします。\n
|
||||
インスタンスのautocommitがTrueの場合、自動コミットモードで接続する。(明示的なトランザクションも無視される)
|
||||
Raises:
|
||||
DBException: 接続失敗
|
||||
"""
|
||||
try:
|
||||
self.__connection = (
|
||||
self.__autocommit_engine.connect() if self.__autocommit is True
|
||||
else self.__transactional_engine.connect())
|
||||
except Exception as e:
|
||||
raise DBException(e)
|
||||
|
||||
def execute_select(self, select_query: str, parameters=None) -> list[dict]:
|
||||
"""SELECTクエリを実行します。
|
||||
|
||||
Args:
|
||||
select_query (str): SELECT文
|
||||
parameters (dict, optional): クエリのプレースホルダーに埋め込む変数の辞書. Defaults to None.
|
||||
|
||||
Raises:
|
||||
DBException: DBエラー
|
||||
|
||||
Returns:
|
||||
list[dict]: カラム名: 値の辞書リスト
|
||||
"""
|
||||
if self.__connection is None:
|
||||
raise DBException('DBに接続していません')
|
||||
|
||||
result = None
|
||||
try:
|
||||
# トランザクションが開始している場合は、トランザクションを引き継ぐ
|
||||
if self.__connection.in_transaction():
|
||||
result = self.__connection.execute(text(select_query), parameters)
|
||||
else:
|
||||
# トランザクションが明示的に開始していない場合は、クエリ単位でトランザクションをbegin-commitする。
|
||||
result = self.__execute_with_transaction(select_query, parameters)
|
||||
except Exception as e:
|
||||
raise DBException(f'SQL Error: {e}')
|
||||
|
||||
result_rows = result.mappings().all()
|
||||
return result_rows
|
||||
|
||||
def execute(self, query: str, parameters=None) -> CursorResult:
|
||||
"""SQLクエリを実行します。
|
||||
|
||||
Args:
|
||||
query (str): SQL文
|
||||
parameters (dict, optional): クエリのプレースホルダーに埋め込む変数の辞書. Defaults to None.
|
||||
|
||||
Raises:
|
||||
DBException: DBエラー
|
||||
|
||||
Returns:
|
||||
CursorResult: 取得結果
|
||||
"""
|
||||
if self.__connection is None:
|
||||
raise DBException('DBに接続していません')
|
||||
|
||||
result = None
|
||||
try:
|
||||
# トランザクションが開始している場合は、トランザクションを引き継ぐ
|
||||
if self.__connection.in_transaction():
|
||||
result = self.__connection.execute(text(query), parameters)
|
||||
else:
|
||||
# トランザクションが明示的に開始していない場合は、クエリ単位でトランザクションをbegin-commitする。
|
||||
result = self.__execute_with_transaction(query, parameters)
|
||||
except Exception as e:
|
||||
raise DBException(f'SQL Error: {e}')
|
||||
|
||||
return result
|
||||
|
||||
def begin(self):
|
||||
"""トランザクションを開始します。"""
|
||||
if not self.__connection.in_transaction():
|
||||
self.__connection.begin()
|
||||
|
||||
def commit(self):
|
||||
"""トランザクションをコミットします"""
|
||||
if self.__connection.in_transaction():
|
||||
self.__connection.commit()
|
||||
|
||||
def rollback(self):
|
||||
"""トランザクションをロールバックします"""
|
||||
if self.__connection.in_transaction():
|
||||
self.__connection.rollback()
|
||||
|
||||
def disconnect(self):
|
||||
"""DB接続を切断します。"""
|
||||
if self.__connection is not None:
|
||||
self.__connection.close()
|
||||
self.__connection = None
|
||||
|
||||
def __execute_with_transaction(self, query: str, parameters: dict):
|
||||
# トランザクションを開始してクエリを実行する
|
||||
with self.__connection.begin():
|
||||
try:
|
||||
result = self.__connection.execute(text(query), parameters=parameters)
|
||||
except Exception as e:
|
||||
self.__connection.rollback()
|
||||
raise e
|
||||
# ここでコミットされる
|
||||
return result
|
||||
0
ecs/jskult-batch-laundering/src/error/__init__.py
Normal file
0
ecs/jskult-batch-laundering/src/error/__init__.py
Normal file
10
ecs/jskult-batch-laundering/src/error/exceptions.py
Normal file
10
ecs/jskult-batch-laundering/src/error/exceptions.py
Normal file
@ -0,0 +1,10 @@
|
||||
class MeDaCaException(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class DBException(MeDaCaException):
|
||||
pass
|
||||
|
||||
|
||||
class BatchOperationException(MeDaCaException):
|
||||
pass
|
||||
39
ecs/jskult-batch-laundering/src/jobctrl_laundering.py
Normal file
39
ecs/jskult-batch-laundering/src/jobctrl_laundering.py
Normal file
@ -0,0 +1,39 @@
|
||||
"""実消化&アルトマーク実績全件洗替処理"""
|
||||
from src.batch.batch_functions import get_batch_statuses
|
||||
from src.error.exceptions import BatchOperationException
|
||||
from src.logging.get_logger import get_logger
|
||||
from src.system_var import constants
|
||||
from src.batch.laundering import (sales_results_laundering,
|
||||
create_inst_merge_for_laundering)
|
||||
|
||||
logger = get_logger('卸販売実績全件洗替')
|
||||
|
||||
|
||||
def exec():
|
||||
try:
|
||||
logger.info('週次バッチ:開始')
|
||||
try:
|
||||
# 日次バッチ処置中フラグ、dump処理状態区分、処理日を取得
|
||||
batch_processing_flag, dump_status_kbn = get_batch_statuses()
|
||||
except BatchOperationException as e:
|
||||
logger.exception(f'日付テーブル取得(異常終了){e}')
|
||||
return constants.BATCH_EXIT_CODE_SUCCESS
|
||||
|
||||
# 日次バッチ処理中の場合、後続の処理は行わない
|
||||
if batch_processing_flag == constants.BATCH_ACTF_BATCH_IN_PROCESSING:
|
||||
logger.warning('日次バッチ処理中のため、実消化&アルトマーク実績全件洗替処理を終了します。')
|
||||
return constants.BATCH_EXIT_CODE_SUCCESS
|
||||
|
||||
# dump取得が正常終了していない場合、後続の処理は行わない
|
||||
if dump_status_kbn != constants.DUMP_STATUS_KBN_UNPROCESSED:
|
||||
logger.warning('dump取得が正常終了していないため、実消化&アルトマーク実績全件洗替処理を終了します。')
|
||||
return constants.BATCH_EXIT_CODE_SUCCESS
|
||||
|
||||
# 洗替用マスタ作成
|
||||
create_inst_merge_for_laundering.exec()
|
||||
# 卸販売実績全件洗替
|
||||
sales_results_laundering.exec()
|
||||
logger.info('週次バッチ:終了')
|
||||
except Exception as e:
|
||||
logger.exception(f'実消化&アルトマーク実績全件洗替処理中に想定外のエラーが発生しました {e}')
|
||||
return constants.BATCH_EXIT_CODE_SUCCESS
|
||||
37
ecs/jskult-batch-laundering/src/logging/get_logger.py
Normal file
37
ecs/jskult-batch-laundering/src/logging/get_logger.py
Normal file
@ -0,0 +1,37 @@
|
||||
import logging
|
||||
|
||||
from src.system_var.environment import LOG_LEVEL
|
||||
|
||||
# boto3関連モジュールのログレベルを事前に個別指定し、モジュール内のDEBUGログの表示を抑止する
|
||||
for name in ["boto3", "botocore", "s3transfer", "urllib3"]:
|
||||
logging.getLogger(name).setLevel(logging.WARNING)
|
||||
|
||||
|
||||
def get_logger(log_name: str) -> logging.Logger:
|
||||
"""一意のログ出力モジュールを取得します。
|
||||
|
||||
Args:
|
||||
log_name (str): ロガー名
|
||||
|
||||
Returns:
|
||||
_type_: _description_
|
||||
"""
|
||||
logger = logging.getLogger(log_name)
|
||||
level = logging.getLevelName(LOG_LEVEL)
|
||||
if not isinstance(level, int):
|
||||
level = logging.INFO
|
||||
logger.setLevel(level)
|
||||
|
||||
if not logger.hasHandlers():
|
||||
handler = logging.StreamHandler()
|
||||
logger.addHandler(handler)
|
||||
|
||||
formatter = logging.Formatter(
|
||||
'%(name)s\t[%(levelname)s]\t%(asctime)s\t%(message)s',
|
||||
'%Y-%m-%d %H:%M:%S'
|
||||
)
|
||||
|
||||
for handler in logger.handlers:
|
||||
handler.setFormatter(formatter)
|
||||
|
||||
return logger
|
||||
8
ecs/jskult-batch-laundering/src/system_var/constants.py
Normal file
8
ecs/jskult-batch-laundering/src/system_var/constants.py
Normal file
@ -0,0 +1,8 @@
|
||||
# バッチ正常終了コード
|
||||
BATCH_EXIT_CODE_SUCCESS = 0
|
||||
|
||||
# バッチ処理中フラグ:処理中
|
||||
BATCH_ACTF_BATCH_IN_PROCESSING = '1'
|
||||
|
||||
# dump取得状態区分:未処理
|
||||
DUMP_STATUS_KBN_UNPROCESSED = '0'
|
||||
20
ecs/jskult-batch-laundering/src/system_var/environment.py
Normal file
20
ecs/jskult-batch-laundering/src/system_var/environment.py
Normal file
@ -0,0 +1,20 @@
|
||||
import os
|
||||
|
||||
# Database
|
||||
DB_HOST = os.environ['DB_HOST']
|
||||
DB_PORT = int(os.environ['DB_PORT'])
|
||||
DB_USERNAME = os.environ['DB_USERNAME']
|
||||
DB_PASSWORD = os.environ['DB_PASSWORD']
|
||||
DB_SCHEMA = os.environ['DB_SCHEMA']
|
||||
|
||||
# 初期値がある環境変数
|
||||
LOG_LEVEL = os.environ.get('LOG_LEVEL', 'INFO')
|
||||
DB_CONNECTION_MAX_RETRY_ATTEMPT = int(os.environ.get('DB_CONNECTION_MAX_RETRY_ATTEMPT', 4))
|
||||
DB_CONNECTION_RETRY_INTERVAL_INIT = int(os.environ.get('DB_CONNECTION_RETRY_INTERVAL', 5))
|
||||
DB_CONNECTION_RETRY_INTERVAL_MIN_SECONDS = int(os.environ.get('DB_CONNECTION_RETRY_MIN_SECONDS', 5))
|
||||
DB_CONNECTION_RETRY_INTERVAL_MAX_SECONDS = int(os.environ.get('DB_CONNECTION_RETRY_MAX_SECONDS', 50))
|
||||
|
||||
# 連携データ抽出期間
|
||||
SALES_LAUNDERING_EXTRACT_DATE_PERIOD = int(os.environ['SALES_LAUNDERING_EXTRACT_DATE_PERIOD'])
|
||||
# 洗替対象テーブル名
|
||||
SALES_LAUNDERING_TARGET_TABLE_NAME = os.environ['SALES_LAUNDERING_TARGET_TABLE_NAME']
|
||||
@ -46,7 +46,13 @@ def update_dump_status_kbn_in_processing() -> None:
|
||||
BatchOperationException: DB操作の何らかのエラー
|
||||
"""
|
||||
db = Database.get_instance()
|
||||
sql = 'UPDATE src05.hdke_tbl SET dump_sts_kbn = :in_processing'
|
||||
sql = """\
|
||||
UPDATE src05.hdke_tbl
|
||||
SET
|
||||
dump_sts_kbn = :in_processing,
|
||||
updater = CURRENT_USER(),
|
||||
update_date = NOW()
|
||||
"""
|
||||
try:
|
||||
db.connect()
|
||||
db.execute(sql, {'in_processing': constants.BATCH_ACTF_BATCH_IN_PROCESSING})
|
||||
@ -68,7 +74,9 @@ def update_dump_status_kbn_error() -> None:
|
||||
sql = """\
|
||||
UPDATE src05.hdke_tbl
|
||||
SET
|
||||
dump_sts_kbn = :dump_unprocessed
|
||||
dump_sts_kbn = :dump_unprocessed,
|
||||
updater = CURRENT_USER(),
|
||||
update_date = NOW()
|
||||
"""
|
||||
try:
|
||||
db.connect()
|
||||
@ -93,7 +101,9 @@ def update_dump_status_kbn_complete() -> None:
|
||||
sql = """\
|
||||
UPDATE src05.hdke_tbl
|
||||
SET
|
||||
dump_sts_kbn = :dump_unprocessed
|
||||
dump_sts_kbn = :dump_unprocessed,
|
||||
updater = CURRENT_USER(),
|
||||
update_date = NOW()
|
||||
"""
|
||||
try:
|
||||
db.connect()
|
||||
|
||||
@ -16,4 +16,4 @@ RUN \
|
||||
|
||||
COPY src ./src
|
||||
|
||||
CMD ["gunicorn", "src.main:app", "-w", "4", "-k" ,"uvicorn.workers.UvicornWorker", "-b", "0.0.0.0:80"]
|
||||
CMD ["gunicorn", "src.main:app", "-w", "4", "-k" ,"uvicorn.workers.UvicornWorker", "-b", "0.0.0.0:80", "--timeout", "300"]
|
||||
|
||||
@ -117,7 +117,7 @@ def inst_emp_csv_upload_view(
|
||||
@router.post('/instEmpCsvUL', response_class=HTMLResponse)
|
||||
async def inst_emp_csv_upload(
|
||||
request: Request,
|
||||
csv_upload_form: Optional[MasterMainteCsvUpModel] = Depends(MasterMainteCsvUpModel.as_form),
|
||||
csv_upload_form: MasterMainteCsvUpModel = Depends(MasterMainteCsvUpModel.as_form),
|
||||
master_mainte_service: MasterMainteService = Depends(get_service(MasterMainteService)),
|
||||
batch_status_service: BatchStatusService = Depends(get_service(BatchStatusService))
|
||||
):
|
||||
@ -137,12 +137,13 @@ async def inst_emp_csv_upload(
|
||||
|
||||
# 画面表示用のモデル
|
||||
error_message_list = []
|
||||
csv_filename: str = csv_upload_form.csv_file.filename
|
||||
if csv_upload_form.csv_file.size == 0:
|
||||
error_message_list.append('選択されたファイルが見つかりませんでした。')
|
||||
elif not csv_upload_form.csv_file.filename.endswith('.csv'):
|
||||
elif not csv_filename.endswith('.csv'):
|
||||
error_message_list.append('選択されたファイル形式が"csv"ではありません。')
|
||||
elif csv_upload_form.csv_file.size >= constants.MENTE_CSV_UPLOAD_MAX_FILE_SIZE_BYTE:
|
||||
error_message_list.append('選択されたCSVファイルサイズが大きいです。100MB未満にしてください。')
|
||||
error_message_list.append('選択されたCSVファイルサイズが大きいです。20MB未満にしてください。')
|
||||
else:
|
||||
mainte_csv_up = master_mainte_service.prepare_mainte_csv_up_view(
|
||||
TextIOWrapper(BytesIO(await csv_upload_form.csv_file.read()), encoding='utf-8'),
|
||||
|
||||
@ -55,31 +55,6 @@ BIO_CSV_HEADER = [
|
||||
'2017年11月以前データ'
|
||||
]
|
||||
|
||||
SLIP_ORG_KBN_FULL_NAME = {
|
||||
'J': 'JD-NET',
|
||||
'N': 'NHI',
|
||||
'H': '手入力'
|
||||
}
|
||||
DATA_KBN_JP_NAME = {
|
||||
'0': '正常',
|
||||
'1': 'ロットエラー',
|
||||
'2': '除外',
|
||||
'3': 'ロット不明',
|
||||
'9': 'エラー(解消済)',
|
||||
}
|
||||
LOT_NO_ERR_FLG_JP_NAME = {
|
||||
'0': '正常',
|
||||
'1': 'ロットエラー',
|
||||
'2': '日付エラー',
|
||||
'3': 'ロットエラー(解消済)',
|
||||
'4': 'ロットエラー(調査不能)',
|
||||
'5': '日付エラー(解消済)',
|
||||
'6': '日付エラー(調査不能)',
|
||||
'7': '除外(卸都合)',
|
||||
'8': '除外(再送信)',
|
||||
'Z': '過去データ'
|
||||
}
|
||||
|
||||
LOGOUT_REASON_DO_LOGOUT = 'do_logout'
|
||||
LOGOUT_REASON_LOGIN_ERROR = 'login_error'
|
||||
LOGOUT_REASON_BATCH_PROCESSING = 'batch_processing'
|
||||
@ -217,5 +192,5 @@ MENTE_CSV_DOWNLOAD_HEADER = [
|
||||
|
||||
MENTE_CSV_DOWNLOAD_FILE_NAME = 'instEmpData.csv'
|
||||
|
||||
# CSVアップロードの制限サイズ=100MB
|
||||
MENTE_CSV_UPLOAD_MAX_FILE_SIZE_BYTE = 104857600
|
||||
# CSVアップロードの制限サイズ=20MB
|
||||
MENTE_CSV_UPLOAD_MAX_FILE_SIZE_BYTE = 20971520
|
||||
|
||||
@ -42,6 +42,7 @@ BEGIN
|
||||
'【洗替】1.卸組織洗替② 開始'
|
||||
);
|
||||
|
||||
SET SESSION optimizer_switch = 'derived_merge=off';
|
||||
INSERT INTO
|
||||
internal05.whs_customer_org_t (
|
||||
whs_cd,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user