diff --git a/ecs/jskult-batch-daily/.env.example b/ecs/jskult-batch-daily/.env.example index d1f4ddf4..91ae5f74 100644 --- a/ecs/jskult-batch-daily/.env.example +++ b/ecs/jskult-batch-daily/.env.example @@ -3,4 +3,8 @@ DB_PORT=************ DB_USERNAME=************ DB_PASSWORD=************ DB_SCHEMA=src05 -LOG_LEVEL=INFO \ No newline at end of file +LOG_LEVEL=INFO +ULTMARC_DATA_BUCKET=**************** +ULTMARC_DATA_FOLDER=recv +ULTMARC_BACKUP_BUCKET=**************** +ULTMARC_BACKUP_FOLDER=ultmarc diff --git a/ecs/jskult-batch-daily/.gitignore b/ecs/jskult-batch-daily/.gitignore index 705f2b57..bd0b37f8 100644 --- a/ecs/jskult-batch-daily/.gitignore +++ b/ecs/jskult-batch-daily/.gitignore @@ -1,4 +1,10 @@ -__pycache__ - .vscode/settings.json .env + +# python +__pycache__ + +# python test +.pytest_cache +.coverage +.report/ \ No newline at end of file diff --git a/ecs/jskult-batch-daily/.vscode/launch.json b/ecs/jskult-batch-daily/.vscode/launch.json index 2df4d8bf..9dbaa9c6 100644 --- a/ecs/jskult-batch-daily/.vscode/launch.json +++ b/ecs/jskult-batch-daily/.vscode/launch.json @@ -5,7 +5,7 @@ "version": "0.2.0", "configurations": [ { - "name": "Batch Sample", + "name": "(DEBUG)jskult batch daily", "type": "python", "request": "launch", "program": "entrypoint.py", diff --git a/ecs/jskult-batch-daily/.vscode/recommended_settings.json b/ecs/jskult-batch-daily/.vscode/recommended_settings.json index d5ce3e07..b5e79d73 100644 --- a/ecs/jskult-batch-daily/.vscode/recommended_settings.json +++ b/ecs/jskult-batch-daily/.vscode/recommended_settings.json @@ -12,7 +12,20 @@ "python.linting.enabled": true, "python.linting.pylintEnabled": false, "python.linting.flake8Enabled": true, - "python.linting.flake8Args": ["--max-line-length=120"], + "python.linting.flake8Args": [ + "--max-line-length=200", + "--ignore=F541" + ], "python.formatting.provider": "autopep8", - "python.formatting.autopep8Args": ["--max-line-length", "120"] + "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 } diff --git a/ecs/jskult-batch-daily/Pipfile b/ecs/jskult-batch-daily/Pipfile index 3cc5b359..a5d5dddd 100644 --- a/ecs/jskult-batch-daily/Pipfile +++ b/ecs/jskult-batch-daily/Pipfile @@ -3,6 +3,10 @@ url = "https://pypi.org/simple" verify_ssl = true name = "pypi" +[scripts] +"test:ultmarc" = "pytest tests/batch/ultmarc/" +"test:ultmarc:cov" = "pytest --cov=src/batch/ultmarc/ --cov-branch --cov-report=term-missing tests/batch/ultmarc/" + [packages] boto3 = "*" PyMySQL = "*" @@ -12,6 +16,8 @@ tenacity = "*" [dev-packages] autopep8 = "*" flake8 = "*" +pytest = "*" +pytest-cov = "*" [requires] python_version = "3.9" diff --git a/ecs/jskult-batch-daily/Pipfile.lock b/ecs/jskult-batch-daily/Pipfile.lock index b6531ec3..519c60a0 100644 --- a/ecs/jskult-batch-daily/Pipfile.lock +++ b/ecs/jskult-batch-daily/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "1b9b3da586499b64915b0cf14217a1bcfb26c5e3e1c6fbfc9cce99242bc4faed" + "sha256": "9bce8f43bcad5d6ae8e5a558b8ade00a83f6e1671993e91b0a883fffa6b95df9" }, "pipfile-spec": 6, "requires": { @@ -18,19 +18,19 @@ "default": { "boto3": { "hashes": [ - "sha256:043f8981d10c4e7c48736df4381dac557b46c5b369b0a450d8f3d7f5fdd24db5", - "sha256:b00f416832bc59863b96175045d2ebe067d9222289bce677c48fd72c006eaaad" + "sha256:816a198a6cc4f283af6b21439d85be6dbe4b73c2232dd906c6bafb4fece28d19", + "sha256:9de90a2c0b853f84436b032b28947fc8a765dc462573a8d543b13f16c6579b40" ], "index": "pypi", - "version": "==1.26.102" + "version": "==1.26.107" }, "botocore": { "hashes": [ - "sha256:4bae8f502507da18ff37c61cb18745cfb11d87a61dd0ea27e346adadff92aa3f", - "sha256:58b11c630d2044ea732ba4c403d29fab51e954465f9b3f7099cbf5ac0ce7ab47" + "sha256:ee1e43e6cd0864cc6811ba3f05123647612ee3f07a286a4c94f5885aa86d6922", + "sha256:f63942b4b7248c0b3d6ecbc2852cf0787c23ace2a91a012f7ee0b3ae3eb08f4f" ], "markers": "python_version >= '3.7'", - "version": "==1.29.102" + "version": "==1.29.107" }, "greenlet": { "hashes": [ @@ -140,50 +140,50 @@ }, "sqlalchemy": { "hashes": [ - "sha256:013f4f330001e84a2b0ef1f2c9bd73169c79d582e54e1a144be1be1dbc911711", - "sha256:0789e199fbce8cb1775337afc631ed12bcc5463dd77d7a06b8dafd758cde51f8", - "sha256:0b698440c477c00bdedff87348b19a79630a235864a8f4378098d61079c16ce9", - "sha256:0eac488be90dd3f7a655d2e34fa59e1305fccabc4abfbd002e3a72ae10bd2f89", - "sha256:14854bdb2a35af536d14f77dfa8dbc20e1bb1972996d64c4147e0d3165c9aaf5", - "sha256:18795e87601b4244fd08b542cd6bff9ef674b17bcd34e4a3c9935398e2cc762c", - "sha256:32f508fef9c5a7d19411d94ef64cf5405e42c4689e51ddbb81ac9a7be045cce8", - "sha256:33f73cc45ffa050f5c3b60ff4490e0ae9e02701461c1600d5ede1b008076b1b9", - "sha256:38e26cf6b9b4c6c37846f7e31b42e4d664b35f055691265f07e06aeb6167c494", - "sha256:3da3dff8d9833a7d7f66a3c45a79a3955f775c79f47bb7eea266d0b4c267b17a", - "sha256:432cfd77642771ee7ea0dd0f3fb664f18506a3625eab6e6d5d1d771569171270", - "sha256:4339110be209fea37a2bb4f35f1127c7562a0393e9e6df5d9a65cc4f5c167cb6", - "sha256:486015a58c9a67f65a15b4f19468b35b97cee074ae55386a9c240f1da308fbfe", - "sha256:494db0026918e3f707466a1200a5dedbf254a4bce01a3115fd95f04ba8258f09", - "sha256:57b80e877eb6ec63295835f8a3b86ca3a44829f80c4748e1b019e03adea550fc", - "sha256:5f7c40ec2e3b31293184020daba95850832bea523a08496ac89b27a5276ec804", - "sha256:6d44ff7573016fc26311b5a5c54d5656fb9e0c39e138bc8b81cb7c8667485203", - "sha256:774965c41b71c8ebe3c5728bf5b9a948231fc3a0422d9fdace0686f5bb689ad6", - "sha256:7917632606fc5d4be661dcde45cc415df835e594e2c50cc999a44f24b6bf6d92", - "sha256:9020125e3be677c64d4dda7048e247343f1663089cf268a4cc98c957adb7dbe0", - "sha256:921485d1f69ed016e1f756de67d02ad4f143eb6b92b9776bfff78786d8978ab5", - "sha256:94556a2a7fc3de094ea056b62845e2e6e271e26d1e1b2540a1cd2d2506257a10", - "sha256:a4c1e1582492c66dfacc9eab52738f3e64d9a2a380e412668f75aa06e540f649", - "sha256:a65a8fd09bdffd63fa23b39cd902e6a4ca23d86ecfe129513e43767a1f3e91fb", - "sha256:a6f7d1debb233f1567d700ebcdde0781a0b63db0ef266246dfbf75ae41bfdf85", - "sha256:b0995b92612979d208189245bf87349ad9243b97b49652347a28ddee0803225a", - "sha256:b8ab8f90f4a13c979e6c41c9f011b655c1b9ae2df6cffa8fa2c7c4d740f3512e", - "sha256:bc370d53fee7408330099c4bcc2573a107757b203bc61f114467dfe586a0c7bd", - "sha256:c38641f5c3714505d65dbbd8fb1350408b9ad8461769ec8e440e1177f9c92d1d", - "sha256:cc337b96ec59ef29907eeadc2ac11188739281568f14c719e61550ca6d201a41", - "sha256:ce076e25f1170000b4ecdc57a1ff8a70dbe4a5648ec3da0563ef3064e8db4f15", - "sha256:cebd161f964af58290596523c65e41a5a161a99f7212b1ae675e288a4b5e0a7c", - "sha256:d2e7411d5ea164c6f4d003f5d4f5e72e202956aaa7496b95bb4a4c39669e001c", - "sha256:e735a635126b2338dfd3a0863b675437cb53d85885a7602b8cffb24345df33ed", - "sha256:e7e61e2e4dfe175dc3510889e44eda1c32f55870d6950ef40519640cb266704d", - "sha256:e90f0be674e0845c5c1ccfa5e31c9ee28fd406546a61afc734355cc7ea1f8f8b", - "sha256:ea1c63e61b5c13161c8468305f0a5837c80aae2070e33654c68dd12572b638eb", - "sha256:ea9461f6955f3cf9eff6eeec271686caed7792c76f5b966886a36a42ea46e6b2", - "sha256:f15c54713a8dd57a01c974c9f96476688f6f6374d348819ed7e459535844b614", - "sha256:fb649c5473f79c9a7b6133f53a31f4d87de14755c79224007eb7ec76e628551e", - "sha256:fc67667c8e8c04e5c3250ab2cd51df40bc7c28c7c253d0475b377eff86fe4bb0" + "sha256:07950fc82f844a2de67ddb4e535f29b65652b4d95e8b847823ce66a6d540a41d", + "sha256:0a865b5ec4ba24f57c33b633b728e43fde77b968911a6046443f581b25d29dd9", + "sha256:0b49f1f71d7a44329a43d3edd38cc5ee4c058dfef4487498393d16172007954b", + "sha256:13f984a190d249769a050634b248aef8991acc035e849d02b634ea006c028fa8", + "sha256:1b69666e25cc03c602d9d3d460e1281810109e6546739187044fc256c67941ef", + "sha256:1d06e119cf79a3d80ab069f064a07152eb9ba541d084bdaee728d8a6f03fd03d", + "sha256:246712af9fc761d6c13f4f065470982e175d902e77aa4218c9cb9fc9ff565a0c", + "sha256:34eb96c1de91d8f31e988302243357bef3f7785e1b728c7d4b98bd0c117dafeb", + "sha256:4c3020afb144572c7bfcba9d7cce57ad42bff6e6115dffcfe2d4ae6d444a214f", + "sha256:4f759eccb66e6d495fb622eb7f4ac146ae674d829942ec18b7f5a35ddf029597", + "sha256:68ed381bc340b4a3d373dbfec1a8b971f6350139590c4ca3cb722fdb50035777", + "sha256:6b72dccc5864ea95c93e0a9c4e397708917fb450f96737b4a8395d009f90b868", + "sha256:6e84ab63d25d8564d7a8c05dc080659931a459ee27f6ed1cf4c91f292d184038", + "sha256:734805708632e3965c2c40081f9a59263c29ffa27cba9b02d4d92dfd57ba869f", + "sha256:78612edf4ba50d407d0eb3a64e9ec76e6efc2b5d9a5c63415d53e540266a230a", + "sha256:7e472e9627882f2d75b87ff91c5a2bc45b31a226efc7cc0a054a94fffef85862", + "sha256:865392a50a721445156809c1a6d6ab6437be70c1c2599f591a8849ed95d3c693", + "sha256:8d118e233f416d713aac715e2c1101e17f91e696ff315fc9efbc75b70d11e740", + "sha256:8d3ece5960b3e821e43a4927cc851b6e84a431976d3ffe02aadb96519044807e", + "sha256:93c78d42c14aa9a9e0866eacd5b48df40a50d0e2790ee377af7910d224afddcf", + "sha256:95719215e3ec7337b9f57c3c2eda0e6a7619be194a5166c07c1e599f6afc20fa", + "sha256:9838bd247ee42eb74193d865e48dd62eb50e45e3fdceb0fdef3351133ee53dcf", + "sha256:aa5c270ece17c0c0e0a38f2530c16b20ea05d8b794e46c79171a86b93b758891", + "sha256:ac6a0311fb21a99855953f84c43fcff4bdca27a2ffcc4f4d806b26b54b5cddc9", + "sha256:ad5363a1c65fde7b7466769d4261126d07d872fc2e816487ae6cec93da604b6b", + "sha256:b3e5864eba71a3718236a120547e52c8da2ccb57cc96cecd0480106a0c799c92", + "sha256:bbda1da8d541904ba262825a833c9f619e93cb3fd1156be0a5e43cd54d588dcd", + "sha256:c6e27189ff9aebfb2c02fd252c629ea58657e7a5ff1a321b7fc9c2bf6dc0b5f3", + "sha256:c8239ce63a90007bce479adf5460d48c1adae4b933d8e39a4eafecfc084e503c", + "sha256:d209594e68bec103ad5243ecac1b40bf5770c9ebf482df7abf175748a34f4853", + "sha256:d5327f54a9c39e7871fc532639616f3777304364a0bb9b89d6033ad34ef6c5f8", + "sha256:db4bd1c4792da753f914ff0b688086b9a8fd78bb9bc5ae8b6d2e65f176b81eb9", + "sha256:e4780be0f19e5894c17f75fc8de2fe1ae233ab37827125239ceb593c6f6bd1e2", + "sha256:e4a019f723b6c1e6b3781be00fb9e0844bc6156f9951c836ff60787cc3938d76", + "sha256:e62c4e762d6fd2901692a093f208a6a6575b930e9458ad58c2a7f080dd6132da", + "sha256:e730603cae5747bc6d6dece98b45a57d647ed553c8d5ecef602697b1c1501cf2", + "sha256:ebc4eeb1737a5a9bdb0c24f4c982319fa6edd23cdee27180978c29cbb026f2bd", + "sha256:ee2946042cc7851842d7a086a92b9b7b494cbe8c3e7e4627e27bc912d3a7655e", + "sha256:f005245e1cb9b8ca53df73ee85e029ac43155e062405015e49ec6187a2e3fb44", + "sha256:f49c5d3c070a72ecb96df703966c9678dda0d4cb2e2736f88d15f5e1203b4159", + "sha256:f61ab84956dc628c8dfe9d105b6aec38afb96adae3e5e7da6085b583ff6ea789" ], "index": "pypi", - "version": "==2.0.7" + "version": "==2.0.9" }, "tenacity": { "hashes": [ @@ -211,6 +211,14 @@ } }, "develop": { + "attrs": { + "hashes": [ + "sha256:29e95c7f6778868dbd49170f98f8818f78f3dc5e0e37c0b1f474e3561b240836", + "sha256:c9227bfc2f01993c03f68db37d1d15c9690188323c067c641f1a35ca58185f99" + ], + "markers": "python_version >= '3.6'", + "version": "==22.2.0" + }, "autopep8": { "hashes": [ "sha256:86e9303b5e5c8160872b2f5ef611161b2893e9bfe8ccc7e2f76385947d57a2f1", @@ -219,6 +227,74 @@ "index": "pypi", "version": "==2.0.2" }, + "coverage": { + "extras": [ + "toml" + ], + "hashes": [ + "sha256:006ed5582e9cbc8115d2e22d6d2144a0725db542f654d9d4fda86793832f873d", + "sha256:046936ab032a2810dcaafd39cc4ef6dd295df1a7cbead08fe996d4765fca9fe4", + "sha256:0484d9dd1e6f481b24070c87561c8d7151bdd8b044c93ac99faafd01f695c78e", + "sha256:0ce383d5f56d0729d2dd40e53fe3afeb8f2237244b0975e1427bfb2cf0d32bab", + "sha256:186e0fc9cf497365036d51d4d2ab76113fb74f729bd25da0975daab2e107fd90", + "sha256:2199988e0bc8325d941b209f4fd1c6fa007024b1442c5576f1a32ca2e48941e6", + "sha256:299bc75cb2a41e6741b5e470b8c9fb78d931edbd0cd009c58e5c84de57c06731", + "sha256:3668291b50b69a0c1ef9f462c7df2c235da3c4073f49543b01e7eb1dee7dd540", + "sha256:36dd42da34fe94ed98c39887b86db9d06777b1c8f860520e21126a75507024f2", + "sha256:38004671848b5745bb05d4d621526fca30cee164db42a1f185615f39dc997292", + "sha256:387fb46cb8e53ba7304d80aadca5dca84a2fbf6fe3faf6951d8cf2d46485d1e5", + "sha256:3eb55b7b26389dd4f8ae911ba9bc8c027411163839dea4c8b8be54c4ee9ae10b", + "sha256:420f94a35e3e00a2b43ad5740f935358e24478354ce41c99407cddd283be00d2", + "sha256:4ac0f522c3b6109c4b764ffec71bf04ebc0523e926ca7cbe6c5ac88f84faced0", + "sha256:4c752d5264053a7cf2fe81c9e14f8a4fb261370a7bb344c2a011836a96fb3f57", + "sha256:4f01911c010122f49a3e9bdc730eccc66f9b72bd410a3a9d3cb8448bb50d65d3", + "sha256:4f68ee32d7c4164f1e2c8797535a6d0a3733355f5861e0f667e37df2d4b07140", + "sha256:4fa54fb483decc45f94011898727802309a109d89446a3c76387d016057d2c84", + "sha256:507e4720791977934bba016101579b8c500fb21c5fa3cd4cf256477331ddd988", + "sha256:53d0fd4c17175aded9c633e319360d41a1f3c6e352ba94edcb0fa5167e2bad67", + "sha256:55272f33da9a5d7cccd3774aeca7a01e500a614eaea2a77091e9be000ecd401d", + "sha256:5764e1f7471cb8f64b8cda0554f3d4c4085ae4b417bfeab236799863703e5de2", + "sha256:57b77b9099f172804e695a40ebaa374f79e4fb8b92f3e167f66facbf92e8e7f5", + "sha256:5afdad4cc4cc199fdf3e18088812edcf8f4c5a3c8e6cb69127513ad4cb7471a9", + "sha256:5cc0783844c84af2522e3a99b9b761a979a3ef10fb87fc4048d1ee174e18a7d8", + "sha256:5e1df45c23d4230e3d56d04414f9057eba501f78db60d4eeecfcb940501b08fd", + "sha256:6146910231ece63facfc5984234ad1b06a36cecc9fd0c028e59ac7c9b18c38c6", + "sha256:797aad79e7b6182cb49c08cc5d2f7aa7b2128133b0926060d0a8889ac43843be", + "sha256:7c20b731211261dc9739bbe080c579a1835b0c2d9b274e5fcd903c3a7821cf88", + "sha256:817295f06eacdc8623dc4df7d8b49cea65925030d4e1e2a7c7218380c0072c25", + "sha256:81f63e0fb74effd5be736cfe07d710307cc0a3ccb8f4741f7f053c057615a137", + "sha256:872d6ce1f5be73f05bea4df498c140b9e7ee5418bfa2cc8204e7f9b817caa968", + "sha256:8c99cb7c26a3039a8a4ee3ca1efdde471e61b4837108847fb7d5be7789ed8fd9", + "sha256:8dbe2647bf58d2c5a6c5bcc685f23b5f371909a5624e9f5cd51436d6a9f6c6ef", + "sha256:8efb48fa743d1c1a65ee8787b5b552681610f06c40a40b7ef94a5b517d885c54", + "sha256:92ebc1619650409da324d001b3a36f14f63644c7f0a588e331f3b0f67491f512", + "sha256:9d22e94e6dc86de981b1b684b342bec5e331401599ce652900ec59db52940005", + "sha256:ba279aae162b20444881fc3ed4e4f934c1cf8620f3dab3b531480cf602c76b7f", + "sha256:bc4803779f0e4b06a2361f666e76f5c2e3715e8e379889d02251ec911befd149", + "sha256:bfe7085783cda55e53510482fa7b5efc761fad1abe4d653b32710eb548ebdd2d", + "sha256:c448b5c9e3df5448a362208b8d4b9ed85305528313fca1b479f14f9fe0d873b8", + "sha256:c90e73bdecb7b0d1cea65a08cb41e9d672ac6d7995603d6465ed4914b98b9ad7", + "sha256:d2b96123a453a2d7f3995ddb9f28d01fd112319a7a4d5ca99796a7ff43f02af5", + "sha256:d52f0a114b6a58305b11a5cdecd42b2e7f1ec77eb20e2b33969d702feafdd016", + "sha256:d530191aa9c66ab4f190be8ac8cc7cfd8f4f3217da379606f3dd4e3d83feba69", + "sha256:d683d230b5774816e7d784d7ed8444f2a40e7a450e5720d58af593cb0b94a212", + "sha256:db45eec1dfccdadb179b0f9ca616872c6f700d23945ecc8f21bb105d74b1c5fc", + "sha256:db8c2c5ace167fd25ab5dd732714c51d4633f58bac21fb0ff63b0349f62755a8", + "sha256:e2926b8abedf750c2ecf5035c07515770944acf02e1c46ab08f6348d24c5f94d", + "sha256:e627dee428a176ffb13697a2c4318d3f60b2ccdde3acdc9b3f304206ec130ccd", + "sha256:efe1c0adad110bf0ad7fb59f833880e489a61e39d699d37249bdf42f80590169" + ], + "markers": "python_version >= '3.7'", + "version": "==7.2.2" + }, + "exceptiongroup": { + "hashes": [ + "sha256:232c37c63e4f682982c8b6459f33a8981039e5fb8756b2074364e5055c498c9e", + "sha256:d484c3090ba2889ae2928419117447a14daf3c1231d5e30d0aae34f354f01785" + ], + "markers": "python_version < '3.11'", + "version": "==1.1.1" + }, "flake8": { "hashes": [ "sha256:3833794e27ff64ea4e9cf5d410082a8b97ff1a06c16aa3d2027339cd0f1195c7", @@ -227,6 +303,14 @@ "index": "pypi", "version": "==6.0.0" }, + "iniconfig": { + "hashes": [ + "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3", + "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374" + ], + "markers": "python_version >= '3.7'", + "version": "==2.0.0" + }, "mccabe": { "hashes": [ "sha256:348e0240c33b60bbdf4e523192ef919f28cb2c3d7d5c7794f74009290f236325", @@ -235,6 +319,22 @@ "markers": "python_version >= '3.6'", "version": "==0.7.0" }, + "packaging": { + "hashes": [ + "sha256:714ac14496c3e68c99c29b00845f7a2b85f3bb6f1078fd9f72fd20f0570002b2", + "sha256:b6ad297f8907de0fa2fe1ccbd26fdaf387f5f47c7275fedf8cce89f99446cf97" + ], + "markers": "python_version >= '3.7'", + "version": "==23.0" + }, + "pluggy": { + "hashes": [ + "sha256:4224373bacce55f955a878bf9cfa763c1e360858e330072059e10bad68531159", + "sha256:74134bbf457f031a36d68416e1509f34bd5ccc019f0bcc952c7b909d06b37bd3" + ], + "markers": "python_version >= '3.6'", + "version": "==1.0.0" + }, "pycodestyle": { "hashes": [ "sha256:347187bdb476329d98f695c213d7295a846d1152ff4fe9bacb8a9590b8ee7053", @@ -251,6 +351,22 @@ "markers": "python_version >= '3.6'", "version": "==3.0.1" }, + "pytest": { + "hashes": [ + "sha256:130328f552dcfac0b1cec75c12e3f005619dc5f874f0a06e8ff7263f0ee6225e", + "sha256:c99ab0c73aceb050f68929bc93af19ab6db0558791c6a0715723abe9d0ade9d4" + ], + "index": "pypi", + "version": "==7.2.2" + }, + "pytest-cov": { + "hashes": [ + "sha256:2feb1b751d66a8bd934e5edfa2e961d11309dc37b73b0eabe73b5945fee20f6b", + "sha256:996b79efde6433cdbd0088872dbc5fb3ed7fe1578b68cdbba634f14bb8dd0470" + ], + "index": "pypi", + "version": "==4.0.0" + }, "tomli": { "hashes": [ "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc", diff --git a/ecs/jskult-batch-daily/README.md b/ecs/jskult-batch-daily/README.md index c0bfb248..d0f37149 100644 --- a/ecs/jskult-batch-daily/README.md +++ b/ecs/jskult-batch-daily/README.md @@ -7,67 +7,212 @@ ## 環境情報 - Python 3.9 -- MySQL 8.x +- MySQL 8.23 - VSCode ## 環境構築 -- Pythonの構築 - - Merck_NewDWH開発2021のWiki、[Python環境構築](https://nds-tyo.backlog.com/alias/wiki/1874930)を参照 - - 「Pipenvの導入」までを行っておくこと - - 構築完了後、プロジェクト配下で以下のコマンドを実行し、Pythonの仮想環境を作成する - - `pipenv install --python ` - - この手順で出力される仮想環境のパスは、後述するVSCodeの設定手順で使用するため、控えておく +- Python の構築 -- MySQLの環境構築 - - Windowsの場合、以下のリンクからダウンロードする + - Merck_NewDWH 開発 2021 の Wiki、[Python 環境構築](https://nds-tyo.backlog.com/alias/wiki/1874930)を参照 + - 「Pipenv の導入」までを行っておくこと + - 構築完了後、プロジェクト配下で以下のコマンドを実行し、Python の仮想環境を作成する + - `pipenv install --dev --python ` + - この手順で出力される仮想環境のパスは、後述する VSCode の設定手順で使用するため、控えておく + +- MySQL の環境構築 + - Windows の場合、以下のリンクからダウンロードする - - - Dockerを利用する場合、「newsdwh-tools」リポジトリのMySQL設定を使用すると便利 + - Docker を利用する場合、「newsdwh-tools」リポジトリの MySQL 設定を使用すると便利 - 「crm-table-to-ddl」フォルダ内で以下のコマンドを実行すると - `docker-compose up -d` - - Dockerの構築手順は、[Dockerのセットアップ手順](https://nds-tyo.backlog.com/alias/wiki/1754332)を参照のこと + - 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コマンドを使用して復元する + - [ローカル開発用データ](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の設定 + - 環境変数を設定する。設定内容は PRJ メンバーより共有を受けてください +- VSCode の設定 - 「.vscode/recommended_settings.json」ファイルをコピーし、「settings.json」ファイルを作成する - - 「python.defaultInterpreterPath」を、Pythonの構築手順で作成した仮想環境のパスに変更する + - 「python.defaultInterpreterPath」を、Python の構築手順で作成した仮想環境のパスに変更する ## 実行 -- VSCode上で「F5」キーを押下すると、バッチ処理が起動する。 +- VSCode 上で「F5」キーを押下すると、バッチ処理が起動する。 - 「entrypoint.py」が、バッチ処理のエントリーポイント。 - 実際の処理は、「src/jobctrl_daily.py」で行っている。 +## 単体テスト + +アルトマーク取込処理は、単体テストコードを使用してテスト自動化を行う + +### テスト準備 + +- VSCodeで以下の拡張機能をインストールする + - Python + - Python Test Explorer for Visual Studio Code + - Test Explorer UI +- VSCode 上でショートカット「ctrl」+「shift」+「P」でコマンドパレットを開く +- コマンドパレットの検索窓に「Python」と入力し、「Python: テストを構成する」を押下する +- 現在のワークスペースを選び、「pytest」を選択する +- 「tests」フォルダを選択する +- バックグランドで、pytest モジュールのインストールが始まれば成功 + +### テスト用のサブコマンド一覧 + +- `pipenv run`のあとに、サブコマンドとしてユーザー定義スクリプトを実行できる + - `Pipfile`内の「scripts」セクションに宣言されている + +| コマンド | 概要 | +| ---------------- | -------------------------------------------------------------------------------------------- | +| test:ultmarc | tests/batch/ultmarc フォルダ配下のユニットテストを実行する | +| test:ultmarc:cov | tests/batch/ultmarc フォルダ配下のユニットテストを実行し、テストカバレッジを取得する(C1, C2) | + +### テスト共通関数の仕様 + +- tests/testing_utility.py内の共通関数の仕様について記載する + +#### create_ultmarc_test_data_from_csv + +- 引数 + - file_path: str +- 戻り値 + - src.batch.ultmarc.datfile.DatFileのインスタンス +- 処理概要 + - CSVファイルから、アルトマークのインプットデータを作成する + - データフォーマットは以下 + - 文字コード: UTF-8 + - 改行コード:LF + - ヘッダ: なし + - 値囲い: ダブルクォート + - アルトマークデータと文字コードを合わせるため、指定されたファイルを一時ディレクトリに、文字コード「cp932」で書き出してからテストデータとして読み込む + - テストデータそのものはUTF-8の文字コードで作成すること + +### create_db_data_from_csv + +- 引数 + - file_path: str +- 戻り値 + - テーブルのレコードに相当する辞書のリスト +- 処理概要 + - CSVファイルから、アルトマークテーブルに相当するテストデータを作成する + - テストの初期データ、期待値データを作成するのに利用する + - データフォーマットは以下 + - 文字コード: UTF-8 + - 改行コード:LF + - ヘッダ: なし + - 値囲い: ダブルクォート + - ファイル内の、以下の形式のデータを自動的に変換する + - `NULL` + - `None`に変換される + - `yyyy-mm-dd`もしくは、`yyyy/mm/dd`の文字 + - Date型に変換される + - `yyyy-mm-dd hh:mm:ss`もしくは、`yyyy/mm/dd hh:mm:ss`の文字 + - DateTime型に変換される + +### create_insert_sql_with_parameter + +- 引数 + - table_name: str テーブル名 + - column_names: list[str] カラム名のリスト + - test_data: list[str]: 値のリスト +- 戻り値 + - INSERT文とバインドパラメータ辞書 +- 処理概要 + - 引数を使用して、`src.db.Database#execute`メソッドで実行可能な形でINSERT文、バインドパラメータを作成する + +### create_delete_sql_with_parameter + +- 引数 + - table_name: str テーブル名 + - column_names: list[str] カラム名のリスト + - test_data: list[str]: 値のリスト +- 戻り値 + - DELETE文とバインドパラメータ辞書 +- 処理概要 + - 引数を使用して、`src.db.Database#execute`メソッドで実行可能な形でDELETE文、バインドパラメータを作成する + +### create_ultmarc_table_mapper_sut + +- 引数 + - line: src.batch.ultmarc.datfile.DatFileLine アルトマークデータファイルの1行 + - db: src.db.Database データベース操作クラス +- 戻り値 + - マッパークラス +- 処理概要 + - src.batch.ultmarc.utmp_tables.ultmarc_table_mapper_factory.UltmarcTableMapperFactoryを通じて、テスト対象のマッパークラスを生成して返す + +### assert_table_results + +- 引数 + - actual_rows: list[dict] テスト結果の辞書リスト + - expect_rows: list[dict] 期待値の辞書リスト + - ignore_col_name: list 比較を無視するDBのカラム名. Default None. +- 戻り値 + - なし +- 処理概要 + - テスト結果データと期待値データを突き合わせ、期待値どおりとなっているかを確認する + - ignore_col_nameに指定したカラムは、呼び出し元のテストコード内で個別に突き合わせする + ## フォルダ構成 ```text . -├── Pipfile -- Pythonモジュールの依存関係を管理するファイル -├── Dockerfile -- Dockerイメージを作成するためのファイル -├── Pipfile -- Pythonモジュールの依存関係を管理するファイル -├── Pipfile.lock -- Pythonモジュールの依存関係バージョン固定用ファイル -├── README.md -- 当ファイル -├── entrypoint.py -- バッチ処理のエントリーポイントになるpythonファイル -└── src -- ソースコードの保管場所 - ├── batch -- バッチ処理関連ソース置き場 - │ ├── batch_functions.py -- バッチ処理共通関数置き場 - │ ├── datachange -- 実績洗替関連ソース置き場 - │ │ └── emp_chg_inst_lau.py -- 施設担当者マスタ洗替 - │ └── jissekiaraigae.py -- 実績洗替処理のエントリーポイント - ├── db - │ └── database.py -- データベース操作共通処理 - ├── error - │ └── exceptions.py -- カスタム例外 - ├── jobctrl_daily.py -- 日次バッチ処理のエントリーポイント。「entrypoint.py」 から呼ばれる。 - ├── logging - │ └── get_logger.py -- ログ出力の共通処理 - ├── system_var - │ └── environment.py -- 環境変数 - └── time - └── elapsed_time.py -- 実行時間計測用 +├── Pipfile -- Pythonモジュールの依存関係を管理するファイル +├── Dockerfile -- Dockerイメージを作成するためのファイル +├── Pipfile -- Pythonモジュールの依存関係を管理するファイル +├── Pipfile.lock -- Pythonモジュールの依存関係バージョン固定用ファイル +├── README.md -- 当ファイル +├── entrypoint.py -- バッチ処理のエントリーポイントになるpythonファイル +├── src -- ソースコードの保管場所 +│ ├── aws -- AWS関連処理 +│ │ └── s3.py -- S3クライアントとバケット処理 +│ ├── batch -- バッチ処理関連ソース置き場 +│ │ ├── batch_functions.py -- バッチ処理共通関数置き場 +│ │ ├── datachange -- 実績洗替関連ソース置き場 +│ │ │ └── emp_chg_inst_lau.py -- 施設担当者マスタ洗替 +│ │ └── jissekiaraigae.py -- 実績洗替処理のエントリーポイント +│ │ └── ultmarc -- アルトマーク関連処理 +│ │ ├── ultmarc_process.py -- アルトマーク関連処理のエントリーポイント +│ │ ├── datfile.py -- データファイル読込 +│ │ └── utmp_tables -- アルトマークテーブルへの登録関連 +│ │ ├── table_mapper -- テーブルへのデータマッピング処理 +│ │ │ ├── concrete -- テーブルマッパーのマッピング処理を行う具象クラス(全テーブル分) +│ │ │ │ ├── com_alma_mapper.py +│ │ │ │ ├── ... +│ │ │ │ └── null_mapper.py -- テスト用、空振りするマッパークラス +│ │ │ └── ultmarc_table_mapper.py -- テーブルへの登録処理を行う抽象クラス +│ │ ├── tables -- アルトマークデータのDTOクラス(全テーブル分) +│ │ │ ├── com_alma.py +│ │ │ ├── ... +│ │ │ └── ultmarc_table.py -- アルトマークテーブルの抽象クラス +│ │ └── ultmarc_table_mapper_factory.py -- テーブルマッパー生成クラス +│ ├── db +│ │ └── database.py -- データベース操作共通処理 +│ ├── error +│ │ └── exceptions.py -- カスタム例外 +│ ├── jobctrl_daily.py -- 日次バッチ処理のエントリーポイント。「entrypoint.py」 から呼ばれる。 +│ ├── logging +│ │ └── get_logger.py -- ログ出力の共通処理 +│ ├── system_var +│ │ └── environment.py -- 環境変数 +│ └── time +│ └── elapsed_time.py -- 実行時間計測用 +└── tests -- ユニットテストのルートディレクト + ├── batch + │ └── ultmarc -- アルトマーク関連のユニットテストを格納する + │ └── utmp_tables + │ └── table_mapper -- 以下、マッパークラス単位でフォルダを切る + │ └── com_alma + │ ├── test_com_alma_mapper.py -- テストコード本体 + │ ├── com_alma_insert.csv -- S3に配置される想定のテストCSVデータ。ケースごとに用意する。 + │ ... + │ ├── db_com_alma_before_update.csv -- テスト時に事前にDBに登録しておくデータ。CSVで用意する。 + │ ... + │ ├── expect_com_alma_insert.csv -- テストの期待値データ。CSVで用意する。 + │ ... + ├── conftest.py -- テスト内で共通利用できるフィクスチャを宣言する(執筆時点ではDBのみ) + └── testing_utility.py -- テストの共通関数 ``` diff --git a/ecs/jskult-batch-daily/pytest.ini b/ecs/jskult-batch-daily/pytest.ini new file mode 100644 index 00000000..5dbe2661 --- /dev/null +++ b/ecs/jskult-batch-daily/pytest.ini @@ -0,0 +1,3 @@ +[pytest] +log_format = %(levelname)s %(asctime)s %(message)s +log_date_format = %Y-%m-%d %H:%M:%S diff --git a/ecs/jskult-batch-daily/src/aws/__init__.py b/ecs/jskult-batch-daily/src/aws/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/ecs/jskult-batch-daily/src/aws/s3.py b/ecs/jskult-batch-daily/src/aws/s3.py new file mode 100644 index 00000000..43460f8d --- /dev/null +++ b/ecs/jskult-batch-daily/src/aws/s3.py @@ -0,0 +1,84 @@ +import os.path as path +import tempfile + +import boto3 + +from src.system_var import environment + + +class S3Client: + __s3_client = boto3.client('s3') + _bucket_name: str + + def list_objects(self, bucket_name: str, folder_name: str): + response = self.__s3_client.list_objects_v2(Bucket=bucket_name, Prefix=folder_name) + if response['KeyCount'] == 0: + return [] + contents = response['Contents'] + # 末尾がスラッシュで終わるものはフォルダとみなしてスキップする + objects = [{'filename': content['Key'], 'size': content['Size']} for content in contents if not content['Key'].endswith('/')] + return objects + + def copy(self, src_bucket: str, src_key: str, dest_bucket: str, dest_key: str) -> None: + copy_source = {'Bucket': src_bucket, 'Key': src_key} + self.__s3_client.copy(copy_source, dest_bucket, dest_key) + return + + def download_file(self, bucket_name: str, file_key: str, file): + self.__s3_client.download_fileobj( + Bucket=bucket_name, + Key=file_key, + Fileobj=file + ) + return + + def upload_file(self, local_file_path: str, bucket_name: str, file_key: str): + self.__s3_client.upload_file( + local_file_path, + Bucket=bucket_name, + Key=file_key + ) + + def delete_file(self, bucket_name: str, file_key: str): + self.__s3_client.delete_object( + Bucket=bucket_name, + Key=file_key + ) + + +class S3Bucket(): + _s3_client = S3Client() + _bucket_name: str = None + + +class UltmarcBucket(S3Bucket): + _bucket_name = environment.ULTMARC_DATA_BUCKET + _folder = environment.ULTMARC_DATA_FOLDER + + def list_dat_file(self): + return self._s3_client.list_objects(self._bucket_name, self._folder) + + def download_dat_file(self, dat_filename: str): + # 一時ファイルとして保存する + temporary_dir = tempfile.mkdtemp() + temporary_file_path = path.join(temporary_dir, f'{dat_filename.replace(f"{self._folder}/", "")}') + with open(temporary_file_path, mode='wb') as f: + self._s3_client.download_file(self._bucket_name, dat_filename, f) + f.seek(0) + return temporary_file_path + + def backup_dat_file(self, dat_file_key: str, datetime_key: str): + ultmarc_backup_bucket = UltmarcBackupBucket() + backup_key = f'{ultmarc_backup_bucket._folder}/{datetime_key}/{dat_file_key.replace(f"{self._folder}/", "")}' + self._s3_client.copy(self._bucket_name, dat_file_key, ultmarc_backup_bucket._bucket_name, backup_key) + + def delete_dat_file(self, dat_file_key: str): + self._s3_client.delete_file(self._bucket_name, dat_file_key) + + +class JskUltBackupBucket(S3Bucket): + _bucket_name = environment.ULTMARC_BACKUP_BUCKET + + +class UltmarcBackupBucket(JskUltBackupBucket): + _folder = environment.ULTMARC_BACKUP_FOLDER diff --git a/ecs/jskult-batch-daily/src/batch/batch_functions.py b/ecs/jskult-batch-daily/src/batch/batch_functions.py index b6b06458..0e8a78fa 100644 --- a/ecs/jskult-batch-daily/src/batch/batch_functions.py +++ b/ecs/jskult-batch-daily/src/batch/batch_functions.py @@ -53,4 +53,4 @@ def logging_sql(logger, sql): logger (logging.Logger): ロガー sql (str): SQL文 """ - logger.debug(f'\n{"-"*15}\n{textwrap.dedent(sql)[1:-1]}\n{"-"*15}') \ No newline at end of file + logger.debug(f'\n{"-"*15}\n{textwrap.dedent(sql)[1:-1]}\n{"-"*15}') diff --git a/ecs/jskult-batch-daily/src/batch/common/batch_config.py b/ecs/jskult-batch-daily/src/batch/common/batch_config.py new file mode 100644 index 00000000..e1db0417 --- /dev/null +++ b/ecs/jskult-batch-daily/src/batch/common/batch_config.py @@ -0,0 +1,10 @@ +class BatchConfig: + # 処理日(yyyy/mm/dd形式) + syor_date: str + __instance = None + + @classmethod + def get_instance(cls): + if cls.__instance is None: + cls.__instance = cls() + return cls.__instance diff --git a/ecs/jskult-batch-daily/src/batch/datachange/res_mak_inst_lau.py b/ecs/jskult-batch-daily/src/batch/datachange/create_inst_merge_for_laundering.py similarity index 56% rename from ecs/jskult-batch-daily/src/batch/datachange/res_mak_inst_lau.py rename to ecs/jskult-batch-daily/src/batch/datachange/create_inst_merge_for_laundering.py index bfd359a1..2e03188f 100644 --- a/ecs/jskult-batch-daily/src/batch/datachange/res_mak_inst_lau.py +++ b/ecs/jskult-batch-daily/src/batch/datachange/create_inst_merge_for_laundering.py @@ -2,19 +2,29 @@ from src.db.database import Database from src.error.exceptions import BatchOperationException from src.logging.get_logger import get_logger -logger = get_logger('実績洗替') +logger = get_logger('洗替用マスタ作成') def batch_process(): db = Database.get_instance() + try: db.connect() except Exception as e: - logger.info("実績洗替 データベース接続に失敗") raise BatchOperationException(e) - logger.info('実績洗替 開始') - db.execute('CALL src05.v_inst_merge_t_create()') - db.execute('CALL src05.inst_merge_t_create()') + logger.info('処理開始') + call_v_inst_merge_t_create(db) + call_inst_merge_t_create(db) db.disconnect() - logger.info('実績洗替 終了') + logger.info('処理終了') + + +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 diff --git a/ecs/jskult-batch-daily/src/batch/datachange/emp_chg_inst_lau.py b/ecs/jskult-batch-daily/src/batch/datachange/emp_chg_inst_lau.py index 252b6e17..64a6a363 100644 --- a/ecs/jskult-batch-daily/src/batch/datachange/emp_chg_inst_lau.py +++ b/ecs/jskult-batch-daily/src/batch/datachange/emp_chg_inst_lau.py @@ -1,18 +1,21 @@ -from src.batch.batch_functions import get_syor_date_as_date_format, logging_sql +from src.batch.batch_functions import logging_sql +from src.batch.common.batch_config import BatchConfig from src.db.database import Database from src.error.exceptions import BatchOperationException from src.logging.get_logger import get_logger from src.time.elapsed_time import ElapsedTime logger = get_logger('48-施設担当者マスタ洗替') +batch_config = BatchConfig.get_instance() + def batch_process(): db = Database.get_instance() db.connect() logger.info('##########################') logger.info('START Changing Employee in charge of institution PGM.') - # 日付テーブルを取得 - syor_date = get_syor_date_as_date_format(db) + # 業務日付を取得 + syor_date = batch_config.syor_date # `emp_chg_inst_lau`をTruncate truncate_emp_chg_inst_lau(db) # emp_chg_inst から、`emp_chg_inst_lau`へInsert @@ -37,6 +40,7 @@ def truncate_emp_chg_inst_lau(db: Database): logger.info("Table `emp_chg_inst_lau` was truncated!") return + def insert_into_emp_chg_inst_lau_from_emp_chg_inst(db: Database): logger.info("##########################") try: @@ -44,7 +48,7 @@ def insert_into_emp_chg_inst_lau_from_emp_chg_inst(db: Database): sql = """ INSERT INTO src05.emp_chg_inst_lau - SELECT + SELECT inst_cd, ta_cd,emp_cd, bu_cd, @@ -69,9 +73,10 @@ def insert_into_emp_chg_inst_lau_from_emp_chg_inst(db: Database): logger.info("Error! Insert into `emp_chg_inst_lau` from `emp_chg_inst` was failed!!!") raise BatchOperationException(e) logger.info("Success! Insert into `emp_chg_inst_lau` from `emp_chg_inst` was inserted!") - + return + def update_emp_chg_inst_lau_from_vop_hco_merge_v(db: Database, syor_date: str): # vop_hco_merge_vはデータが作られないため、この洗い替え処理は基本空振りする logger.info("##########################") @@ -94,7 +99,7 @@ def update_emp_chg_inst_lau_from_vop_hco_merge_v(db: Database, syor_date: str): if count == 0: logger.info('vop_hco_merge_v Table Data is not exists!') return - + logger.info('vop_hco_merge_v Table Data is exists!') # vop_hco_merge_v から、emp_chg_inst_lauをUpdateします result = db.execute_select( @@ -102,11 +107,11 @@ def update_emp_chg_inst_lau_from_vop_hco_merge_v(db: Database, syor_date: str): SELECT v_inst_cd, v_inst_cd_merg - FROM + FROM src05.vop_hco_merge_v WHERE STR_TO_DATE(apply_dt, '%Y-%m-%d') <= :syor_date - ORDER BY + ORDER BY STR_TO_DATE(apply_dt, '%Y-%m-%d') ASC """, {'syor_date': syor_date} @@ -153,7 +158,7 @@ def update_dcf_inst_merge_from_emp_chg_inst_lau(db: Database, syor_date: str): muko_flg = '0' AND dcf_inst_cd_new IS NOT NULL AND enabled_flg = 'Y' - AND STR_TO_DATE(CONCAT(tekiyo_month, '01'), '%Y%m%d') <= :syor_date -- TODO: tekiyo_monthはいっぴにする + AND STR_TO_DATE(CONCAT(tekiyo_month, '01'), '%Y%m%d') <= :syor_date """, {'syor_date': syor_date} ) @@ -164,27 +169,27 @@ def update_dcf_inst_merge_from_emp_chg_inst_lau(db: Database, syor_date: str): if count == 0: logger.info('dcf_inst_merge Table Data is not exists!') return - + logger.info('dcf_inst_merge Table Data is exists!') # dcf_inst_mergeから、emp_chg_inst_lauをUpdate logger.info("##########################") logger.info("#### UPDATE DATA #########") - logger.info("##########################") + logger.info("##########################") try: elapsed_time = ElapsedTime() update_sql = """ UPDATE src05.emp_chg_inst_lau el, ( - SELECT + SELECT dcf_inst_cd, - dcf_inst_cd_new + dcf_inst_cd_new FROM src05.dcf_inst_merge - WHERE - muko_flg = '0' - AND dcf_inst_cd_new IS NOT NULL - AND enabled_flg = 'Y' + WHERE + muko_flg = '0' + AND dcf_inst_cd_new IS NOT NULL + AND enabled_flg = 'Y' AND STR_TO_DATE(CONCAT(tekiyo_month, '01'), '%Y%m%d') <= :syor_date ) dm SET @@ -204,5 +209,5 @@ def update_dcf_inst_merge_from_emp_chg_inst_lau(db: Database, syor_date: str): raise BatchOperationException(e) logger.info("emp_chg_inst_lau.v_inst_cd was set!") - + return diff --git a/ecs/jskult-batch-daily/src/batch/jissekiaraigae.py b/ecs/jskult-batch-daily/src/batch/jissekiaraigae.py index 93895f77..be7e6384 100644 --- a/ecs/jskult-batch-daily/src/batch/jissekiaraigae.py +++ b/ecs/jskult-batch-daily/src/batch/jissekiaraigae.py @@ -1,5 +1,5 @@ from src.batch.datachange import emp_chg_inst_lau -from src.batch.datachange import res_mak_inst_lau +from src.batch.datachange import create_inst_merge_for_laundering from src.logging.get_logger import get_logger logger = get_logger('実績洗替') @@ -9,6 +9,6 @@ def batch_process(): """実績洗替処理""" logger.info('Start Jisseki Araigae Batch PGM.') # 洗替用マスタ作成 - res_mak_inst_lau.batch_process() + create_inst_merge_for_laundering.batch_process() # 施設担当者洗替 emp_chg_inst_lau.batch_process() diff --git a/ecs/jskult-batch-daily/src/batch/ultmarc/__init__.py b/ecs/jskult-batch-daily/src/batch/ultmarc/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/ecs/jskult-batch-daily/src/batch/ultmarc/datfile.py b/ecs/jskult-batch-daily/src/batch/ultmarc/datfile.py new file mode 100644 index 00000000..2631eaff --- /dev/null +++ b/ecs/jskult-batch-daily/src/batch/ultmarc/datfile.py @@ -0,0 +1,60 @@ +import csv +from io import TextIOWrapper + + +class DatFileLine: + layout_class: str + records: list[str] + + def __init__(self, dat_line: list[str]) -> None: + self.layout_class = dat_line[0] + self.records = dat_line + + +class DatFile: + """アルトマークデータファイル""" + + lines: list[DatFileLine] + success_count: int = 0 + error_count: int = 0 + total_count: int = 0 + __i: int = 0 + + def __iter__(self): + return self + + def __next__(self) -> DatFileLine: + if self.__i == len(self.lines): + raise StopIteration() + line = self.lines[self.__i] + self.__i += 1 + return line + + def __init__(self, file: TextIOWrapper) -> None: + reader = csv.reader(file) + csv_rows = [DatFileLine(row) for row in reader] + + self.lines = csv_rows + self.total_count = len(csv_rows) + + def count_up_success(self): + self.success_count += 1 + + def count_up_error(self): + self.error_count += 1 + + @classmethod + def from_path(cls, local_file_path: str): + """アルトマークデータファイルを読み込み、新しいインスタンスを作成する + + Args: + local_file_path (str): ローカルのファイルパス + + Returns: + DatFile: このクラスのインスタンス + """ + # cp932(Shift-JIS Windows拡張)でファイルを読み込む + file = open(local_file_path, encoding='cp932') + instance = cls(file) + file.close() + return instance diff --git a/ecs/jskult-batch-daily/src/batch/ultmarc/ultmarc_process.py b/ecs/jskult-batch-daily/src/batch/ultmarc/ultmarc_process.py new file mode 100644 index 00000000..42bc6af6 --- /dev/null +++ b/ecs/jskult-batch-daily/src/batch/ultmarc/ultmarc_process.py @@ -0,0 +1,99 @@ +"""アルトマークデータ保管""" + +from src.aws.s3 import UltmarcBucket +from src.batch.common.batch_config import BatchConfig +from src.batch.ultmarc.datfile import DatFile +from src.batch.ultmarc.utmp_tables.ultmarc_table_mapper_factory import \ + UltmarcTableMapperFactory +from src.db.database import Database +from src.logging.get_logger import get_logger + +logger = get_logger('アルトマークデータ保管') +ultmarc_bucket = UltmarcBucket() +batch_config = BatchConfig.get_instance() + + +def exec_import(): + """アルトマーク取り込み処理""" + try: + logger.info('アルトマーク取込処理: 開始') + # datファイルをS3から取得する + dat_file_list = ultmarc_bucket.list_dat_file() + + # ファイルがない場合は処理せず、正常終了とする + if len(dat_file_list) == 0: + logger.info('ファイルがないため、アルトマーク取込処理をスキップします') + return + + # ファイルが複数ある場合はエラーとする + if len(dat_file_list) > 1: + logger.error(f'複数の取込ファイルがあるため、異常終了 ファイル一覧:{dat_file_list}') + return + + # ファイルの件数は必ず1件になる + dat_file_info = dat_file_list[0] + # 0Byteの場合、 + if dat_file_info['size'] == 0: + logger.info(f'0Byteファイルのため、処理をスキップします。ファイル名={dat_file_info["filename"]}') + return + + dat_file_name = dat_file_info['filename'] + logger.info(f"{dat_file_name}を取り込みます") + # ファイルをバックアップ + # 現行は、jobctrl_dailyの先頭でやっている + ultmarc_bucket.backup_dat_file(dat_file_name, batch_config.syor_date) + # datファイルをダウンロード + local_file_path = ultmarc_bucket.download_dat_file(dat_file_name) + dat_file = DatFile.from_path(local_file_path) + # アルトマーク取り込み実行 + _import_to_ultmarc_table(dat_file) + # 処理後、ファイルをS3から削除する + logger.info(f'取り込み処理が完了したため、datファイルを削除。ファイル名={dat_file_name}') + ultmarc_bucket.delete_dat_file(dat_file_name) + except Exception as e: + logger.exception(e) + raise e + finally: + logger.info('アルトマーク取込処理: 終了') + + +def _import_to_ultmarc_table(dat_file: DatFile): + db = Database.get_instance() + # DB接続 + db.connect() + # ファイル単位でトランザクションを行う + db.begin() + logger.info('Transaction BEGIN') + mapper_factory = UltmarcTableMapperFactory() + # datファイルを1行ずつ処理し、各テーブルへ登録 + for line in dat_file: + try: + # 書き込み先のテーブルを特定 + mapper_class = mapper_factory.create( + line.layout_class, + line.records, + db + ) + mapper_class.make_query() + mapper_class.execute_queries() + dat_file.count_up_success() + except Exception as e: + logger.warning(e) + record = line.records + log_message = ','.join([f'"{r}"' for r in record]) + logger.warning(f'ERROR_LINE: {log_message}') + dat_file.count_up_error() + # すべての行を登録終えたらコミットする + db.commit() + db.disconnect() + # 処理結果をログに出力する + logger.info('Transaction COMMIT') + logger.info(f'ultmarc import process RESULT') + logger.info(f'SUCCESS_COUNT={dat_file.success_count}') + logger.info(f'ERROR_COUNT={dat_file.error_count}') + logger.info(f'ALL_COUNT={dat_file.total_count}') + + # 1件でもエラーがあれば、通知用にログに出力する + if dat_file.error_count > 0: + logger.warning('取り込みに失敗した行があります。詳細は`ERROR_LINE:`の行を確認してください。') + return diff --git a/ecs/jskult-batch-daily/src/batch/ultmarc/utmp_tables/__init__.py b/ecs/jskult-batch-daily/src/batch/ultmarc/utmp_tables/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/ecs/jskult-batch-daily/src/batch/ultmarc/utmp_tables/table_mapper/concrete/__init__.py b/ecs/jskult-batch-daily/src/batch/ultmarc/utmp_tables/table_mapper/concrete/__init__.py new file mode 100644 index 00000000..b0f23166 --- /dev/null +++ b/ecs/jskult-batch-daily/src/batch/ultmarc/utmp_tables/table_mapper/concrete/__init__.py @@ -0,0 +1,8 @@ +import glob +import os + +# 同階層内のモジュールを一括でインポート +__all__ = [ + os.path.split(os.path.splitext(file)[0])[1] + for file in glob.glob(os.path.join(os.path.dirname(__file__), '[a-zA-Z0-9]*.py')) +] \ No newline at end of file diff --git a/ecs/jskult-batch-daily/src/batch/ultmarc/utmp_tables/table_mapper/concrete/com_alma_mapper.py b/ecs/jskult-batch-daily/src/batch/ultmarc/utmp_tables/table_mapper/concrete/com_alma_mapper.py new file mode 100644 index 00000000..5963aa3f --- /dev/null +++ b/ecs/jskult-batch-daily/src/batch/ultmarc/utmp_tables/table_mapper/concrete/com_alma_mapper.py @@ -0,0 +1,92 @@ +from src.batch.ultmarc.utmp_tables.table_mapper.ultmarc_table_mapper import \ + UltmarcTableMapper +from src.batch.ultmarc.utmp_tables.tables.com_alma import ComAlma + + +class ComAlmaMapper(UltmarcTableMapper): + """レイアウト区分004: COM_出身校 登録処理""" + + # レコード存在確認SQL + RECORD_EXISTS_QUERY = """\ + SELECT + COUNT(*) AS count_num + FROM + src05.com_alma + WHERE + alma_cd = :alma_cd + """ + # データ登録用SQL + INSERT_QUERY = """\ + INSERT INTO src05.com_alma + ( + alma_cd, + alma, + regist_ymd, + sys_regist_date, + regist_prgm_id, + sys_update_date, + update_prgm_id + ) + VALUES ( + :alma_cd, + :alma, + :execute_date_str_ymd, + :execute_datetime, + :program_name, + :execute_datetime, + :program_name + ) + """ + + UPDATE_QUERY = """\ + UPDATE + src05.com_alma + SET + alma = :alma, + update_ymd = :execute_date_str_ymd, + sys_update_date = :execute_datetime, + update_prgm_id = :program_name + WHERE + alma_cd = :alma_cd + """ + + # 修正区分が「C(削除)」の場合の更新SQL + LOGICAL_DELETE_QUERY = """\ + UPDATE + src05.com_alma + SET + delete_ymd = :execute_date_str_ymd, + sys_update_date = :execute_date_str_ymd, + update_prgm_id = :program_name + WHERE + alma_cd = :alma_cd + """ + record: ComAlma + + def __init__(self, record: list[str], db) -> None: + super().__init__(record, db, ComAlma) + program_name = __name__.split('.')[-1] # 当モジュール名(現行から変わっている) + # モジュール名をクエリパラメータに設定 + self.query_parameter['program_name'] = program_name + # 読み込んだレコード値もクエリパラメータに追加 + self.query_parameter = {**self.query_parameter, **self.record.to_sql_parameter()} + + def make_query(self): + # 修正区分がC(削除)の場合、論理削除 + if self.record.maint_flag == 'C': + self.queries.append(self.LOGICAL_DELETE_QUERY) + return + + # 追加、更新の場合 + self.queries.append(self.__make_upsert_query()) + return + + def __make_upsert_query(self): + # レコードの存在確認 + record_count = self.db.execute_select(self.RECORD_EXISTS_QUERY, self.query_parameter) + # 存在しない場合はInsert + if record_count[0]['count_num'] == 0: + return self.INSERT_QUERY + + # 存在する場合はUpdate + return self.UPDATE_QUERY diff --git a/ecs/jskult-batch-daily/src/batch/ultmarc/utmp_tables/table_mapper/concrete/com_dr_wrkplace_mapper.py b/ecs/jskult-batch-daily/src/batch/ultmarc/utmp_tables/table_mapper/concrete/com_dr_wrkplace_mapper.py new file mode 100644 index 00000000..8b9253a2 --- /dev/null +++ b/ecs/jskult-batch-daily/src/batch/ultmarc/utmp_tables/table_mapper/concrete/com_dr_wrkplace_mapper.py @@ -0,0 +1,257 @@ +from src.batch.ultmarc.utmp_tables.table_mapper.ultmarc_table_mapper import \ + UltmarcTableMapper +from src.batch.ultmarc.utmp_tables.tables.com_dr_wrkplace import ComDrWrkplace + + +class ComDrWrkplaceMapper(UltmarcTableMapper): + """レイアウト区分501-01:COM_医師勤務先 登録処理""" + + # レコード存在確認SQL + RECORD_EXISTS_QUERY = """\ + SELECT + COUNT(*) AS count_num + FROM + src05.com_dr_wrkplace + WHERE + dcf_pcf_dr_cd = :full_dcfdr_code + AND dcf_dsf_inst_cd = :full_hp_code + """ + # COM_所属部課から所属部科カナと所属部科名を取得するSQL + GET_NAME_FROM_COM_BLNG_SEC_QUERY = """\ + SELECT + blng_sec_kana, + blng_sec_name + FROM + src05.com_blng_sec + WHERE + blng_sec_cd = :sectcode + """ + # データ登録用SQL + INSERT_QUERY = """\ + INSERT INTO src05.com_dr_wrkplace ( + dcf_dsf_inst_cd, + dcf_pcf_dr_cd, + blng_sec_cd, + post_cd, + identity_cd, + aply_start_ymd, + blng_sec_name_kana, + blng_sec_name, + notdm_flg, + regist_ymd, + sys_regist_date, + regist_prgm_id, + sys_update_date, + update_prgm_id + ) + VALUES ( + :full_hp_code, + :full_dcfdr_code, + :sectcode, + :postcode, + :identitycode, + :syor_date, + :sectname_kana, + :sectname, + :notdm_flg, + :execute_date_str_ymd, + :execute_datetime, + :program_name, + :execute_datetime, + :program_name + ) + """ + + # 更新用SQL + UPDATE_QUERY = """\ + UPDATE src05.com_dr_wrkplace + SET + {update_columns} + update_ymd = :execute_date_str_ymd, + sys_update_date = :execute_datetime, + update_prgm_id = :program_name + WHERE + DCF_PCF_DR_CD= :full_dcfdr_code + AND DCF_DSF_INST_CD = :full_hp_code + """ + + # 更新・削除の場合に該当のデータを履歴テーブルに退避するSQL + TO_HISTORY_QUERY = """\ + INSERT INTO src05.com_dr_wrkplace_his ( + dcf_dsf_inst_cd, + dcf_pcf_dr_cd, + blng_sec_cd, + post_cd, + identity_cd, + aply_start_ymd, + blng_sec_name_kana, + blng_sec_name, + notdm_flg, + aply_end_ymd, + regist_ymd, + sys_regist_date, + regist_prgm_id, + sys_update_date, + update_prgm_id + ) + SELECT + dcf_dsf_inst_cd, + dcf_pcf_dr_cd, + ( + CASE + WHEN blng_sec_cd = '' THEN '9999' + ELSE blng_sec_cd + END + ) AS blng_sec_cd, + ( + CASE + WHEN post_cd = '' THEN '999' + ELSE post_cd + END + ) AS post_cd, + ( + CASE + WHEN identity_cd = '' THEN '999' + ELSE identity_cd + END + ) AS identity_cd, + DATE_FORMAT(aply_start_ymd, '%Y%m%d'), + blng_sec_name_kana, + blng_sec_name, + notdm_flg, + ( + CASE + WHEN DATE_FORMAT(aply_start_ymd, '%Y%m%d') > DATE_FORMAT(:syor_date, '%Y%m%d') -1 THEN DATE_FORMAT(aply_start_ymd, '%Y%m%d') + ELSE DATE_FORMAT(:syor_date, '%Y%m%d') -1 + END + ) AS aply_end_ymd, + :execute_date_str_ymd, + :execute_datetime, + :program_name, + :execute_datetime, + :program_name + FROM + src05.com_dr_wrkplace + WHERE + dcf_pcf_dr_cd = :full_dcfdr_code + AND dcf_dsf_inst_cd = :full_hp_code + AND aply_start_ymd < :syor_date + """ + + # 退職レコードの場合、物理削除するSQL + PHYSICAL_DELETE_FOR_RETIREMENT_QUERY = """\ + DELETE FROM src05.com_dr_wrkplace + WHERE + dcf_pcf_dr_cd = :full_dcfdr_code + AND dcf_dsf_inst_cd = :full_hp_code + """ + + record: ComDrWrkplace + + def __init__(self, record: list[str], db) -> None: + super().__init__(record, db, ComDrWrkplace) + program_name = __name__.split('.')[-1] # 当モジュール名(現行から変わっている) + # モジュール名をクエリパラメータに設定 + self.query_parameter['program_name'] = program_name + # 読み込んだレコード値もクエリパラメータに追加 + self.query_parameter = {**self.query_parameter, **self.record.to_sql_parameter()} + + def make_query(self): + # 所属部科を取得し、所属部科カナと所属部科名を設定する + self.__set_sect_name_and_sect_name_kana() + # 追加/更新クエリを生成 + # 履歴へのレコード登録もあるため、リストで返る + self.queries = self.__make_queries() + return + + def __set_sect_name_and_sect_name_kana(self): + # 所属部科を取得し、所属部科カナと所属部科名を設定する + com_blng_sec_records = self.db.execute_select(self.GET_NAME_FROM_COM_BLNG_SEC_QUERY, self.query_parameter) + if len(com_blng_sec_records) == 0: + return + # 必ず1件 + com_blng_sec_record = com_blng_sec_records[0] + if com_blng_sec_record['blng_sec_kana'] != '' and com_blng_sec_record['blng_sec_kana'] is not None: + self.record.sectname_kana = com_blng_sec_record['blng_sec_kana'] + self.query_parameter['sectname_kana'] = com_blng_sec_record['blng_sec_kana'] + + if com_blng_sec_record['blng_sec_name'] != '' and com_blng_sec_record['blng_sec_name'] is not None: + self.record.sectname = com_blng_sec_record['blng_sec_name'] + self.query_parameter['sectname'] = com_blng_sec_record['blng_sec_name'] + + def __make_queries(self): + # レコードの存在確認 + record_count = self.db.execute_select(self.RECORD_EXISTS_QUERY, self.query_parameter) + # 存在しない場合はInsert + if record_count[0]['count_num'] == 0: + return [self.INSERT_QUERY] + + # 存在する場合はUpdate + # 予備/退職異動区分が1(削除:退職)の場合、退職済みのレコードとして処理 + if self.record.drretflag == '1': + # 履歴への移動と、退職レコードの物理削除 + return [self.TO_HISTORY_QUERY, self.PHYSICAL_DELETE_FOR_RETIREMENT_QUERY] + + # 履歴への移動+更新クエリ生成 + return self.__make_update_query() + + def __make_update_query(self): + make_history_query = None + # 履歴レコード作成判断となる、UPDATE SET句を作成 + set_clauses_with_historical = self.__make_update_columns_with_historical() + # 履歴レコード作成判断とならない、UPDATE SET句 + set_clause_without_historical = [] + # DM不可フラグの値をセット + # 履歴レコード作成判断とならないため、後から設定 + if self.record.notdm_flg != '': + notdm_flg = None if self.record.notdm_flg == '@' else self.record.notdm_flg + self.query_parameter['notdm_flg'] = notdm_flg + set_clause_without_historical.append(f'notdm_flg = :notdm_flg') + # 何かしら更新がある場合、履歴作成クエリを作成 + if len(set_clauses_with_historical) != 0: + make_history_query = self.TO_HISTORY_QUERY + + update_columns = ','.join(set_clauses_with_historical + set_clause_without_historical) + if len(update_columns) > 0: + # 何かしら更新がある場合、末尾にカンマを付けてSET句を完成させる + update_columns += ',' + + update_query = self.UPDATE_QUERY.format( + update_columns=update_columns + ) + + return [make_history_query, update_query] + + def __make_update_columns_with_historical(self): + # 履歴レコードの作成有無を判断するカラムの更新設定 + # DM不可フラグは、履歴レコードの作成判断に使わないため、この関数の外で判定する + set_clauses = [] + # 役職コード + if self.record.postcode != '': + set_clauses.append('post_cd = :postcode') + self.query_parameter['postcode'] = '' if self.record.postcode == '@' else self.record.postcode + # 大学順位 + if self.record.identitycode != '': + set_clauses.append('identity_cd = :identitycode') + self.query_parameter['identitycode'] = '' if self.record.identitycode == '@' else self.record.identitycode + # 所属部科(集合項目) + if self.record.sectcode != '': + # 所属部科コード + self.query_parameter['sectcode'] = '9999' if self.record.sectcode == '@' else self.record.sectcode + set_clauses.append('blng_sec_cd = :sectcode') + # 所属部科(カナ) + sectname_kana = None if self.record.sectname_kana == '@' else self.record.sectname_kana + self.query_parameter['sectname_kana'] = sectname_kana + set_clauses.append(f'blng_sec_name_kana = :sectname_kana') + # 所属部科(漢字) + # 全角文字なので、修正項目として全角@が連携されるパターンがある + sectname = None if self.record.sectname == '@' else self.record.sectname + self.query_parameter['sectname'] = sectname + set_clauses.append(f'blng_sec_name = :sectname') + + # 何かしら更新がある場合、適用開始日をセットする + if len(set_clauses) != 0: + # 処理日はパラメータに設定済み + set_clauses.append("aply_start_ymd = DATE_FORMAT(:syor_date, '%Y%m%d')") + + return set_clauses diff --git a/ecs/jskult-batch-daily/src/batch/ultmarc/utmp_tables/table_mapper/concrete/com_hamtec_mapper.py b/ecs/jskult-batch-daily/src/batch/ultmarc/utmp_tables/table_mapper/concrete/com_hamtec_mapper.py new file mode 100644 index 00000000..4cb71bbf --- /dev/null +++ b/ecs/jskult-batch-daily/src/batch/ultmarc/utmp_tables/table_mapper/concrete/com_hamtec_mapper.py @@ -0,0 +1,99 @@ +from src.batch.ultmarc.utmp_tables.table_mapper.ultmarc_table_mapper import \ + UltmarcTableMapper +from src.batch.ultmarc.utmp_tables.tables.com_hamtec import ComHamtec + + +class ComHamtecMapper(UltmarcTableMapper): + """レイアウト区分021: COM_高度先進医療 登録処理""" + + # レコード存在確認SQL + RECORD_EXISTS_QUERY = """\ + SELECT + COUNT(*) AS count_num + FROM + src05.com_hamtec + WHERE + hamtec_cd = :hamtec_cd + """ + # データ登録用SQL + INSERT_QUERY = """\ + INSERT INTO src05.com_hamtec + ( + hamtec_cd, + hamtec_div, + hamtec_name, + regist_ymd, + sys_regist_date, + regist_prgm_id, + sys_update_date, + update_prgm_id + ) + VALUES ( + :hamtec_cd, + :hamtec_div, + :hamtec_name, + :execute_date_str_ymd, + :execute_datetime, + :program_name, + :execute_datetime, + :program_name + ) + """ + + UPDATE_QUERY = """\ + UPDATE + src05.com_hamtec + SET + hamtec_div = :hamtec_div, + hamtec_name = :hamtec_name, + update_ymd = :execute_date_str_ymd, + sys_update_date = :execute_datetime, + update_prgm_id = :program_name + WHERE + hamtec_cd = :hamtec_cd + """ + + # 修正区分が「C(削除)」の場合の更新SQL + LOGICAL_DELETE_QUERY = """\ + UPDATE + src05.com_hamtec + SET + delete_ymd = :execute_date_str_ymd, + sys_update_date = :execute_date_str_ymd, + update_prgm_id = :program_name + WHERE + hamtec_cd = :hamtec_cd + """ + record: ComHamtec + + def __init__(self, record: list[str], db) -> None: + super().__init__(record, db, ComHamtec) + program_name = __name__.split('.')[-1] # 当モジュール名(現行から変わっている) + # モジュール名をクエリパラメータに設定 + self.query_parameter['program_name'] = program_name + # 読み込んだレコード値もクエリパラメータに追加 + self.query_parameter = {**self.query_parameter, **self.record.to_sql_parameter()} + + def make_query(self): + # 修正区分がC(削除)の場合、論理削除 + if self.record.maint_flag == 'C': + self.queries.append(self.LOGICAL_DELETE_QUERY) + return + + # 追加、更新の場合 + self.queries.append(self.__make_upsert_query()) + return + + def __make_upsert_query(self): + # レコードの存在確認 + record_count = self.db.execute_select(self.RECORD_EXISTS_QUERY, self.query_parameter) + # 存在しない場合はInsert + if record_count[0]['count_num'] == 0: + return self.INSERT_QUERY + + # 存在する場合はUpdate + # 更新データがある場合のみ更新 + if self.record.hamtec_div != '' or self.record.hamtec_name != '': + return self.UPDATE_QUERY + else: + return None diff --git a/ecs/jskult-batch-daily/src/batch/ultmarc/utmp_tables/table_mapper/concrete/com_inst_mapper.py b/ecs/jskult-batch-daily/src/batch/ultmarc/utmp_tables/table_mapper/concrete/com_inst_mapper.py new file mode 100644 index 00000000..6a34c446 --- /dev/null +++ b/ecs/jskult-batch-daily/src/batch/ultmarc/utmp_tables/table_mapper/concrete/com_inst_mapper.py @@ -0,0 +1,9 @@ +from src.batch.ultmarc.utmp_tables.table_mapper.ultmarc_table_mapper import \ + UltmarcTableMapper + + +class ComInstMapper(UltmarcTableMapper): + """COM_施設 登録処理: TODO""" + + def make_query(self): + self.queries.append(None) diff --git a/ecs/jskult-batch-daily/src/batch/ultmarc/utmp_tables/table_mapper/concrete/null_mapper.py b/ecs/jskult-batch-daily/src/batch/ultmarc/utmp_tables/table_mapper/concrete/null_mapper.py new file mode 100644 index 00000000..9b5d93a1 --- /dev/null +++ b/ecs/jskult-batch-daily/src/batch/ultmarc/utmp_tables/table_mapper/concrete/null_mapper.py @@ -0,0 +1,8 @@ +from src.batch.ultmarc.utmp_tables.table_mapper.ultmarc_table_mapper import \ + UltmarcTableMapper + + +class NullMapper(UltmarcTableMapper): + + def make_query(self): + return super().make_query() diff --git a/ecs/jskult-batch-daily/src/batch/ultmarc/utmp_tables/table_mapper/ultmarc_table_mapper.py b/ecs/jskult-batch-daily/src/batch/ultmarc/utmp_tables/table_mapper/ultmarc_table_mapper.py new file mode 100644 index 00000000..5a62d171 --- /dev/null +++ b/ecs/jskult-batch-daily/src/batch/ultmarc/utmp_tables/table_mapper/ultmarc_table_mapper.py @@ -0,0 +1,50 @@ +from abc import ABCMeta, abstractmethod +from datetime import datetime + +from src.batch.common.batch_config import BatchConfig +from src.batch.ultmarc.utmp_tables.tables.ultmarc_table import UltmarcTable +from src.db.database import Database + +# 処理日を使用するために、configを使用 +batch_config = BatchConfig.get_instance() + + +class UltmarcTableMapper(metaclass=ABCMeta): + """アルトマークテーブルへの登録処理の抽象クラス""" + + record: UltmarcTable + db: Database + queries: list[str] + query_parameter: dict + + def __init__(self, record: list[str], db: Database, table_class: type[UltmarcTable]) -> None: + self.record = table_class(record) + self.db = db + + # 実行年月日(文字列)、実行年月日時分秒を設定 + now = datetime.now() + execute_date_str_ymd = now.strftime('%Y%m%d') + execute_datetime = now.strftime('%Y/%m/%d %H:%M:%S') + # クエリリストを初期化 + self.queries = [] + # 共通クエリパラメータを設定 + self.query_parameter = { + 'execute_date_str_ymd': execute_date_str_ymd, + 'execute_datetime': execute_datetime, + # バッチ共通設定から処理日を取得 + 'syor_date': batch_config.syor_date + } + + @abstractmethod + def make_query(self): + pass + + def execute_queries(self): + if len(self.queries) == 0: + raise Exception('make_queryを呼び出してから実行してください') + + for query in self.queries: + if query is None: + continue + + self.db.execute(query, self.query_parameter) diff --git a/ecs/jskult-batch-daily/src/batch/ultmarc/utmp_tables/tables/__init__.py b/ecs/jskult-batch-daily/src/batch/ultmarc/utmp_tables/tables/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/ecs/jskult-batch-daily/src/batch/ultmarc/utmp_tables/tables/com_alma.py b/ecs/jskult-batch-daily/src/batch/ultmarc/utmp_tables/tables/com_alma.py new file mode 100644 index 00000000..80940b09 --- /dev/null +++ b/ecs/jskult-batch-daily/src/batch/ultmarc/utmp_tables/tables/com_alma.py @@ -0,0 +1,14 @@ +from src.batch.ultmarc.utmp_tables.tables.ultmarc_table import UltmarcTable + + +class ComAlma(UltmarcTable): + """レイアウト区分004: COM_出身校""" + maint_flag: str # 修正区分 + alma_cd: str # 出身校コード + alma: str # 出身校 + + def __init__(self, record: list[str]): + super().__init__(record) + self.maint_flag = record[2] + self.alma_cd = record[1] + self.alma = record[5] diff --git a/ecs/jskult-batch-daily/src/batch/ultmarc/utmp_tables/tables/com_dr_wrkplace.py b/ecs/jskult-batch-daily/src/batch/ultmarc/utmp_tables/tables/com_dr_wrkplace.py new file mode 100644 index 00000000..9472206d --- /dev/null +++ b/ecs/jskult-batch-daily/src/batch/ultmarc/utmp_tables/tables/com_dr_wrkplace.py @@ -0,0 +1,49 @@ +from src.batch.ultmarc.utmp_tables.tables.ultmarc_table import UltmarcTable + + +class ComDrWrkplace(UltmarcTable): + """レイアウト区分501-01:COM_医師勤務先""" + maint_flag: str # 修正区分 + dcfdr_id: str # 個人コード(ID) + dcfdr_code: str # 個人コード(個人コード) + dcfdr_yobi: str # 個人コード(予備) + hp_id: str # 施設コード(ID) + hp_code: str # 施設コード(施設コード) + hp_yobi: str # 施設コード(予備) + drretflag: str # 予備/退職異動区分 + maintdate: str # メンテナンス年月日 + trndate: str # 予備/転送年月日 + postcode: str # 役職コード + identitycode: str # 大学職位 + sectcode: str # 所属部科コード + sectname: str # 所属部科(漢字) + sectname_kana: str # 所属部科(カナ) + notdm_flg: str # DM不可フラグ + full_dcfdr_code: str # 個人ID+個人コード+個人コード予備 + full_hp_code: str # 施設ID+施設コード+施設コード予備 + + def __init__(self, record: list[str]): + super().__init__(record) + self.maintflag = record[4] + self.dcfdr_id = record[1] + self.dcfdr_code = record[2] + self.dcfdr_yobi = record[3].strip() + self.hp_id = record[5] + self.hp_code = record[6] + self.hp_yobi = record[7].strip() + self.drretflag = record[8] + self.maintdate = record[9] + self.trndate = record[10] + self.postcode = record[11].strip() + self.identitycode = record[12].strip() + + # 所属部科の集合項目 + self.sectcode = record[13].strip() + self.sectname = record[14].strip() + self.sectname_kana = record[15].strip() + + self.notdm_flg = record[16].strip() + + # ID、コード、予備を結合してフル桁コードに変換 + self.full_dcfdr_code = ''.join([self.dcfdr_id, self.dcfdr_code, self.dcfdr_yobi]) + self.full_hp_code = ''.join([self.hp_id, self.hp_code, self.hp_yobi]) diff --git a/ecs/jskult-batch-daily/src/batch/ultmarc/utmp_tables/tables/com_hamtec.py b/ecs/jskult-batch-daily/src/batch/ultmarc/utmp_tables/tables/com_hamtec.py new file mode 100644 index 00000000..0eb5ab1c --- /dev/null +++ b/ecs/jskult-batch-daily/src/batch/ultmarc/utmp_tables/tables/com_hamtec.py @@ -0,0 +1,16 @@ +from src.batch.ultmarc.utmp_tables.tables.ultmarc_table import UltmarcTable + + +class ComHamtec(UltmarcTable): + """レイアウト区分021: COM_高度先進医療""" + maint_flag: str # 修正区分 + hamtec_cd: str # 高度先進医療コード + hamtec_div: str # 高度先進医療区分 + hamtec_name: str # 高度先進医療名 + + def __init__(self, record: list[str]): + super().__init__(record) + self.maint_flag = record[3] + self.hamtec_cd = record[1] + self.hamtec_div = record[2] + self.hamtec_name = record[6] diff --git a/ecs/jskult-batch-daily/src/batch/ultmarc/utmp_tables/tables/ultmarc_table.py b/ecs/jskult-batch-daily/src/batch/ultmarc/utmp_tables/tables/ultmarc_table.py new file mode 100644 index 00000000..ebbbc39d --- /dev/null +++ b/ecs/jskult-batch-daily/src/batch/ultmarc/utmp_tables/tables/ultmarc_table.py @@ -0,0 +1,9 @@ +class UltmarcTable: + """アルトマーク関連テーブルの抽象クラス""" + record: list + + def __init__(self, record: list): + self.record = record + + def to_sql_parameter(self): + return vars(self) diff --git a/ecs/jskult-batch-daily/src/batch/ultmarc/utmp_tables/ultmarc_table_mapper_factory.py b/ecs/jskult-batch-daily/src/batch/ultmarc/utmp_tables/ultmarc_table_mapper_factory.py new file mode 100644 index 00000000..ebea9e55 --- /dev/null +++ b/ecs/jskult-batch-daily/src/batch/ultmarc/utmp_tables/ultmarc_table_mapper_factory.py @@ -0,0 +1,107 @@ +from src.batch.ultmarc.utmp_tables.table_mapper.concrete import ( + com_alma_mapper, com_dr_wrkplace_mapper, com_hamtec_mapper, + com_inst_mapper, null_mapper) +from src.batch.ultmarc.utmp_tables.table_mapper.ultmarc_table_mapper import \ + UltmarcTableMapper +from src.db.database import Database + +# テーブルとのマッピング +COM_TABLE_LIST = { + # レコードID固定 + # COM_医師学会 + # TODO: 入れ子にしない + "521": null_mapper.NullMapper, + # COM_施設属性 + "111": null_mapper.NullMapper, + # COM_臨床研修病院 + "112": null_mapper.NullMapper, + # COM_医師 + "501": null_mapper.NullMapper, + # COM_施設 + "101": com_inst_mapper.ComInstMapper, + # COM_薬局 + "102": null_mapper.NullMapper, + # COM_医師勤務先 + "502": com_dr_wrkplace_mapper.ComDrWrkplaceMapper, + # COM_専門分野 + "511": null_mapper.NullMapper, + # COM_都道府県医療機能情報(基本) + "132": null_mapper.NullMapper, + # COM_都道府県医療機能情報(施設設備) + "133": null_mapper.NullMapper, + # COM_都道府県医療機能情報(疾患治療) + "134": null_mapper.NullMapper, + # COM_都道府県医療機能情報(短期滞在手術) + "135": null_mapper.NullMapper, + # COM_都道府県医療機能情報(専門外来) + "136": null_mapper.NullMapper, + # COM_診療科目 + "001": null_mapper.NullMapper, + # COM_病院種別 + "002": null_mapper.NullMapper, + # COM_出身校学部識別 + "003": null_mapper.NullMapper, + # COM_出身校 + "004": com_alma_mapper.ComAlmaMapper, + # COM_役職 + "005": null_mapper.NullMapper, + # 都道府県マスタ + "006": null_mapper.NullMapper, + # COM_経営体 + "007": null_mapper.NullMapper, + # COM_所属部科 + "008": null_mapper.NullMapper, + # COM_学会 + "009": null_mapper.NullMapper, + # COM_専門医資格 + "010": null_mapper.NullMapper, + # COM_施設区分 + "011": null_mapper.NullMapper, + # COM_高度先進医療 + "021": com_hamtec_mapper.ComHamtecMapper, + # COM_先端医療機器 + "022": null_mapper.NullMapper, + # COM_看護種別 + "023": null_mapper.NullMapper, + # COM_医療機能評価 + "024": null_mapper.NullMapper, + # COM_地域クリティカルパス + "026": null_mapper.NullMapper, + # COM_疾患別リハビリテーション科 + "027": null_mapper.NullMapper, + # COM_政策医療 + "028": null_mapper.NullMapper, + # COM_医療圏都道府県 + "121": null_mapper.NullMapper, + # COM_医療圏3次マスタ + "122": null_mapper.NullMapper, + # COM_二次医療圏 + "123": null_mapper.NullMapper, + # COM_医療圏都道府県市町村対照表 + "124": null_mapper.NullMapper +} + + +class UltmarcTableMapperFactory: + + def create(self, layout_class: str, records: list[str], db: Database) -> UltmarcTableMapper: + """レイアウト区分とレコードIDから、マッピング先のテーブルマッパーを特定する + + Args: + layout_class (str): レイアウト区分 + records (list[str]): アルトマークデータの1行 + db (Database): データベース操作クラス + + Raises: + Exception: レイアウトを特定できない場合 + + Returns: + UltmarcTableMapper: マッパークラス + """ + # レイアウト区分から、マッピング先のテーブルを特定 + mapper_class = COM_TABLE_LIST.get(layout_class) + # レイアウト区分が特定できない場合はエラーとする + if mapper_class is None: + raise Exception(f'マッピング先のテーブルを特定できませんでした。レイアウト区分={layout_class}') + + return mapper_class(records, db) diff --git a/ecs/jskult-batch-daily/src/db/database.py b/ecs/jskult-batch-daily/src/db/database.py index 0317bc21..f67a21b9 100644 --- a/ecs/jskult-batch-daily/src/db/database.py +++ b/ecs/jskult-batch-daily/src/db/database.py @@ -1,6 +1,5 @@ from sqlalchemy import (Connection, CursorResult, Engine, QueuePool, create_engine, text) -from sqlalchemy.engine.create import create_engine from sqlalchemy.engine.url import URL from tenacity import retry, stop_after_attempt, wait_exponential @@ -10,6 +9,7 @@ from src.system_var import environment logger = get_logger(__name__) + class Database: """データベース操作クラス""" __connection: Connection = None @@ -19,8 +19,7 @@ class Database: __username: str = None __password: str = None __schema: str = None - __connection_string:str = None - + __connection_string: str = None def __init__(self, username: str, password: str, host: str, port: int, schema: str) -> None: """このクラスの新たなインスタンスを初期化します @@ -37,9 +36,9 @@ class Database: self.__host = host self.__port = int(port) self.__schema = schema - + self.__connection_string = URL.create( - drivername='mysql+pymysql', + drivername='mysql+pymysql', username=self.__username, password=self.__password, host=self.__host, @@ -47,12 +46,11 @@ class Database: database=self.__schema, query={"charset": "utf8mb4"} ) - + self.__engine = create_engine( self.__connection_string, pool_timeout=5, - poolclass=QueuePool, - isolation_level="AUTOCOMMIT" + poolclass=QueuePool ) @classmethod @@ -103,10 +101,18 @@ class Database: """ if self.__connection is None: raise DBException('DBに接続していません') + + result = None try: - result = self.__connection.execute(text(select_query), parameters=parameters) + # トランザクションが開始している場合は、トランザクションを引き継ぐ + 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(e) + raise DBException(f'SQL Error: {e}') + result_rows = result.mappings().all() return result_rows @@ -125,10 +131,18 @@ class Database: """ if self.__connection is None: raise DBException('DBに接続していません') + + result = None try: - result = self.__connection.execute(text(query), parameters=parameters) + # トランザクションが開始している場合は、トランザクションを引き継ぐ + 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(e) + raise DBException(f'SQL Error: {e}') + return result def begin(self): @@ -151,3 +165,14 @@ class Database: 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 diff --git a/ecs/jskult-batch-daily/src/error/exceptions.py b/ecs/jskult-batch-daily/src/error/exceptions.py index 612060c5..c9effa01 100644 --- a/ecs/jskult-batch-daily/src/error/exceptions.py +++ b/ecs/jskult-batch-daily/src/error/exceptions.py @@ -4,11 +4,14 @@ from tenacity import RetryError class MeDaCaException(Exception): pass + class DBException(MeDaCaException): pass + class BatchOperationException(MeDaCaException): pass + class MaxRetryExceededException(MeDaCaException, RetryError): - pass \ No newline at end of file + pass diff --git a/ecs/jskult-batch-daily/src/jobctrl_daily.py b/ecs/jskult-batch-daily/src/jobctrl_daily.py index 7b8cfd38..f91437b5 100644 --- a/ecs/jskult-batch-daily/src/jobctrl_daily.py +++ b/ecs/jskult-batch-daily/src/jobctrl_daily.py @@ -1,10 +1,16 @@ from src.batch import jissekiaraigae -from src.batch.batch_functions import get_syor_date +from src.batch.batch_functions import get_syor_date_as_date_format +from src.batch.common.batch_config import BatchConfig +from src.batch.ultmarc import ultmarc_process from src.error.exceptions import BatchOperationException from src.logging.get_logger import get_logger logger = get_logger('日次処理コントロール') # ここを処理IDとかにするといいかもしれない +# バッチ共通設定を取得 +batch_config = BatchConfig.get_instance() + + def batch_process(): try: logger.info('日次ジョブ:開始') @@ -15,14 +21,16 @@ def batch_process(): # logger.error('データベース接続エラー(異常終了)') # 検査例外を捕まえて、共通的に出せばいいと思う try: logger.info('処理日取得') - syor_date = get_syor_date() - except BatchOperationException as e: + syor_date = get_syor_date_as_date_format() + except BatchOperationException as e: logger.error(f'処理日取得エラー(異常終了){e}') logger.info(f'処理日={syor_date}') + # バッチ共通設定に処理日を追加 + batch_config.syor_date = syor_date # 休日判定ファイルを読み込み logger.info('休日判定処理') if True: # 休日判定 - logger.info('非営業日かつ月、火、水以外です。') # 分岐 + logger.info('非営業日かつ月、火、水以外です。') # 分岐 try: # 処理中フラグ判定。ここでdumpのフラグも見る logger.info('処理フラグ更新中') @@ -32,7 +40,7 @@ def batch_process(): logger.info('日次ジョブ:終了(正常終了)') try: logger.info('日次ジョブ処理中判定') - if True: # 処理中判定 + if True: # 処理中判定 logger.error('処理フラグ処理中(異常終了)') logger.info('処理中フラグの更新:起動') logger.info('処理中フラグの更新:終了') @@ -54,21 +62,22 @@ def batch_process(): logger.debug('卸在庫データファイル名作成: {read_filename}') logger.debug('ファイル移動OK:{_MOVE_OROSHI_ZAIKO}') # S3からダウンロード logger.debug('ファイル解凍OK:{sprintf(_ZIP_OROSHI_ZAIKO, $read_filename)}') # gunzip -fなので、gzipを使う - logger.debug('ファイル名変更OK: {sprintf(_RENAME_OROSHI_ZAIKO, $read_filename)}') #S3にアップロード + logger.debug('ファイル名変更OK: {sprintf(_RENAME_OROSHI_ZAIKO, $read_filename)}') # S3にアップロード try: logger.info('卸在庫データ取込:起動') logger.info('卸在庫データ取込:終了') except BatchOperationException as e: logger.error(f'卸在庫データ取込処理エラー(異常終了){e}') logger.info('日次処理(アルトマーク)') - if True: # アルトマークなければ + if True: # アルトマークなければ logger.info('日次処理(アルトマーク)実行対象日でない為未実行') try: logger.info('アルトマーク取込:起動') + ultmarc_process.exec_import() logger.info('アルトマーク取込:終了') except BatchOperationException as e: logger.error(f'アルトマーク取込処理エラー(異常終了){e}') - if True: # 休日判定 + if True: # 休日判定 try: logger.info('メルク施設マスタ作成') logger.info('メルク施設マスタ作成終了') @@ -83,7 +92,7 @@ def batch_process(): logger.info('V実消化連携データ存在確認') if True: logger.error('V実消化連携データ存在確認(異常終了)') - + logger.info('日次処理(V実消化)') try: logger.info('V実消化取込:起動') @@ -111,7 +120,7 @@ def batch_process(): logger.exception(f'処理中フラグ更新エラー(異常終了){e}') logger.info('ワークディレクトリクリーニング') logger.info('日次ジョブ:終了(正常終了)') - + return 0 except Exception as e: raise e diff --git a/ecs/jskult-batch-daily/src/logging/get_logger.py b/ecs/jskult-batch-daily/src/logging/get_logger.py index 868ab5ea..f36f1199 100644 --- a/ecs/jskult-batch-daily/src/logging/get_logger.py +++ b/ecs/jskult-batch-daily/src/logging/get_logger.py @@ -6,8 +6,16 @@ from src.system_var.environment import LOG_LEVEL for name in ["boto3", "botocore", "s3transfer", "urllib3"]: logging.getLogger(name).setLevel(logging.WARNING) -# 共通ロガー -def get_logger(log_name): + +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): diff --git a/ecs/jskult-batch-daily/src/system_var/environment.py b/ecs/jskult-batch-daily/src/system_var/environment.py index 143d2d26..e7248191 100644 --- a/ecs/jskult-batch-daily/src/system_var/environment.py +++ b/ecs/jskult-batch-daily/src/system_var/environment.py @@ -1,12 +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['LOG_LEVEL'] +# AWS +ULTMARC_DATA_BUCKET = os.environ['ULTMARC_DATA_BUCKET'] +ULTMARC_DATA_FOLDER = os.environ['ULTMARC_DATA_FOLDER'] +ULTMARC_BACKUP_BUCKET = os.environ['ULTMARC_BACKUP_BUCKET'] +ULTMARC_BACKUP_FOLDER = os.environ['ULTMARC_BACKUP_FOLDER'] + +# 初期値がある環境変数 +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)) diff --git a/ecs/jskult-batch-daily/tests/__init__.py b/ecs/jskult-batch-daily/tests/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/ecs/jskult-batch-daily/tests/batch/__init__.py b/ecs/jskult-batch-daily/tests/batch/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/ecs/jskult-batch-daily/tests/batch/ultmarc/__init__.py b/ecs/jskult-batch-daily/tests/batch/ultmarc/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/ecs/jskult-batch-daily/tests/batch/ultmarc/utmp_tables/__init__.py b/ecs/jskult-batch-daily/tests/batch/ultmarc/utmp_tables/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/ecs/jskult-batch-daily/tests/batch/ultmarc/utmp_tables/table_mapper/__init__.py b/ecs/jskult-batch-daily/tests/batch/ultmarc/utmp_tables/table_mapper/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/ecs/jskult-batch-daily/tests/batch/ultmarc/utmp_tables/table_mapper/com_alma/__init__.py b/ecs/jskult-batch-daily/tests/batch/ultmarc/utmp_tables/table_mapper/com_alma/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/ecs/jskult-batch-daily/tests/batch/ultmarc/utmp_tables/table_mapper/com_alma/com_alma_delete.csv b/ecs/jskult-batch-daily/tests/batch/ultmarc/utmp_tables/table_mapper/com_alma/com_alma_delete.csv new file mode 100644 index 00000000..a437f7df --- /dev/null +++ b/ecs/jskult-batch-daily/tests/batch/ultmarc/utmp_tables/table_mapper/com_alma/com_alma_delete.csv @@ -0,0 +1,7 @@ +"004","001","A","20141113","20141114","北大" +"004","002","A","20141113","20141114","札幌医" +"004","003","A","20141113","20141114","弘大" +"004","004","A","20141113","20141114", +"004","005","A","20141113","20141114","東北大" +"004","006","C","20141113","20141114","福島医" +"004","007","A","20141113","20141114","群馬大" diff --git a/ecs/jskult-batch-daily/tests/batch/ultmarc/utmp_tables/table_mapper/com_alma/com_alma_insert.csv b/ecs/jskult-batch-daily/tests/batch/ultmarc/utmp_tables/table_mapper/com_alma/com_alma_insert.csv new file mode 100644 index 00000000..4f37bb30 --- /dev/null +++ b/ecs/jskult-batch-daily/tests/batch/ultmarc/utmp_tables/table_mapper/com_alma/com_alma_insert.csv @@ -0,0 +1,6 @@ +"004","001","A","20141113","20141114","北大" +"004","002","A","20141113","20141114","札幌医" +"004","003","A","20141113","20141114","弘大" +"004","004","A","20141113","20141114","岩手医" +"004","005","A","20141113","20141114","東北大" +"004","006","A","20141113","20141114","福島医" \ No newline at end of file diff --git a/ecs/jskult-batch-daily/tests/batch/ultmarc/utmp_tables/table_mapper/com_alma/com_alma_update.csv b/ecs/jskult-batch-daily/tests/batch/ultmarc/utmp_tables/table_mapper/com_alma/com_alma_update.csv new file mode 100644 index 00000000..0599c239 --- /dev/null +++ b/ecs/jskult-batch-daily/tests/batch/ultmarc/utmp_tables/table_mapper/com_alma/com_alma_update.csv @@ -0,0 +1,7 @@ +"004","001","B","20141113","20141114","北大" +"004","002","B","20141113","20141114","札幌医" +"004","003","B","20141113","20141114","弘大" +"004","004","B","20141113","20141114", +"004","005","B","20141113","20141114","福島医" +"004","006","B","20141113","20141114","東北大" +"004","007","A","20141113","20141114","神大" \ No newline at end of file diff --git a/ecs/jskult-batch-daily/tests/batch/ultmarc/utmp_tables/table_mapper/com_alma/db_com_alma_before_delete.csv b/ecs/jskult-batch-daily/tests/batch/ultmarc/utmp_tables/table_mapper/com_alma/db_com_alma_before_delete.csv new file mode 100644 index 00000000..259afa23 --- /dev/null +++ b/ecs/jskult-batch-daily/tests/batch/ultmarc/utmp_tables/table_mapper/com_alma/db_com_alma_before_delete.csv @@ -0,0 +1,7 @@ +"alma_cd","alma","regist_ymd","update_ymd","delete_ymd","regist_date","create_user","update_date","update_user","sys_regist_date","regist_prgm_id","sys_update_date","update_prgm_id" +"001","北大","20171020","20171020","NULL","NULL","NULL","NULL","NULL","2017/10/20 10:27:33","clsComAlma","2017/10/20 10:35:27","clsComAlma" +"002","札幌医","20171020","20171020","NULL","NULL","NULL","NULL","NULL","2017/10/20 10:27:33","clsComAlma","2017/10/20 10:35:27","clsComAlma" +"003","弘大","20171020","20171020","NULL","NULL","NULL","NULL","NULL","2017/10/20 10:27:33","clsComAlma","2017/10/20 10:35:27","clsComAlma" +"004",,"20171020","20171020","NULL","NULL","NULL","NULL","NULL","2017/10/20 10:27:33","clsComAlma","2017/10/20 10:35:27","clsComAlma" +"005","東北大","20171020","20171020","NULL","NULL","NULL","NULL","NULL","2017/10/20 10:27:33","clsComAlma","2017/10/20 10:35:27","clsComAlma" +"006","福島医","20171020","20171020","NULL","NULL","NULL","NULL","NULL","2017/10/20 10:27:33","clsComAlma","2017/10/20 10:35:27","clsComAlma" diff --git a/ecs/jskult-batch-daily/tests/batch/ultmarc/utmp_tables/table_mapper/com_alma/db_com_alma_before_update.csv b/ecs/jskult-batch-daily/tests/batch/ultmarc/utmp_tables/table_mapper/com_alma/db_com_alma_before_update.csv new file mode 100644 index 00000000..5284785e --- /dev/null +++ b/ecs/jskult-batch-daily/tests/batch/ultmarc/utmp_tables/table_mapper/com_alma/db_com_alma_before_update.csv @@ -0,0 +1,7 @@ +"alma_cd","alma","regist_ymd","update_ymd","delete_ymd","regist_date","create_user","update_date","update_user","sys_regist_date","regist_prgm_id","sys_update_date","update_prgm_id" +"001","北大","20171020","NULL","NULL","NULL","NULL","NULL","NULL","2017/10/20 10:27:33","clsComAlma","2017/10/20 10:27:33","clsComAlma" +"002","札幌医","20171020","NULL","NULL","NULL","NULL","NULL","NULL","2017/10/20 10:27:33","clsComAlma","2017/10/20 10:27:33","clsComAlma" +"003","弘大","20171020","NULL","NULL","NULL","NULL","NULL","NULL","2017/10/20 10:27:33","clsComAlma","2017/10/20 10:27:33","clsComAlma" +"004","岩手医","20171020","NULL","NULL","NULL","NULL","NULL","NULL","2017/10/20 10:27:33","clsComAlma","2017/10/20 10:27:33","clsComAlma" +"005","東北大","20171020","NULL","NULL","NULL","NULL","NULL","NULL","2017/10/20 10:27:33","clsComAlma","2017/10/20 10:27:33","clsComAlma" +"006","福島医","20171020","NULL","NULL","NULL","NULL","NULL","NULL","2017/10/20 10:27:33","clsComAlma","2017/10/20 10:27:33","clsComAlma" \ No newline at end of file diff --git a/ecs/jskult-batch-daily/tests/batch/ultmarc/utmp_tables/table_mapper/com_alma/expect_com_alma_delete.csv b/ecs/jskult-batch-daily/tests/batch/ultmarc/utmp_tables/table_mapper/com_alma/expect_com_alma_delete.csv new file mode 100644 index 00000000..6cb36d4b --- /dev/null +++ b/ecs/jskult-batch-daily/tests/batch/ultmarc/utmp_tables/table_mapper/com_alma/expect_com_alma_delete.csv @@ -0,0 +1,8 @@ +"alma_cd","alma","regist_ymd","update_ymd","delete_ymd","regist_date","create_user","update_date","update_user","sys_regist_date","regist_prgm_id","sys_update_date","update_prgm_id" +"001","北大","20171020","20171020","NULL","NULL","NULL","NULL","NULL","2017/10/20 10:27:33","clsComAlma","2017/10/20 10:43:15","com_alma_mapper" +"002","札幌医","20171020","20171020","NULL","NULL","NULL","NULL","NULL","2017/10/20 10:27:33","clsComAlma","2017/10/20 10:43:15","com_alma_mapper" +"003","弘大","20171020","20171020","NULL","NULL","NULL","NULL","NULL","2017/10/20 10:27:33","clsComAlma","2017/10/20 10:43:15","com_alma_mapper" +"004","","20171020","20171020","NULL","NULL","NULL","NULL","NULL","2017/10/20 10:27:33","clsComAlma","2017/10/20 10:43:15","com_alma_mapper" +"005","東北大","20171020","20171020","NULL","NULL","NULL","NULL","NULL","2017/10/20 10:27:33","clsComAlma","2017/10/20 10:43:15","com_alma_mapper" +"006","福島医","20171020","20171020","20171020","NULL","NULL","NULL","NULL","2017/10/20 10:27:33","clsComAlma","2017/10/20 10:43:15","com_alma_mapper" +"007","群馬大","20171020","NULL","NULL","NULL","NULL","NULL","NULL","2017/10/20 10:43:15","com_alma_mapper","2017/10/20 10:43:15","com_alma_mapper" diff --git a/ecs/jskult-batch-daily/tests/batch/ultmarc/utmp_tables/table_mapper/com_alma/expect_com_alma_insert.csv b/ecs/jskult-batch-daily/tests/batch/ultmarc/utmp_tables/table_mapper/com_alma/expect_com_alma_insert.csv new file mode 100644 index 00000000..8fafdb5f --- /dev/null +++ b/ecs/jskult-batch-daily/tests/batch/ultmarc/utmp_tables/table_mapper/com_alma/expect_com_alma_insert.csv @@ -0,0 +1,7 @@ +"alma_cd","alma","regist_ymd","update_ymd","delete_ymd","regist_date","create_user","update_date","update_user","sys_regist_date","regist_prgm_id","sys_update_date","update_prgm_id" +"001","北大","20171020","NULL","NULL","NULL","NULL","NULL","NULL","2017/10/20 10:27:33","com_alma_mapper","2017/10/20 10:27:33","com_alma_mapper" +"002","札幌医","20171020","NULL","NULL","NULL","NULL","NULL","NULL","2017/10/20 10:27:33","com_alma_mapper","2017/10/20 10:27:33","com_alma_mapper" +"003","弘大","20171020","NULL","NULL","NULL","NULL","NULL","NULL","2017/10/20 10:27:33","com_alma_mapper","2017/10/20 10:27:33","com_alma_mapper" +"004","岩手医","20171020","NULL","NULL","NULL","NULL","NULL","NULL","2017/10/20 10:27:33","com_alma_mapper","2017/10/20 10:27:33","com_alma_mapper" +"005","東北大","20171020","NULL","NULL","NULL","NULL","NULL","NULL","2017/10/20 10:27:33","com_alma_mapper","2017/10/20 10:27:33","com_alma_mapper" +"006","福島医","20171020","NULL","NULL","NULL","NULL","NULL","NULL","2017/10/20 10:27:33","com_alma_mapper","2017/10/20 10:27:33","com_alma_mapper" diff --git a/ecs/jskult-batch-daily/tests/batch/ultmarc/utmp_tables/table_mapper/com_alma/expect_com_alma_update.csv b/ecs/jskult-batch-daily/tests/batch/ultmarc/utmp_tables/table_mapper/com_alma/expect_com_alma_update.csv new file mode 100644 index 00000000..50811ab3 --- /dev/null +++ b/ecs/jskult-batch-daily/tests/batch/ultmarc/utmp_tables/table_mapper/com_alma/expect_com_alma_update.csv @@ -0,0 +1,8 @@ +"alma_cd","alma","regist_ymd","update_ymd","delete_ymd","regist_date","create_user","update_date","update_user","sys_regist_date","regist_prgm_id","sys_update_date","update_prgm_id" +"001","北大","20171020","20171020","NULL","NULL","NULL","NULL","NULL","2017/10/20 10:27:33","clsComAlma","2017/10/20 10:35:27","com_alma_mapper" +"002","札幌医","20171020","20171020","NULL","NULL","NULL","NULL","NULL","2017/10/20 10:27:33","clsComAlma","2017/10/20 10:35:27","com_alma_mapper" +"003","弘大","20171020","20171020","NULL","NULL","NULL","NULL","NULL","2017/10/20 10:27:33","clsComAlma","2017/10/20 10:35:27","com_alma_mapper" +"004",,"20171020","20171020","NULL","NULL","NULL","NULL","NULL","2017/10/20 10:27:33","clsComAlma","2017/10/20 10:35:27","com_alma_mapper" +"005","福島医","20171020","20171020","NULL","NULL","NULL","NULL","NULL","2017/10/20 10:27:33","clsComAlma","2017/10/20 10:35:27","com_alma_mapper" +"006","東北大","20171020","20171020","NULL","NULL","NULL","NULL","NULL","2017/10/20 10:27:33","clsComAlma","2017/10/20 10:35:27","com_alma_mapper" +"007","神大","20171020","NULL","NULL","NULL","NULL","NULL","NULL","2017/10/20 10:27:33","com_alma_mapper","2017/10/20 10:35:27","com_alma_mapper" diff --git a/ecs/jskult-batch-daily/tests/batch/ultmarc/utmp_tables/table_mapper/com_alma/test_com_alma_mapper.py b/ecs/jskult-batch-daily/tests/batch/ultmarc/utmp_tables/table_mapper/com_alma/test_com_alma_mapper.py new file mode 100644 index 00000000..238f8a3d --- /dev/null +++ b/ecs/jskult-batch-daily/tests/batch/ultmarc/utmp_tables/table_mapper/com_alma/test_com_alma_mapper.py @@ -0,0 +1,197 @@ +import os.path as path +from datetime import datetime + +import pytest + +from src.batch.common.batch_config import BatchConfig +from src.batch.ultmarc.utmp_tables.table_mapper.concrete import com_alma_mapper +from src.db.database import Database +from tests.testing_utility import (assert_table_results, + create_db_data_from_csv, + create_delete_sql_with_parameter, + create_insert_sql_with_parameter, + create_ultmarc_table_mapper_sut, + create_ultmarc_test_data_from_csv) + + +class TestComAlmaMapper: + """レイアウト区分004: COM_出身校""" + + db: Database + batch_config: BatchConfig + test_file_path: str = path.dirname(__file__) + + @pytest.fixture(autouse=True, scope='function') + def pre_test(self, database: Database): + """テスト実行前後処理""" + self.batch_config = BatchConfig.get_instance() + # setup + self.db = database + self.db.connect() + self.db.begin() + + # testing + yield + + # teardown + self.db.rollback() + self.db.disconnect() + + def test_insert_record(self): + """ + Cases: + COM_出身校テーブルにレコードを登録する + Arranges: + - CSVデータを用意し、読み込む + - 追加対象となるレコードを削除する + Expects: + - 登録内容が期待値と一致すること + """ + + # Arrange + # 処理日設定 + self.batch_config.syor_date = datetime.strftime(datetime.now(), '%Y/%m/%d') + # テスト用のCSVを読み込む + test_dat_file = create_ultmarc_test_data_from_csv(path.join(self.test_file_path, 'com_alma_insert.csv')) + # 一旦全データをDBから削除 + delete_sql, delete_parameter = create_delete_sql_with_parameter('src05.com_alma', {'1': '1'}) + self.db.execute(delete_sql, delete_parameter) + + # Act + for line_number, line in enumerate(test_dat_file, start=1): + sut: com_alma_mapper.ComAlmaMapper = create_ultmarc_table_mapper_sut(line, self.db) + assert type(sut) is com_alma_mapper.ComAlmaMapper, f'{line_number}行目:マッパークラスが期通りか' + + sut.make_query() + sut.execute_queries() + + # Assert + # 期待値ファイルを読み込む + expect_data_list = create_db_data_from_csv(path.join(self.test_file_path, 'expect_com_alma_insert.csv')) + primary_keys = [f"'{primary_key['alma_cd']}'" for primary_key in expect_data_list] + actual_select_sql = f"SELECT * FROM src05.com_alma WHERE alma_cd IN ({','.join(primary_keys)})" + actual_data_list = self.db.execute_select(actual_select_sql) + # 期待値検査 + ignore_columns = ['regist_ymd', 'sys_update_date', 'sys_regist_date'] + assert_table_results(actual_data_list, expect_data_list, ignore_col_name=ignore_columns) + # 動的日付項目の個別確認 + line_number = 0 + for actual_row, expect_row in zip(actual_data_list, expect_data_list): + line_number += 1 + for actual_col_name, expect_col_name in zip(actual_row, expect_row): + if actual_col_name in ['regist_ymd', 'sys_regist_date', 'sys_update_date']: + assert actual_row[actual_col_name] >= expect_row[expect_col_name], f'{line_number}行目:{actual_col_name}が、期待値以降であること' + + def test_update_record(self): + """ + Cases: + COM_出身校テーブルのレコードを更新する + Arranges: + - CSVデータを用意し、読み込む + - 更新対象となるレコードを登録する + Expects: + - 登録内容が期待値と一致すること + """ + + # Arrange + # 処理日設定 + self.batch_config.syor_date = datetime.strftime(datetime.now(), '%Y/%m/%d') + # テスト用のCSVを読み込む + test_dat_file = create_ultmarc_test_data_from_csv(path.join(self.test_file_path, 'com_alma_update.csv')) + # 一旦全データをDBから削除 + delete_sql, delete_parameter = create_delete_sql_with_parameter('src05.com_alma', {'1': '1'}) + self.db.execute(delete_sql, delete_parameter) + # テストデータをDBに登録 + # DBデータを読み込む + test_sql_data_list = create_db_data_from_csv(path.join(self.test_file_path, 'db_com_alma_before_update.csv')) + for test_data in test_sql_data_list: + insert_sql, insert_parameter = create_insert_sql_with_parameter( + 'src05.com_alma', + test_data.keys(), + test_data.values() + ) + self.db.execute(insert_sql, insert_parameter) + + # Act + for line_number, line in enumerate(test_dat_file, start=1): + sut: com_alma_mapper.ComAlmaMapper = create_ultmarc_table_mapper_sut(line, self.db) + assert type(sut) is com_alma_mapper.ComAlmaMapper, f'{line_number}行目:マッパークラスが期通りか' + sut.make_query() + sut.execute_queries() + + # Assert + # 期待値ファイルを読み込む + expect_data_list = create_db_data_from_csv(path.join(self.test_file_path, 'expect_com_alma_update.csv')) + primary_keys = [f"'{primary_key['alma_cd']}'" for primary_key in expect_data_list] + actual_select_sql = f"SELECT * FROM src05.com_alma WHERE alma_cd IN ({','.join(primary_keys)})" + actual_data_list = self.db.execute_select(actual_select_sql) + # 期待値検査 + ignore_columns = ['regist_ymd', 'update_ymd', 'sys_update_date', 'sys_regist_date'] + assert_table_results(actual_data_list, expect_data_list, ignore_col_name=ignore_columns) + # 動的日付項目の個別確認 + line_number = 0 + for actual_row, expect_row in zip(actual_data_list, expect_data_list): + line_number += 1 + for actual_col_name, expect_col_name in zip(actual_row, expect_row): + if actual_col_name in ignore_columns: + if expect_row[expect_col_name] is None: + assert actual_row[actual_col_name] is None, f'{line_number}行目:{actual_col_name}が、登録されていないこと' + else: + assert actual_row[actual_col_name] >= expect_row[expect_col_name], f'{line_number}行目:{actual_col_name}が、期待値以降であること' + + def test_logical_delete(self): + """ + Cases: + COM_出身校テーブルのレコードを1件論理削除する + Arranges: + - CSVデータを用意し、読み込む + - 削除対象となるレコードを登録する + Expects: + - 登録内容が期待値と一致すること + """ + + # Arrange + # 処理日設定 + self.batch_config.syor_date = datetime.strftime(datetime.now(), '%Y/%m/%d') + # テスト用のCSVを読み込む + test_dat_file = create_ultmarc_test_data_from_csv(path.join(self.test_file_path, 'com_alma_delete.csv')) + # 一旦全データをDBから削除 + delete_sql, delete_parameter = create_delete_sql_with_parameter('src05.com_alma', {'1': '1'}) + self.db.execute(delete_sql, delete_parameter) + # テストデータをDBに登録 + # DBデータを読み込む + test_sql_data_list = create_db_data_from_csv(path.join(self.test_file_path, 'db_com_alma_before_delete.csv')) + for test_data in test_sql_data_list: + insert_sql, insert_parameter = create_insert_sql_with_parameter( + 'src05.com_alma', + test_data.keys(), + test_data.values() + ) + self.db.execute(insert_sql, insert_parameter) + + # Act + for line_number, line in enumerate(test_dat_file, start=1): + sut: com_alma_mapper.ComAlmaMapper = create_ultmarc_table_mapper_sut(line, self.db) + assert type(sut) is com_alma_mapper.ComAlmaMapper, f'{line_number}行目:マッパークラスが期通りか' + sut.make_query() + sut.execute_queries() + + # Assert + # 期待値ファイルを読み込む + expect_data_list = create_db_data_from_csv(path.join(self.test_file_path, 'expect_com_alma_delete.csv')) + primary_keys = [f"'{primary_key['alma_cd']}'" for primary_key in expect_data_list] + actual_select_sql = f"SELECT * FROM src05.com_alma WHERE alma_cd IN ({','.join(primary_keys)})" + actual_data_list = self.db.execute_select(actual_select_sql) + # 期待値検査 + ignore_columns = ['regist_ymd', 'update_ymd', 'delete_ymd', 'sys_update_date', 'sys_regist_date'] + assert_table_results(actual_data_list, expect_data_list, ignore_col_name=ignore_columns) + # 動的日付項目の個別確認 + line_number = 0 + for actual_row, expect_row in zip(actual_data_list, expect_data_list): + line_number += 1 + for actual_col_name, expect_col_name in zip(actual_row, expect_row): + if actual_col_name in ignore_columns: + if expect_row[expect_col_name] is None: + assert actual_row[actual_col_name] is None, f'{line_number}行目:{actual_col_name}が、登録されていないこと' + else: + assert actual_row[actual_col_name] >= expect_row[expect_col_name], f'{line_number}行目:{actual_col_name}が、期待値以降であること' diff --git a/ecs/jskult-batch-daily/tests/batch/ultmarc/utmp_tables/table_mapper/com_dr_wrkplace/__init__.py b/ecs/jskult-batch-daily/tests/batch/ultmarc/utmp_tables/table_mapper/com_dr_wrkplace/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/ecs/jskult-batch-daily/tests/batch/ultmarc/utmp_tables/table_mapper/com_dr_wrkplace/com_dr_wrkplace_delete.csv b/ecs/jskult-batch-daily/tests/batch/ultmarc/utmp_tables/table_mapper/com_dr_wrkplace/com_dr_wrkplace_delete.csv new file mode 100644 index 00000000..d23ec8cc --- /dev/null +++ b/ecs/jskult-batch-daily/tests/batch/ultmarc/utmp_tables/table_mapper/com_dr_wrkplace/com_dr_wrkplace_delete.csv @@ -0,0 +1,5 @@ +"502","01","997682","","B","00","5408060","","1","20141204","20141206","","","1512","","","" +"502","01","997906","","B","00","5409446","","1","20141128","20141206","","","6802","","","" +"502","01","997682","","B","00","5412977","","1","20141204","20141206","","","6720","","","" +"502","01","995783","","B","00","5414992","","1","20141204","20141206","","","1118","","","" +"502","01","997906","","B","00","5503358","","1","20141202","20141206","","","7212","","","" diff --git a/ecs/jskult-batch-daily/tests/batch/ultmarc/utmp_tables/table_mapper/com_dr_wrkplace/com_dr_wrkplace_insert.csv b/ecs/jskult-batch-daily/tests/batch/ultmarc/utmp_tables/table_mapper/com_dr_wrkplace/com_dr_wrkplace_insert.csv new file mode 100644 index 00000000..c0abf3ce --- /dev/null +++ b/ecs/jskult-batch-daily/tests/batch/ultmarc/utmp_tables/table_mapper/com_dr_wrkplace/com_dr_wrkplace_insert.csv @@ -0,0 +1,10 @@ +"502","01","995783","","A","00","5414992","","2","20141113","20141114","501","","","","","" +"502","01","995783","","A","00","5507600","","2","20141113","20141114","133","144","9112","","","" +"502","01","997682","","A","00","5402984","","2","20141113","20141114","165","144","1512","","","" +"502","01","997682","","A","00","5408060","","2","20141113","20141114","","144","6802","","","" +"502","01","997682","","A","00","5412977","","2","20141113","20141114","","144","6720","","","" +"502","01","997906","","A","00","5409446","","2","20141113","20141114","501","","1118","","","" +"502","01","997906","","A","00","5503358","","2","20141113","20141114","172","144","1118","","","" +"502","01","997906","","A","00","5504428","","2","20141113","20141114","","144","7212","","","" +"502","01","997906","","A","00","5507600","","2","20141113","20141114","","144","9114","","","" +"502","01","999613","","A","00","5504428","","2","20141113","20141114","","144","5140","","","" diff --git a/ecs/jskult-batch-daily/tests/batch/ultmarc/utmp_tables/table_mapper/com_dr_wrkplace/com_dr_wrkplace_update.csv b/ecs/jskult-batch-daily/tests/batch/ultmarc/utmp_tables/table_mapper/com_dr_wrkplace/com_dr_wrkplace_update.csv new file mode 100644 index 00000000..73c4c336 --- /dev/null +++ b/ecs/jskult-batch-daily/tests/batch/ultmarc/utmp_tables/table_mapper/com_dr_wrkplace/com_dr_wrkplace_update.csv @@ -0,0 +1,5 @@ +"502","01","997906","","B","00","5409446","","","20170906","20170910","","","","","","@" +"502","01","995783","","B","00","5507600","","","20170907","20170910","@","802","@","@","@","" +"502","01","997682","","A","00","5408060","","","20141113","20141114","","","","","","" +"502","01","997682","","B","00","5402984","","","20141113","20141114","165","@","","","","" +"502","01","999613","","B","00","5504428","","2","20170328","20170401","501","","9999","内分泌・骨代謝外来","ナイブンピ.ホネタイシヤガイライ","" \ No newline at end of file diff --git a/ecs/jskult-batch-daily/tests/batch/ultmarc/utmp_tables/table_mapper/com_dr_wrkplace/db_com_blng_sec_before_delete.csv b/ecs/jskult-batch-daily/tests/batch/ultmarc/utmp_tables/table_mapper/com_dr_wrkplace/db_com_blng_sec_before_delete.csv new file mode 100644 index 00000000..d37f092e --- /dev/null +++ b/ecs/jskult-batch-daily/tests/batch/ultmarc/utmp_tables/table_mapper/com_dr_wrkplace/db_com_blng_sec_before_delete.csv @@ -0,0 +1,6 @@ +"blng_sec_cd","blng_sec_kana","blng_sec_name","regist_ymd","update_ymd","delete_ymd","inst_category","trt_category","category_sort","regist_date","create_user","update_date","update_user","sys_regist_date","regist_prgm_id","sys_update_date","update_prgm_id" +"1512",,NULL,"20150825","NULL","NULL","NULL","NULL","NULL","NULL","NULL","NULL","NULL","2015-08-25 00:10:58","clsComBlngSec","2022-05-16 22:18:28","clsComBlngSec" +"6802","NULL",,"20150825","NULL","NULL","NULL","NULL","NULL","NULL","NULL","NULL","NULL","2015-08-25 00:10:58","clsComBlngSec","2022-05-30 22:18:48","clsComBlngSec" +"6720",,"NULL","20150825","NULL","NULL","NULL","NULL","NULL","NULL","NULL","NULL","NULL","2015-08-25 00:10:58","clsComBlngSec","2019-12-23 22:13:44","clsComBlngSec" +"1118","NULL",,"20150825","NULL","NULL","NULL","NULL","NULL","NULL","NULL","NULL","NULL","2015-08-25 00:10:58","clsComBlngSec","2016-05-17 00:13:18","clsComBlngSec" +"7212",,"NULL","20150818","NULL","NULL","NULL","NULL","NULL","NULL","NULL","NULL","NULL","2015-08-18 00:12:58","clsComBlngSec","2021-01-11 22:15:40","clsComBlngSec" diff --git a/ecs/jskult-batch-daily/tests/batch/ultmarc/utmp_tables/table_mapper/com_dr_wrkplace/db_com_blng_sec_before_insert.csv b/ecs/jskult-batch-daily/tests/batch/ultmarc/utmp_tables/table_mapper/com_dr_wrkplace/db_com_blng_sec_before_insert.csv new file mode 100644 index 00000000..bb604b15 --- /dev/null +++ b/ecs/jskult-batch-daily/tests/batch/ultmarc/utmp_tables/table_mapper/com_dr_wrkplace/db_com_blng_sec_before_insert.csv @@ -0,0 +1,9 @@ +"blng_sec_cd","blng_sec_kana","blng_sec_name","regist_ymd","update_ymd","delete_ymd","inst_category","trt_category","category_sort","regist_date","create_user","update_date","update_user","sys_regist_date","regist_prgm_id","sys_update_date","update_prgm_id" +"1512","シヨウカキゲカ","消化器外科","20150825","NULL","NULL","NULL","NULL","NULL","NULL","NULL","NULL","NULL","2015-08-25 00:10:58","clsComBlngSec","2022-05-16 22:18:28","clsComBlngSec" +"6802","シヨウカキゲカガク1","消化器外科学Ⅰ","20150825","NULL","NULL","NULL","NULL","NULL","NULL","NULL","NULL","NULL","2015-08-25 00:10:58","clsComBlngSec","2022-05-30 22:18:48","clsComBlngSec" +"6720","シヨウカキゲカガク","消化器外科学","20150825","NULL","NULL","NULL","NULL","NULL","NULL","NULL","NULL","NULL","2015-08-25 00:10:58","clsComBlngSec","2019-12-23 22:13:44","clsComBlngSec" +"1118","ケツエキナイカ","血液内科","20150825","NULL","NULL","NULL","NULL","NULL","NULL","NULL","NULL","NULL","2015-08-25 00:10:58","clsComBlngSec","2016-05-17 00:13:18","clsComBlngSec" +"7212","ユケツ.サイボウチリヨウガク","輸血・細胞治療学","20150818","NULL","NULL","NULL","NULL","NULL","NULL","NULL","NULL","NULL","2015-08-18 00:12:58","clsComBlngSec","2021-01-11 22:15:40","clsComBlngSec" +"5140","ヤクリガク","薬理学","20150818","NULL","NULL","NULL","NULL","NULL","NULL","NULL","NULL","NULL","2015-08-18 00:12:58","clsComBlngSec","2022-08-22 22:23:47","clsComBlngSec" +"9112","ハツセイ.セイシヨクブモン","発生・生殖部門","20150818","NULL","NULL","NULL","NULL","NULL","NULL","NULL","NULL","NULL","2015-08-18 00:12:58","clsComBlngSec","2022-08-01 22:23:53","clsComBlngSec" +"9114","サイボウイシヨクブモン","細胞移植部門","20150818","NULL","NULL","NULL","NULL","NULL","NULL","NULL","NULL","NULL","2015-08-18 00:12:58","clsComBlngSec","2022-08-01 22:23:53","clsComBlngSec" diff --git a/ecs/jskult-batch-daily/tests/batch/ultmarc/utmp_tables/table_mapper/com_dr_wrkplace/db_com_dr_wrkplace_before_delete.csv b/ecs/jskult-batch-daily/tests/batch/ultmarc/utmp_tables/table_mapper/com_dr_wrkplace/db_com_dr_wrkplace_before_delete.csv new file mode 100644 index 00000000..d2432eb9 --- /dev/null +++ b/ecs/jskult-batch-daily/tests/batch/ultmarc/utmp_tables/table_mapper/com_dr_wrkplace/db_com_dr_wrkplace_before_delete.csv @@ -0,0 +1,11 @@ +"dcf_dsf_inst_cd","dcf_pcf_dr_cd","blng_sec_cd","post_cd","identity_cd","aply_start_ymd","blng_sec_name_kana","blng_sec_name","notdm_flg","regist_ymd","update_ymd","regist_date","create_user","update_date","update_user","sys_regist_date","regist_prgm_id","sys_update_date","update_prgm_id" +"005414992","01995783",,"501",,"2020-02-22",,,,"2022-02-03","NULL","NULL","NULL","NULL","NULL","2022-02-03 14:23:39","clsComDrWrk","2022-02-03 14:23:39","clsComDrWrk" +"005507600","01995783","9999",,"802","2020-02-23",,,,"2022-02-03","2022-02-03","NULL","NULL","NULL","NULL","2022-02-03 14:23:39","clsComDrWrk","2022-02-03 14:43:43","clsComDrWrk" +"005402984","01997682","1512","165",,"2020-02-23","シヨウカキゲカ","消化器外科",,"2022-02-03","2022-02-03","NULL","NULL","NULL","NULL","2022-02-03 14:23:39","clsComDrWrk","2022-02-03 14:43:43","clsComDrWrk" +"005408060","01997682","6802",,"144","2020-02-22","シヨウカキゲカガク1","消化器外科学Ⅰ",,"2022-02-03","NULL","NULL","NULL","NULL","NULL","2022-02-03 14:23:39","clsComDrWrk","2022-02-03 14:23:39","clsComDrWrk" +"005412977","01997682","6720",,"144","2020-02-22","シヨウカキゲカガク","消化器外科学",,"2022-02-03","NULL","NULL","NULL","NULL","NULL","2022-02-03 14:23:39","clsComDrWrk","2022-02-03 14:23:39","clsComDrWrk" +"005409446","01997906","1118","501",,"2020-02-22","ケツエキナイカ","血液内科",,"2022-02-03","2022-02-03","NULL","NULL","NULL","NULL","2022-02-03 14:23:39","clsComDrWrk","2022-02-03 14:43:43","clsComDrWrk" +"005503358","01997906","1118","172","144","2020-02-22","ケツエキナイカ","血液内科",,"2022-02-03","NULL","NULL","NULL","NULL","NULL","2022-02-03 14:23:39","clsComDrWrk","2022-02-03 14:23:39","clsComDrWrk" +"005504428","01997906","7212",,"144","2020-02-22","ユケツ.サイボウチリヨウガク","輸血・細胞治療学",,"2022-02-03","NULL","NULL","NULL","NULL","NULL","2022-02-03 14:23:39","clsComDrWrk","2022-02-03 14:23:39","clsComDrWrk" +"005507600","01997906","9114",,"144","2020-02-22","サイボウイシヨクブモン","細胞移植部門",,"2022-02-03","NULL","NULL","NULL","NULL","NULL","2022-02-03 14:23:39","clsComDrWrk","2022-02-03 14:23:39","clsComDrWrk" +"005504428","01999613","9999","501","144","2020-02-23","ナイブンピ.ホネタイシヤガイライ","内分泌・骨代謝外来",,"2022-02-03","2022-02-03","NULL","NULL","NULL","NULL","2022-02-03 14:23:39","clsComDrWrk","2022-02-03 14:43:43","clsComDrWrk" diff --git a/ecs/jskult-batch-daily/tests/batch/ultmarc/utmp_tables/table_mapper/com_dr_wrkplace/db_com_dr_wrkplace_before_update.csv b/ecs/jskult-batch-daily/tests/batch/ultmarc/utmp_tables/table_mapper/com_dr_wrkplace/db_com_dr_wrkplace_before_update.csv new file mode 100644 index 00000000..f0da440a --- /dev/null +++ b/ecs/jskult-batch-daily/tests/batch/ultmarc/utmp_tables/table_mapper/com_dr_wrkplace/db_com_dr_wrkplace_before_update.csv @@ -0,0 +1,11 @@ +"dcf_dsf_inst_cd","dcf_pcf_dr_cd","blng_sec_cd","post_cd","identity_cd","aply_start_ymd","blng_sec_name_kana","blng_sec_name","notdm_flg","regist_ymd","update_ymd","regist_date","create_user","update_date","update_user","sys_regist_date","regist_prgm_id","sys_update_date","update_prgm_id" +"005414992","01995783",,"501",,"2020-02-22",,,,"2022-02-03","NULL","NULL","NULL","NULL","NULL","2022-02-03 14:23:39","clsComDrWrk","2022-02-03 14:23:39","clsComDrWrk" +"005507600","01995783","9112","133","144","2020-02-22","ハツセイ.セイシヨクブモン","発生・生殖部門","1","2022-02-03","NULL","NULL","NULL","NULL","NULL","2022-02-03 14:23:39","clsComDrWrk","2022-02-03 14:23:39","clsComDrWrk" +"005402984","01997682","1512","165","144","2020-02-22","シヨウカキゲカ","消化器外科",,"2022-02-03","NULL","NULL","NULL","NULL","NULL","2022-02-03 14:23:39","clsComDrWrk","2022-02-03 14:23:39","clsComDrWrk" +"005408060","01997682","6802",,"144","2020-02-22","シヨウカキゲカガク1","消化器外科学Ⅰ",,"2022-02-03","NULL","NULL","NULL","NULL","NULL","2022-02-03 14:23:39","clsComDrWrk","2022-02-03 14:23:39","clsComDrWrk" +"005412977","01997682","6720",,"144","2020-02-22","シヨウカキゲカガク","消化器外科学",,"2022-02-03","NULL","NULL","NULL","NULL","NULL","2022-02-03 14:23:39","clsComDrWrk","2022-02-03 14:23:39","clsComDrWrk" +"005409446","01997906","1118","501",,"2020-02-22","ケツエキナイカ","血液内科","1","2022-02-03","NULL","NULL","NULL","NULL","NULL","2022-02-03 14:23:39","clsComDrWrk","2022-02-03 14:23:39","clsComDrWrk" +"005503358","01997906","1118","172","144","2020-02-22","ケツエキナイカ","血液内科",,"2022-02-03","NULL","NULL","NULL","NULL","NULL","2022-02-03 14:23:39","clsComDrWrk","2022-02-03 14:23:39","clsComDrWrk" +"005504428","01997906","7212",,"144","2020-02-22","ユケツ.サイボウチリヨウガク","輸血・細胞治療学",,"2022-02-03","NULL","NULL","NULL","NULL","NULL","2022-02-03 14:23:39","clsComDrWrk","2022-02-03 14:23:39","clsComDrWrk" +"005507600","01997906","9114",,"144","2020-02-22","サイボウイシヨクブモン","細胞移植部門",,"2022-02-03","NULL","NULL","NULL","NULL","NULL","2022-02-03 14:23:39","clsComDrWrk","2022-02-03 14:23:39","clsComDrWrk" +"005504428","01999613","5140",,"144","2020-02-22","ヤクリガク","薬理学",,"2022-02-03","NULL","NULL","NULL","NULL","NULL","2022-02-03 14:23:39","clsComDrWrk","2022-02-03 14:23:39","clsComDrWrk" diff --git a/ecs/jskult-batch-daily/tests/batch/ultmarc/utmp_tables/table_mapper/com_dr_wrkplace/db_com_dr_wrkplace_his_before_delete.csv b/ecs/jskult-batch-daily/tests/batch/ultmarc/utmp_tables/table_mapper/com_dr_wrkplace/db_com_dr_wrkplace_his_before_delete.csv new file mode 100644 index 00000000..c0621a43 --- /dev/null +++ b/ecs/jskult-batch-daily/tests/batch/ultmarc/utmp_tables/table_mapper/com_dr_wrkplace/db_com_dr_wrkplace_his_before_delete.csv @@ -0,0 +1,4 @@ +"dr_wrkplace_his_key","dcf_dsf_inst_cd","dcf_pcf_dr_cd","blng_sec_cd","post_cd","identity_cd","aply_start_ymd","blng_sec_name_kana","blng_sec_name","notdm_flg","aply_end_ymd","regist_ymd","update_ymd","regist_date","create_user","update_date","update_user","sys_regist_date","regist_prgm_id","sys_update_date","update_prgm_id" +"1482020","005507600","01995783","9112","133","144","20200222","ハツセイ.セイシヨクブモン","発生・生殖部門",,"20200222","20220203","NULL","NULL","NULL","NULL","NULL","2022-02-03 14:43:43","com_dr_wrkplace_mapper","2022-02-03 14:43:43","com_dr_wrkplace_mapper" +"1482021","005402984","01997682","1512","165","144","20200222","シヨウカキゲカ","消化器外科",,"20200222","20220203","NULL","NULL","NULL","NULL","NULL","2022-02-03 14:43:43","com_dr_wrkplace_mapper","2022-02-03 14:43:43","com_dr_wrkplace_mapper" +"1482022","005504428","01999613","5140","999","144","20200222","ヤクリガク","薬理学",,"20200222","20220203","NULL","NULL","NULL","NULL","NULL","2022-02-03 14:43:43","com_dr_wrkplace_mapper","2022-02-03 14:43:43","com_dr_wrkplace_mapper" diff --git a/ecs/jskult-batch-daily/tests/batch/ultmarc/utmp_tables/table_mapper/com_dr_wrkplace/expect_com_dr_wrkplace_delete.csv b/ecs/jskult-batch-daily/tests/batch/ultmarc/utmp_tables/table_mapper/com_dr_wrkplace/expect_com_dr_wrkplace_delete.csv new file mode 100644 index 00000000..4f5049a2 --- /dev/null +++ b/ecs/jskult-batch-daily/tests/batch/ultmarc/utmp_tables/table_mapper/com_dr_wrkplace/expect_com_dr_wrkplace_delete.csv @@ -0,0 +1,6 @@ +"dcf_dsf_inst_cd","dcf_pcf_dr_cd","blng_sec_cd","post_cd","identity_cd","aply_start_ymd","blng_sec_name_kana","blng_sec_name","notdm_flg","regist_ymd","update_ymd","regist_date","create_user","update_date","update_user","sys_regist_date","regist_prgm_id","sys_update_date","update_prgm_id" +"005507600","01995783","9999",,"802","2020-02-23",,,,"2022-02-03","2022-02-03","NULL","NULL","NULL","NULL","2022-02-03 14:23:39","clsComDrWrk","2022-02-03 14:43:43","clsComDrWrk" +"005402984","01997682","1512","165",,"2020-02-23","シヨウカキゲカ","消化器外科",,"2022-02-03","2022-02-03","NULL","NULL","NULL","NULL","2022-02-03 14:23:39","clsComDrWrk","2022-02-03 14:43:43","clsComDrWrk" +"005504428","01997906","7212",,"144","2020-02-22","ユケツ.サイボウチリヨウガク","輸血・細胞治療学",,"2022-02-03","NULL","NULL","NULL","NULL","NULL","2022-02-03 14:23:39","clsComDrWrk","2022-02-03 14:23:39","clsComDrWrk" +"005507600","01997906","9114",,"144","2020-02-22","サイボウイシヨクブモン","細胞移植部門",,"2022-02-03","NULL","NULL","NULL","NULL","NULL","2022-02-03 14:23:39","clsComDrWrk","2022-02-03 14:23:39","clsComDrWrk" +"005504428","01999613","9999","501","144","2020-02-23","ナイブンピ.ホネタイシヤガイライ","内分泌・骨代謝外来",,"2022-02-03","2022-02-03","NULL","NULL","NULL","NULL","2022-02-03 14:23:39","clsComDrWrk","2022-02-03 14:43:43","clsComDrWrk" \ No newline at end of file diff --git a/ecs/jskult-batch-daily/tests/batch/ultmarc/utmp_tables/table_mapper/com_dr_wrkplace/expect_com_dr_wrkplace_his_delete.csv b/ecs/jskult-batch-daily/tests/batch/ultmarc/utmp_tables/table_mapper/com_dr_wrkplace/expect_com_dr_wrkplace_his_delete.csv new file mode 100644 index 00000000..a4471434 --- /dev/null +++ b/ecs/jskult-batch-daily/tests/batch/ultmarc/utmp_tables/table_mapper/com_dr_wrkplace/expect_com_dr_wrkplace_his_delete.csv @@ -0,0 +1,9 @@ +"dr_wrkplace_his_key","dcf_dsf_inst_cd","dcf_pcf_dr_cd","blng_sec_cd","post_cd","identity_cd","aply_start_ymd","blng_sec_name_kana","blng_sec_name","notdm_flg","aply_end_ymd","regist_ymd","update_ymd","regist_date","create_user","update_date","update_user","sys_regist_date","regist_prgm_id","sys_update_date","update_prgm_id" +"1482020","005507600","01995783","9112","133","144","20200222","ハツセイ.セイシヨクブモン","発生・生殖部門",,"20200222","20220203","NULL","NULL","NULL","NULL","NULL","2022-02-03 14:43:43","com_dr_wrkplace_mapper","2022-02-03 14:43:43","com_dr_wrkplace_mapper" +"1482021","005402984","01997682","1512","165","144","20200222","シヨウカキゲカ","消化器外科",,"20200222","20220203","NULL","NULL","NULL","NULL","NULL","2022-02-03 14:43:43","com_dr_wrkplace_mapper","2022-02-03 14:43:43","com_dr_wrkplace_mapper" +"1482022","005504428","01999613","5140","999","144","20200222","ヤクリガク","薬理学",,"20200222","20220203","NULL","NULL","NULL","NULL","NULL","2022-02-03 14:43:43","com_dr_wrkplace_mapper","2022-02-03 14:43:43","com_dr_wrkplace_mapper" +"1482023","005408060","01997682","6802","999","144","20200222","シヨウカキゲカガク1","消化器外科学Ⅰ",,"20200223","20220203","NULL","NULL","NULL","NULL","NULL","2022-02-03 16:18:08","com_dr_wrkplace_mapper","2022-02-03 16:18:08","com_dr_wrkplace_mapper" +"1482024","005409446","01997906","1118","501","999","20200222","ケツエキナイカ","血液内科",,"20200223","20220203","NULL","NULL","NULL","NULL","NULL","2022-02-03 16:18:08","com_dr_wrkplace_mapper","2022-02-03 16:18:08","com_dr_wrkplace_mapper" +"1482025","005412977","01997682","6720","999","144","20200222","シヨウカキゲカガク","消化器外科学",,"20200223","20220203","NULL","NULL","NULL","NULL","NULL","2022-02-03 16:18:08","com_dr_wrkplace_mapper","2022-02-03 16:18:08","com_dr_wrkplace_mapper" +"1482026","005414992","01995783","9999","501","999","20200222",,,,"20200223","20220203","NULL","NULL","NULL","NULL","NULL","2022-02-03 16:18:08","com_dr_wrkplace_mapper","2022-02-03 16:18:08","com_dr_wrkplace_mapper" +"1482027","005503358","01997906","1118","172","144","20200222","ケツエキナイカ","血液内科",,"20200223","20220203","NULL","NULL","NULL","NULL","NULL","2022-02-03 16:18:08","com_dr_wrkplace_mapper","2022-02-03 16:18:08","com_dr_wrkplace_mapper" \ No newline at end of file diff --git a/ecs/jskult-batch-daily/tests/batch/ultmarc/utmp_tables/table_mapper/com_dr_wrkplace/expect_com_dr_wrkplace_his_update.csv b/ecs/jskult-batch-daily/tests/batch/ultmarc/utmp_tables/table_mapper/com_dr_wrkplace/expect_com_dr_wrkplace_his_update.csv new file mode 100644 index 00000000..cc43df9e --- /dev/null +++ b/ecs/jskult-batch-daily/tests/batch/ultmarc/utmp_tables/table_mapper/com_dr_wrkplace/expect_com_dr_wrkplace_his_update.csv @@ -0,0 +1,4 @@ +"dr_wrkplace_his_key","dcf_dsf_inst_cd","dcf_pcf_dr_cd","blng_sec_cd","post_cd","identity_cd","aply_start_ymd","blng_sec_name_kana","blng_sec_name","notdm_flg","aply_end_ymd","regist_ymd","update_ymd","regist_date","create_user","update_date","update_user","sys_regist_date","regist_prgm_id","sys_update_date","update_prgm_id" +"1","005507600","01995783","9112","133","144","20200222","ハツセイ.セイシヨクブモン","発生・生殖部門","1","20200222","20220203","NULL","NULL","NULL","NULL","NULL","2022-02-03 14:43:43","com_dr_wrkplace_mapper","2022-02-03 14:43:43","com_dr_wrkplace_mapper" +"2","005402984","01997682","1512","165","144","20200222","シヨウカキゲカ","消化器外科",,"20200222","20220203","NULL","NULL","NULL","NULL","NULL","2022-02-03 14:43:43","com_dr_wrkplace_mapper","2022-02-03 14:43:43","com_dr_wrkplace_mapper" +"3","005504428","01999613","5140","999","144","20200222","ヤクリガク","薬理学",,"20200222","20220203","NULL","NULL","NULL","NULL","NULL","2022-02-03 14:43:43","com_dr_wrkplace_mapper","2022-02-03 14:43:43","com_dr_wrkplace_mapper" \ No newline at end of file diff --git a/ecs/jskult-batch-daily/tests/batch/ultmarc/utmp_tables/table_mapper/com_dr_wrkplace/expect_com_dr_wrkplace_insert.csv b/ecs/jskult-batch-daily/tests/batch/ultmarc/utmp_tables/table_mapper/com_dr_wrkplace/expect_com_dr_wrkplace_insert.csv new file mode 100644 index 00000000..3f8923af --- /dev/null +++ b/ecs/jskult-batch-daily/tests/batch/ultmarc/utmp_tables/table_mapper/com_dr_wrkplace/expect_com_dr_wrkplace_insert.csv @@ -0,0 +1,11 @@ +"dcf_dsf_inst_cd","dcf_pcf_dr_cd","blng_sec_cd","post_cd","identity_cd","aply_start_ymd","blng_sec_name_kana","blng_sec_name","notdm_flg","regist_ymd","update_ymd","regist_date","create_user","update_date","update_user","sys_regist_date","regist_prgm_id","sys_update_date","update_prgm_id" +"005414992","01995783",,"501",,"2020-02-22",,,,"2022-02-02","NULL","NULL","NULL","NULL","NULL","2022-02-02 14:54:00","com_dr_wrkplace_mapper","2022-02-02 14:54:00","com_dr_wrkplace_mapper" +"005507600","01995783","9112","133","144","2020-02-22","ハツセイ.セイシヨクブモン","発生・生殖部門",,"2022-02-02","NULL","NULL","NULL","NULL","NULL","2022-02-02 10:45:16","com_dr_wrkplace_mapper","2022-02-02 14:54:00","com_dr_wrkplace_mapper" +"005402984","01997682","1512","165","144","2020-02-22","シヨウカキゲカ","消化器外科",,"2022-02-02","NULL","NULL","NULL","NULL","NULL","2022-02-02 10:45:16","com_dr_wrkplace_mapper","2022-02-02 14:54:00","com_dr_wrkplace_mapper" +"005408060","01997682","6802",,"144","2020-02-22","シヨウカキゲカガク1","消化器外科学Ⅰ",,"2022-02-02","NULL","NULL","NULL","NULL","NULL","2022-02-02 10:45:16","com_dr_wrkplace_mapper","2022-02-02 14:54:00","com_dr_wrkplace_mapper" +"005412977","01997682","6720",,"144","2020-02-22","シヨウカキゲカガク","消化器外科学",,"2022-02-02","NULL","NULL","NULL","NULL","NULL","2022-02-02 10:45:16","com_dr_wrkplace_mapper","2022-02-02 14:54:00","com_dr_wrkplace_mapper" +"005409446","01997906","1118","501",,"2020-02-22","ケツエキナイカ","血液内科",,"2022-02-02","NULL","NULL","NULL","NULL","NULL","2022-02-02 10:45:16","com_dr_wrkplace_mapper","2022-02-02 14:54:00","com_dr_wrkplace_mapper" +"005503358","01997906","1118","172","144","2020-02-22","ケツエキナイカ","血液内科",,"2022-02-02","NULL","NULL","NULL","NULL","NULL","2022-02-02 10:45:17","com_dr_wrkplace_mapper","2022-02-02 14:54:00","com_dr_wrkplace_mapper" +"005504428","01997906","7212",,"144","2020-02-22","ユケツ.サイボウチリヨウガク","輸血・細胞治療学",,"2022-02-02","NULL","NULL","NULL","NULL","NULL","2022-02-02 10:45:17","com_dr_wrkplace_mapper","2022-02-02 14:54:00","com_dr_wrkplace_mapper" +"005507600","01997906","9114",,"144","2020-02-22","サイボウイシヨクブモン","細胞移植部門",,"2022-02-02","NULL","NULL","NULL","NULL","NULL","2022-02-02 10:45:17","com_dr_wrkplace_mapper","2022-02-02 14:54:00","com_dr_wrkplace_mapper" +"005504428","01999613","5140",,"144","2020-02-22","ヤクリガク","薬理学",,"2022-02-02","NULL","NULL","NULL","NULL","NULL","2022-02-02 10:45:17","com_dr_wrkplace_mapper","2022-02-02 14:54:00","com_dr_wrkplace_mapper" diff --git a/ecs/jskult-batch-daily/tests/batch/ultmarc/utmp_tables/table_mapper/com_dr_wrkplace/expect_com_dr_wrkplace_update.csv b/ecs/jskult-batch-daily/tests/batch/ultmarc/utmp_tables/table_mapper/com_dr_wrkplace/expect_com_dr_wrkplace_update.csv new file mode 100644 index 00000000..1cee6ac3 --- /dev/null +++ b/ecs/jskult-batch-daily/tests/batch/ultmarc/utmp_tables/table_mapper/com_dr_wrkplace/expect_com_dr_wrkplace_update.csv @@ -0,0 +1,11 @@ +"dcf_dsf_inst_cd","dcf_pcf_dr_cd","blng_sec_cd","post_cd","identity_cd","aply_start_ymd","blng_sec_name_kana","blng_sec_name","notdm_flg","regist_ymd","update_ymd","regist_date","create_user","update_date","update_user","sys_regist_date","regist_prgm_id","sys_update_date","update_prgm_id" +"005414992","01995783",,"501",,"2020-02-22",,,,"2022-02-03","NULL","NULL","NULL","NULL","NULL","2022-02-03 14:23:39","clsComDrWrk","2022-02-03 14:23:39","clsComDrWrk" +"005507600","01995783","9999",,"802","2020-02-23","NULL","NULL","1","2022-02-03","2022-02-03","NULL","NULL","NULL","NULL","2022-02-03 14:23:39","clsComDrWrk","2022-02-03 14:43:43","com_dr_wrkplace_mapper" +"005402984","01997682","1512","165",,"2020-02-23","シヨウカキゲカ","消化器外科",,"2022-02-03","2022-02-03","NULL","NULL","NULL","NULL","2022-02-03 14:23:39","clsComDrWrk","2022-02-03 14:43:43","com_dr_wrkplace_mapper" +"005408060","01997682","6802",,"144","2020-02-22","シヨウカキゲカガク1","消化器外科学Ⅰ",,"2022-02-03","2022-02-03","NULL","NULL","NULL","NULL","2022-02-03 14:23:39","clsComDrWrk","2022-02-03 14:43:43","com_dr_wrkplace_mapper" +"005412977","01997682","6720",,"144","2020-02-22","シヨウカキゲカガク","消化器外科学",,"2022-02-03","NULL","NULL","NULL","NULL","NULL","2022-02-03 14:23:39","clsComDrWrk","2022-02-03 14:23:39","clsComDrWrk" +"005409446","01997906","1118","501",,"2020-02-22","ケツエキナイカ","血液内科","NULL","2022-02-03","2022-02-03","NULL","NULL","NULL","NULL","2022-02-03 14:23:39","clsComDrWrk","2022-02-03 14:43:43","com_dr_wrkplace_mapper" +"005503358","01997906","1118","172","144","2020-02-22","ケツエキナイカ","血液内科",,"2022-02-03","NULL","NULL","NULL","NULL","NULL","2022-02-03 14:23:39","clsComDrWrk","2022-02-03 14:23:39","clsComDrWrk" +"005504428","01997906","7212",,"144","2020-02-22","ユケツ.サイボウチリヨウガク","輸血・細胞治療学",,"2022-02-03","NULL","NULL","NULL","NULL","NULL","2022-02-03 14:23:39","clsComDrWrk","2022-02-03 14:23:39","clsComDrWrk" +"005507600","01997906","9114",,"144","2020-02-22","サイボウイシヨクブモン","細胞移植部門",,"2022-02-03","NULL","NULL","NULL","NULL","NULL","2022-02-03 14:23:39","clsComDrWrk","2022-02-03 14:23:39","clsComDrWrk" +"005504428","01999613","9999","501","144","2020-02-23","ナイブンピ.ホネタイシヤガイライ","内分泌・骨代謝外来",,"2022-02-03","2022-02-03","NULL","NULL","NULL","NULL","2022-02-03 14:23:39","clsComDrWrk","2022-02-03 14:43:43","com_dr_wrkplace_mapper" \ No newline at end of file diff --git a/ecs/jskult-batch-daily/tests/batch/ultmarc/utmp_tables/table_mapper/com_dr_wrkplace/test_com_dr_wrkplace_mapper.py b/ecs/jskult-batch-daily/tests/batch/ultmarc/utmp_tables/table_mapper/com_dr_wrkplace/test_com_dr_wrkplace_mapper.py new file mode 100644 index 00000000..f838dabf --- /dev/null +++ b/ecs/jskult-batch-daily/tests/batch/ultmarc/utmp_tables/table_mapper/com_dr_wrkplace/test_com_dr_wrkplace_mapper.py @@ -0,0 +1,390 @@ +import os.path as path + +import pytest + +from src.batch.common.batch_config import BatchConfig +from src.batch.ultmarc.utmp_tables.table_mapper.concrete import \ + com_dr_wrkplace_mapper +from src.db.database import Database +from tests.testing_utility import (assert_table_results, + create_db_data_from_csv, + create_delete_sql_with_parameter, + create_insert_sql_with_parameter, + create_ultmarc_table_mapper_sut, + create_ultmarc_test_data_from_csv) + + +class TestComDrWrkplaceMapper: + """COM_DCF医師勤務先""" + + db: Database + batch_config: BatchConfig + test_file_path: str = path.dirname(__file__) + + @ pytest.fixture(autouse=True, scope='function') + def pre_test(self, database: Database): + """テスト実行前後処理""" + self.batch_config = BatchConfig.get_instance() + + # setup + self.db = database + self.db.connect() + self.db.begin() + + # testing + yield + + # teardown + self.db.rollback() + self.db.disconnect() + + def test_insert_record(self): + """ + Cases: + COM_DCF医師勤務先テーブルにレコードを登録する + Arranges: + - CSVデータを用意する + - 追加対象となるレコードを削除する + Expects: + - COM_医師勤務先の登録内容が期待値と一致すること + - COM_医師勤務先履歴にデータが登録されないこと + """ + + # Arrange + # 処理日設定 + # 適用開始日と同値になる + self.batch_config.syor_date = '2020/02/22' + # テスト用のCSVを読み込む + test_dat_file = create_ultmarc_test_data_from_csv(path.join(self.test_file_path, 'com_dr_wrkplace_insert.csv')) + # 一旦全データをDBから削除 + # COM_医師勤務先 + delete_sql, delete_parameter = create_delete_sql_with_parameter('src05.com_dr_wrkplace', {'1': '1'}) + self.db.execute(delete_sql, delete_parameter) + # COM_医師勤務先履歴 + delete_sql, delete_parameter = create_delete_sql_with_parameter('src05.com_dr_wrkplace_his', {'1': '1'}) + self.db.execute(delete_sql, delete_parameter) + # COM_所属部科 + delete_sql, delete_parameter = create_delete_sql_with_parameter('src05.com_blng_sec', {'1': '1'}) + self.db.execute(delete_sql, delete_parameter) + + # COM_所属部科を登録 + test_sql_data_list = create_db_data_from_csv(path.join(self.test_file_path, 'db_com_blng_sec_before_insert.csv')) + for test_data in test_sql_data_list: + insert_sql, insert_parameter = create_insert_sql_with_parameter( + 'src05.com_blng_sec', + test_data.keys(), + test_data.values() + ) + self.db.execute(insert_sql, insert_parameter) + + # Act + for line_number, line in enumerate(test_dat_file, start=1): + sut: com_dr_wrkplace_mapper.ComDrWrkplaceMapper = create_ultmarc_table_mapper_sut(line, self.db) + assert type(sut) is com_dr_wrkplace_mapper.ComDrWrkplaceMapper, f'{line_number}行目:マッパークラスが期通りか' + + sut.make_query() + sut.execute_queries() + + # Assert + # 期待値ファイルを読み込む + expect_dr_data_list = create_db_data_from_csv(path.join(self.test_file_path, 'expect_com_dr_wrkplace_insert.csv')) + primary_keys_dcf_dsf_inst_cd = [{'dcf_dsf_inst_cd': columns['dcf_dsf_inst_cd']} for columns in expect_dr_data_list] + primary_keys_dcf_pcf_dr_cd = [{'dcf_pcf_dr_cd': columns['dcf_pcf_dr_cd']} for columns in expect_dr_data_list] + # 複合主キーのため、1件ずつ取得して期待値を作る + actual_dr_data_list = [] + actual_dr_select_sql = """\ + SELECT * FROM src05.com_dr_wrkplace + WHERE + dcf_dsf_inst_cd = :dcf_dsf_inst_cd + AND dcf_pcf_dr_cd = :dcf_pcf_dr_cd\ + """ + actual_his_select_sql = """\ + SELECT * FROM src05.com_dr_wrkplace_his + WHERE + dcf_dsf_inst_cd = :dcf_dsf_inst_cd + AND dcf_pcf_dr_cd = :dcf_pcf_dr_cd + """ + for param_dcf_dsf_inst_cd, param_dcf_pcf_dr_cd in zip(primary_keys_dcf_dsf_inst_cd, primary_keys_dcf_pcf_dr_cd): + # COM_医師勤務先の取得 + actual_dr_data = self.db.execute_select( + actual_dr_select_sql, + {**param_dcf_dsf_inst_cd, **param_dcf_pcf_dr_cd}) + assert len(actual_dr_data) == 1, '1件取得できていること' + actual_dr_data_list.append(actual_dr_data[0]) + + # COM_医師勤務先履歴の取得 + # 取得できないこと + actual_his_data = self.db.execute_select( + actual_his_select_sql, + {**param_dcf_dsf_inst_cd, **param_dcf_pcf_dr_cd}) + assert len(actual_his_data) == 0, '履歴が作成されていないこと' + + assert len(actual_dr_data_list) == len(expect_dr_data_list), 'COM_医師勤務先が期待値通りの件数作成されていること' + + # 期待値検査 + ignore_columns = ['regist_ymd', 'sys_update_date', 'sys_regist_date'] + assert_table_results(actual_dr_data_list, expect_dr_data_list, ignore_col_name=ignore_columns) + # 動的日付項目の個別確認 + line_number = 0 + for actual_row, expect_row in zip(actual_dr_data_list, expect_dr_data_list): + line_number += 1 + for actual_col_name, expect_col_name in zip(actual_row, expect_row): + if actual_col_name in ignore_columns: + assert actual_row[actual_col_name] >= expect_row[expect_col_name], f'{line_number}行目:{actual_col_name}が、期待値以降であること' + + def test_update_record(self): + """ + Cases: + COM_DCF医師勤務先テーブルのレコードを更新する + Arranges: + - CSVデータを用意し、読み込む + - 更新対象となるレコードを登録する + Expects: + - COM_医師勤務先の登録内容が期待値と一致すること + - COM_医師勤務先履歴にデータが登録され、期待値と一致すること + """ + + # Arrange + # 処理日設定 + # 適用開始日と同値、適用終了日の+1日になる + self.batch_config.syor_date = '2020/02/23' + # テスト用のCSVを読み込む + test_dat_file = create_ultmarc_test_data_from_csv(path.join(self.test_file_path, 'com_dr_wrkplace_update.csv')) + # 一旦全データをDBから削除 + # COM_医師勤務先 + delete_sql, delete_parameter = create_delete_sql_with_parameter('src05.com_dr_wrkplace', {'1': '1'}) + self.db.execute(delete_sql, delete_parameter) + # COM_医師勤務先履歴 + delete_sql, delete_parameter = create_delete_sql_with_parameter('src05.com_dr_wrkplace_his', {'1': '1'}) + self.db.execute(delete_sql, delete_parameter) + # COM_所属部科 + delete_sql, delete_parameter = create_delete_sql_with_parameter('src05.com_blng_sec', {'1': '1'}) + self.db.execute(delete_sql, delete_parameter) + + # COM_医師勤務先を登録 + test_sql_data_list = create_db_data_from_csv(path.join(self.test_file_path, 'db_com_dr_wrkplace_before_update.csv')) + for test_data in test_sql_data_list: + insert_sql, insert_parameter = create_insert_sql_with_parameter( + 'src05.com_dr_wrkplace', + test_data.keys(), + test_data.values() + ) + self.db.execute(insert_sql, insert_parameter) + + # Act + for line_number, line in enumerate(test_dat_file, start=1): + sut: com_dr_wrkplace_mapper.ComDrWrkplaceMapper = create_ultmarc_table_mapper_sut(line, self.db) + assert type(sut) is com_dr_wrkplace_mapper.ComDrWrkplaceMapper, f'{line_number}行目:マッパークラスが期通りか' + + sut.make_query() + sut.execute_queries() + + # Assert + # 期待値ファイルを読み込む + expect_dr_data_list = create_db_data_from_csv(path.join(self.test_file_path, 'expect_com_dr_wrkplace_update.csv')) + expect_his_data_list = create_db_data_from_csv(path.join(self.test_file_path, 'expect_com_dr_wrkplace_his_update.csv')) + # 複合主キーのため、1件ずつ取得して期待値を作る + actual_dr_data_list = [] + actual_his_data_list = [] + actual_dr_select_sql = """\ + SELECT * FROM src05.com_dr_wrkplace + WHERE + dcf_dsf_inst_cd = :dcf_dsf_inst_cd + AND dcf_pcf_dr_cd = :dcf_pcf_dr_cd\ + """ + actual_his_select_sql = """\ + SELECT * FROM src05.com_dr_wrkplace_his + WHERE + dcf_dsf_inst_cd = :dcf_dsf_inst_cd + AND dcf_pcf_dr_cd = :dcf_pcf_dr_cd + """ + # COM_医師勤務先の取得 + primary_keys_dcf_dsf_inst_cd = [{'dcf_dsf_inst_cd': columns['dcf_dsf_inst_cd']} for columns in expect_dr_data_list] + primary_keys_dcf_pcf_dr_cd = [{'dcf_pcf_dr_cd': columns['dcf_pcf_dr_cd']} for columns in expect_dr_data_list] + for param_dcf_dsf_inst_cd, param_dcf_pcf_dr_cd in zip(primary_keys_dcf_dsf_inst_cd, primary_keys_dcf_pcf_dr_cd): + actual_dr_data = self.db.execute_select( + actual_dr_select_sql, + {**param_dcf_dsf_inst_cd, **param_dcf_pcf_dr_cd}) + assert len(actual_dr_data) == 1, '1件取得できていること' + actual_dr_data_list.append(actual_dr_data[0]) + + # COM_医師勤務先履歴の取得 + primary_keys_dcf_dsf_inst_cd = [{'dcf_dsf_inst_cd': columns['dcf_dsf_inst_cd']} for columns in expect_his_data_list] + primary_keys_dcf_pcf_dr_cd = [{'dcf_pcf_dr_cd': columns['dcf_pcf_dr_cd']} for columns in expect_his_data_list] + for param_dcf_dsf_inst_cd, param_dcf_pcf_dr_cd in zip(primary_keys_dcf_dsf_inst_cd, primary_keys_dcf_pcf_dr_cd): + actual_his_data = self.db.execute_select( + actual_his_select_sql, + {**param_dcf_dsf_inst_cd, **param_dcf_pcf_dr_cd}) + assert len(actual_dr_data) == 1, '1件取得できていること' + actual_his_data_list.append(actual_his_data[0]) + + assert len(actual_his_data_list) == len(expect_his_data_list), 'COM_医師勤務先が期待値通りの件数作成されていること' + assert len(actual_his_data_list) == len(expect_his_data_list), 'COM_医師勤務先履歴が期待値通りの件数作成されていること' + + # 期待値検査 + # COM_医師勤務先 + dr_ignore_columns = ['regist_ymd', 'update_ymd', 'sys_update_ymd', 'sys_update_date', 'sys_regist_date'] + assert_table_results(actual_dr_data_list, expect_dr_data_list, ignore_col_name=dr_ignore_columns) + # 動的日付項目の個別確認 + line_number = 0 + for actual_row, expect_row in zip(actual_dr_data_list, expect_dr_data_list): + line_number += 1 + for actual_col_name, expect_col_name in zip(actual_row, expect_row): + if actual_col_name in dr_ignore_columns: + if expect_row[expect_col_name] is None: + assert actual_row[actual_col_name] is None, f'{line_number}行目:{actual_col_name}が、登録されていないこと' + else: + assert actual_row[actual_col_name] >= expect_row[expect_col_name], f'{line_number}行目:{actual_col_name}が、期待値以降であること' + + # COM_医師勤務先履歴 + his_ignore_columns = ['dr_wrkplace_his_key', 'regist_ymd', 'update_ymd', 'sys_update_date', 'sys_regist_date'] + assert_table_results(actual_his_data_list, expect_his_data_list, ignore_col_name=his_ignore_columns) + # 動的日付項目の個別確認 + line_number = 0 + for actual_row, expect_row in zip(actual_dr_data_list, expect_dr_data_list): + line_number += 1 + for actual_col_name, expect_col_name in zip(actual_row, expect_row): + if actual_col_name in his_ignore_columns: + if expect_row[expect_col_name] is None: + assert actual_row[actual_col_name] is None, f'{line_number}行目:{actual_col_name}が、登録されていないこと' + else: + assert actual_row[actual_col_name] >= expect_row[expect_col_name], f'{line_number}行目:{actual_col_name}が、期待値以降であること' + + def test_delete_record(self): + """ + Cases: + COM_DCF医師勤務先テーブルのレコードを削除する + Arranges: + - CSVデータを用意し、読み込む + - 削除対象となるレコードを登録する + Expects: + - COM_医師勤務先の登録内容が期待値と一致すること + - COM_医師勤務先履歴にデータが登録されないこと + """ + + # Arrange + # 処理日設定 + self.batch_config.syor_date = '2020/02/24' + # テスト用のCSVを読み込む + test_dat_file = create_ultmarc_test_data_from_csv(path.join(self.test_file_path, 'com_dr_wrkplace_delete.csv')) + # 一旦全データをDBから削除 + # COM_医師勤務先 + delete_sql, delete_parameter = create_delete_sql_with_parameter('src05.com_dr_wrkplace', {'1': '1'}) + self.db.execute(delete_sql, delete_parameter) + # COM_医師勤務先履歴 + delete_sql, delete_parameter = create_delete_sql_with_parameter('src05.com_dr_wrkplace_his', {'1': '1'}) + self.db.execute(delete_sql, delete_parameter) + # COM_所属部科 + delete_sql, delete_parameter = create_delete_sql_with_parameter('src05.com_blng_sec', {'1': '1'}) + self.db.execute(delete_sql, delete_parameter) + + # COM_医師勤務先を登録 + test_sql_data_list = create_db_data_from_csv(path.join(self.test_file_path, 'db_com_dr_wrkplace_before_delete.csv')) + for test_data in test_sql_data_list: + insert_sql, insert_parameter = create_insert_sql_with_parameter( + 'src05.com_dr_wrkplace', + test_data.keys(), + test_data.values() + ) + self.db.execute(insert_sql, insert_parameter) + + # COM_医師勤務先履歴を登録 + test_sql_data_list = create_db_data_from_csv(path.join(self.test_file_path, 'db_com_dr_wrkplace_his_before_delete.csv')) + for test_data in test_sql_data_list: + insert_sql, insert_parameter = create_insert_sql_with_parameter( + 'src05.com_dr_wrkplace_his', + test_data.keys(), + test_data.values() + ) + self.db.execute(insert_sql, insert_parameter) + + # COM_所属部科を登録 + test_sql_data_list = create_db_data_from_csv(path.join(self.test_file_path, 'db_com_blng_sec_before_delete.csv')) + for test_data in test_sql_data_list: + insert_sql, insert_parameter = create_insert_sql_with_parameter( + 'src05.com_blng_sec', + test_data.keys(), + test_data.values() + ) + self.db.execute(insert_sql, insert_parameter) + + # Act + for line_number, line in enumerate(test_dat_file, start=1): + sut: com_dr_wrkplace_mapper.ComDrWrkplaceMapper = create_ultmarc_table_mapper_sut(line, self.db) + assert type(sut) is com_dr_wrkplace_mapper.ComDrWrkplaceMapper, f'{line_number}行目:マッパークラスが期通りか' + + sut.make_query() + sut.execute_queries() + + # Assert + # 期待値ファイルを読み込む + expect_dr_data_list = create_db_data_from_csv(path.join(self.test_file_path, 'expect_com_dr_wrkplace_delete.csv')) + expect_his_data_list = create_db_data_from_csv(path.join(self.test_file_path, 'expect_com_dr_wrkplace_his_delete.csv')) + # 複合主キーのため、1件ずつ取得して期待値を作る + actual_dr_data_list = [] + actual_his_data_list = [] + actual_dr_select_sql = """\ + SELECT * FROM src05.com_dr_wrkplace + WHERE + dcf_dsf_inst_cd = :dcf_dsf_inst_cd + AND dcf_pcf_dr_cd = :dcf_pcf_dr_cd\ + """ + actual_his_select_sql = """\ + SELECT * FROM src05.com_dr_wrkplace_his + WHERE + dcf_dsf_inst_cd = :dcf_dsf_inst_cd + AND dcf_pcf_dr_cd = :dcf_pcf_dr_cd + """ + + # COM_医師勤務先の取得 + primary_keys_dcf_dsf_inst_cd = [{'dcf_dsf_inst_cd': columns['dcf_dsf_inst_cd']} for columns in expect_dr_data_list] + primary_keys_dcf_pcf_dr_cd = [{'dcf_pcf_dr_cd': columns['dcf_pcf_dr_cd']} for columns in expect_dr_data_list] + for param_dcf_dsf_inst_cd, param_dcf_pcf_dr_cd in zip(primary_keys_dcf_dsf_inst_cd, primary_keys_dcf_pcf_dr_cd): + actual_dr_data = self.db.execute_select( + actual_dr_select_sql, + {**param_dcf_dsf_inst_cd, **param_dcf_pcf_dr_cd}) + assert len(actual_dr_data) == 1, '1件取得できていること' + actual_dr_data_list.append(actual_dr_data[0]) + + # COM_医師勤務先履歴の取得 + primary_keys_dcf_dsf_inst_cd = [{'dcf_dsf_inst_cd': columns['dcf_dsf_inst_cd']} for columns in expect_his_data_list] + primary_keys_dcf_pcf_dr_cd = [{'dcf_pcf_dr_cd': columns['dcf_pcf_dr_cd']} for columns in expect_his_data_list] + for param_dcf_dsf_inst_cd, param_dcf_pcf_dr_cd in zip(primary_keys_dcf_dsf_inst_cd, primary_keys_dcf_pcf_dr_cd): + # COM_医師勤務先履歴の取得 + actual_his_data = self.db.execute_select( + actual_his_select_sql, + {**param_dcf_dsf_inst_cd, **param_dcf_pcf_dr_cd}) + assert len(actual_his_data) == 1, '1件取得できていること' + actual_his_data_list.append(actual_his_data[0]) + + assert len(actual_dr_data_list) == len(expect_dr_data_list), 'COM_医師勤務先が期待値通りの件数作成されていること' + assert len(actual_his_data_list) == len(expect_his_data_list), 'COM_医師勤務先履歴が期待値通りの件数作成されていること' + + # 期待値検査 + # COM_医師勤務先 + dr_ignore_columns = ['regist_ymd', 'update_ymd', 'sys_update_ymd', 'sys_update_date', 'sys_regist_date'] + assert_table_results(actual_dr_data_list, expect_dr_data_list, ignore_col_name=dr_ignore_columns) + # 動的日付項目の個別確認 + line_number = 0 + for actual_row, expect_row in zip(actual_dr_data_list, expect_dr_data_list): + line_number += 1 + for actual_col_name, expect_col_name in zip(actual_row, expect_row): + if actual_col_name in dr_ignore_columns: + if expect_row[expect_col_name] is None: + assert actual_row[actual_col_name] is None, f'{line_number}行目:{actual_col_name}が、登録されていないこと' + else: + assert actual_row[actual_col_name] >= expect_row[expect_col_name], f'{line_number}行目:{actual_col_name}が、期待値以降であること' + + # COM_医師勤務先履歴 + his_ignore_columns = ['dr_wrkplace_his_key', 'regist_ymd', 'update_ymd', 'sys_update_date', 'sys_regist_date'] + assert_table_results(actual_his_data_list, expect_his_data_list, ignore_col_name=his_ignore_columns) + # 動的日付項目の個別確認 + line_number = 0 + for actual_row, expect_row in zip(actual_dr_data_list, expect_dr_data_list): + line_number += 1 + for actual_col_name, expect_col_name in zip(actual_row, expect_row): + if actual_col_name in his_ignore_columns: + if expect_row[expect_col_name] is None: + assert actual_row[actual_col_name] is None, f'{line_number}行目:{actual_col_name}が、登録されていないこと' + else: + assert actual_row[actual_col_name] >= expect_row[expect_col_name], f'{line_number}行目:{actual_col_name}が、期待値以降であること' diff --git a/ecs/jskult-batch-daily/tests/batch/ultmarc/utmp_tables/table_mapper/com_hamtec/__init__.py b/ecs/jskult-batch-daily/tests/batch/ultmarc/utmp_tables/table_mapper/com_hamtec/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/ecs/jskult-batch-daily/tests/batch/ultmarc/utmp_tables/table_mapper/com_hamtec/com_hamtec_delete.csv b/ecs/jskult-batch-daily/tests/batch/ultmarc/utmp_tables/table_mapper/com_hamtec/com_hamtec_delete.csv new file mode 100644 index 00000000..7cbc586b --- /dev/null +++ b/ecs/jskult-batch-daily/tests/batch/ultmarc/utmp_tables/table_mapper/com_hamtec/com_hamtec_delete.csv @@ -0,0 +1,7 @@ +"021","001",,"A","20141113","20141114", +"021","002","1","A","20141113","20141114","電磁波温熱療法(放射線療法と併用しないもの)" +"021","003","2","A","20141113","20141114","微小銅線による脳血管性病変に対しての電気的凝固治療" +"021","004","1","C","20141113","20141114","顔面骨、頭蓋骨の観血的移動術" +"021","005","1","A","20141113","20141114","培養細胞による先天性代謝異常診断(胎児又は新生児に係るものに限る)" +"021","006","1","A","20141113","20141114","造血器腫瘍のDNA診断" +"021","007","2","A","20141113","20141114","重症肥満の外科治療法" \ No newline at end of file diff --git a/ecs/jskult-batch-daily/tests/batch/ultmarc/utmp_tables/table_mapper/com_hamtec/com_hamtec_insert.csv b/ecs/jskult-batch-daily/tests/batch/ultmarc/utmp_tables/table_mapper/com_hamtec/com_hamtec_insert.csv new file mode 100644 index 00000000..31e575d3 --- /dev/null +++ b/ecs/jskult-batch-daily/tests/batch/ultmarc/utmp_tables/table_mapper/com_hamtec/com_hamtec_insert.csv @@ -0,0 +1,6 @@ +"021","001","2","A","20141113","20141114","直流電流による骨電気治療法" +"021","002","1","A","20141113","20141114","電磁波温熱療法(放射線療法と併用しないもの)" +"021","003","2","A","20141113","20141114","微小銅線による脳血管性病変に対しての電気的凝固治療" +"021","004","1","A","20141113","20141114","顔面骨、頭蓋骨の観血的移動術" +"021","005","1","A","20141113","20141114","造血器腫瘍のDNA診断" +"021","006","1","A","20141113","20141114","培養細胞による先天性代謝異常診断(胎児又は新生児に係るものに限る)" \ No newline at end of file diff --git a/ecs/jskult-batch-daily/tests/batch/ultmarc/utmp_tables/table_mapper/com_hamtec/com_hamtec_update.csv b/ecs/jskult-batch-daily/tests/batch/ultmarc/utmp_tables/table_mapper/com_hamtec/com_hamtec_update.csv new file mode 100644 index 00000000..43b1e27c --- /dev/null +++ b/ecs/jskult-batch-daily/tests/batch/ultmarc/utmp_tables/table_mapper/com_hamtec/com_hamtec_update.csv @@ -0,0 +1,6 @@ +"021","001",,"B","20141113","20141114", +"021","002","1","B","20141113","20141114","電磁波温熱療法(放射線療法と併用しないもの)" +"021","003","2","B","20141113","20141114","微小銅線による脳血管性病変に対しての電気的凝固治療" +"021","004","1","B","20141113","20141114","顔面骨、頭蓋骨の観血的移動術" +"021","005","1","B","20141113","20141114","培養細胞による先天性代謝異常診断(胎児又は新生児に係るものに限る)" +"021","006","1","B","20141113","20141114","造血器腫瘍のDNA診断" \ No newline at end of file diff --git a/ecs/jskult-batch-daily/tests/batch/ultmarc/utmp_tables/table_mapper/com_hamtec/db_com_hamtec_before_delete.csv b/ecs/jskult-batch-daily/tests/batch/ultmarc/utmp_tables/table_mapper/com_hamtec/db_com_hamtec_before_delete.csv new file mode 100644 index 00000000..ac7de33a --- /dev/null +++ b/ecs/jskult-batch-daily/tests/batch/ultmarc/utmp_tables/table_mapper/com_hamtec/db_com_hamtec_before_delete.csv @@ -0,0 +1,7 @@ +"hamtec_cd","hamtec_div","hamtec_name","regist_ymd","update_ymd","delete_ymd","regist_date","create_user","update_date","update_user","sys_regist_date","regist_prgm_id","sys_update_date","update_prgm_id" +"001","2","直流電流による骨電気治療法","20171018","NULL","NULL","NULL","NULL","NULL","NULL","2017/10/18 17:03:10","clsComHamtec","2017/10/18 17:03:10","clsComHamtec" +"002","1","電磁波温熱療法(放射線療法と併用しないもの)","20171018","20171018","NULL","NULL","NULL","NULL","NULL","2017/10/18 17:03:10","clsComHamtec","2017/10/18 17:08:06","clsComHamtec" +"003","2","微小銅線による脳血管性病変に対しての電気的凝固治療","20171018","20171018","NULL","NULL","NULL","NULL","NULL","2017/10/18 17:03:10","clsComHamtec","2017/10/18 17:08:06","clsComHamtec" +"004","1","顔面骨、頭蓋骨の観血的移動術","20171018","20171018","NULL","NULL","NULL","NULL","NULL","2017/10/18 17:03:10","clsComHamtec","2017/10/18 17:08:06","clsComHamtec" +"005","1","培養細胞による先天性代謝異常診断(胎児又は新生児に係るものに限る)","20171018","20171018","NULL","NULL","NULL","NULL","NULL","2017/10/18 17:03:10","clsComHamtec","2017/10/18 17:08:06","clsComHamtec" +"006","1","造血器腫瘍のDNA診断","20171018","20171018","NULL","NULL","NULL","NULL","NULL","2017/10/18 17:03:10","clsComHamtec","2017/10/18 17:08:06","clsComHamtec" diff --git a/ecs/jskult-batch-daily/tests/batch/ultmarc/utmp_tables/table_mapper/com_hamtec/db_com_hamtec_before_update.csv b/ecs/jskult-batch-daily/tests/batch/ultmarc/utmp_tables/table_mapper/com_hamtec/db_com_hamtec_before_update.csv new file mode 100644 index 00000000..f6d16401 --- /dev/null +++ b/ecs/jskult-batch-daily/tests/batch/ultmarc/utmp_tables/table_mapper/com_hamtec/db_com_hamtec_before_update.csv @@ -0,0 +1,7 @@ +"hamtec_cd","hamtec_div","hamtec_name","regist_ymd","update_ymd","delete_ymd","regist_date","create_user","update_date","update_user","sys_regist_date","regist_prgm_id","sys_update_date","update_prgm_id" +"001","2","直流電流による骨電気治療法","20171018","NULL","NULL","NULL","NULL","NULL","NULL","2017/10/18 17:03:10","clsComHamtec","2017/10/18 17:03:10","clsComHamtec" +"002","1","電磁波温熱療法(放射線療法と併用しないもの)","20171018","NULL","NULL","NULL","NULL","NULL","NULL","2017/10/18 17:03:10","clsComHamtec","2017/10/18 17:08:06","clsComHamtec" +"003","2","微小銅線による脳血管性病変に対しての電気的凝固治療","20171018","NULL","NULL","NULL","NULL","NULL","NULL","2017/10/18 17:03:10","clsComHamtec","2017/10/18 17:08:06","clsComHamtec" +"004","1","顔面骨、頭蓋骨の観血的移動術","20171018","NULL","NULL","NULL","NULL","NULL","NULL","2017/10/18 17:03:10","clsComHamtec","2017/10/18 17:08:06","clsComHamtec" +"005","1","培養細胞による先天性代謝異常診断(胎児又は新生児に係るものに限る)","20171018","NULL","NULL","NULL","NULL","NULL","NULL","2017/10/18 17:03:10","clsComHamtec","2017/10/18 17:08:06","clsComHamtec" +"006","1","造血器腫瘍のDNA診断","20171018","NULL","NULL","NULL","NULL","NULL","NULL","2017/10/18 17:03:10","clsComHamtec","2017/10/18 17:08:06","clsComHamtec" \ No newline at end of file diff --git a/ecs/jskult-batch-daily/tests/batch/ultmarc/utmp_tables/table_mapper/com_hamtec/expect_com_hamtec_delete.csv b/ecs/jskult-batch-daily/tests/batch/ultmarc/utmp_tables/table_mapper/com_hamtec/expect_com_hamtec_delete.csv new file mode 100644 index 00000000..9b5b62d9 --- /dev/null +++ b/ecs/jskult-batch-daily/tests/batch/ultmarc/utmp_tables/table_mapper/com_hamtec/expect_com_hamtec_delete.csv @@ -0,0 +1,8 @@ +"hamtec_cd","hamtec_div","hamtec_name","regist_ymd","update_ymd","delete_ymd","regist_date","create_user","update_date","update_user","sys_regist_date","regist_prgm_id","sys_update_date","update_prgm_id" +"001","2","直流電流による骨電気治療法","20171018","NULL","NULL","NULL","NULL","NULL","NULL","2017/10/18 17:03:10","clsComHamtec","2017/10/18 17:03:10","clsComHamtec" +"002","1","電磁波温熱療法(放射線療法と併用しないもの)","20171018","20171018","NULL","NULL","NULL","NULL","NULL","2017/10/18 17:03:10","clsComHamtec","2017/10/18 17:21:01","com_hamtec_mapper" +"003","2","微小銅線による脳血管性病変に対しての電気的凝固治療","20171018","20171018","NULL","NULL","NULL","NULL","NULL","2017/10/18 17:03:10","clsComHamtec","2017/10/18 17:21:01","com_hamtec_mapper" +"004","1","顔面骨、頭蓋骨の観血的移動術","20171018","20171018","20171018","NULL","NULL","NULL","NULL","2017/10/18 17:03:10","clsComHamtec","2017/10/18 17:21:01","com_hamtec_mapper" +"005","1","培養細胞による先天性代謝異常診断(胎児又は新生児に係るものに限る)","20171018","20171018","NULL","NULL","NULL","NULL","NULL","2017/10/18 17:03:10","clsComHamtec","2017/10/18 17:21:01","com_hamtec_mapper" +"006","1","造血器腫瘍のDNA診断","20171018","20171018","NULL","NULL","NULL","NULL","NULL","2017/10/18 17:03:10","clsComHamtec","2017/10/18 17:21:01","com_hamtec_mapper" +"007","2","重症肥満の外科治療法","20171018","NULL","NULL","NULL","NULL","NULL","NULL","2017/10/18 17:21:01","com_hamtec_mapper","2017/10/18 17:21:01","com_hamtec_mapper" diff --git a/ecs/jskult-batch-daily/tests/batch/ultmarc/utmp_tables/table_mapper/com_hamtec/expect_com_hamtec_insert.csv b/ecs/jskult-batch-daily/tests/batch/ultmarc/utmp_tables/table_mapper/com_hamtec/expect_com_hamtec_insert.csv new file mode 100644 index 00000000..35b58442 --- /dev/null +++ b/ecs/jskult-batch-daily/tests/batch/ultmarc/utmp_tables/table_mapper/com_hamtec/expect_com_hamtec_insert.csv @@ -0,0 +1,7 @@ +"hamtec_cd","hamtec_div","hamtec_name","regist_ymd","update_ymd","delete_ymd","regist_date","create_user","update_date","update_user","sys_regist_date","regist_prgm_id","sys_update_date","update_prgm_id" +"001","2","直流電流による骨電気治療法","20171018","NULL","NULL","NULL","NULL","NULL","NULL","2017/10/18 16:24:26","com_hamtec_mapper","2017/10/18 16:24:26","com_hamtec_mapper" +"002","1","電磁波温熱療法(放射線療法と併用しないもの)","20171018","NULL","NULL","NULL","NULL","NULL","NULL","2017/10/18 16:24:26","com_hamtec_mapper","2017/10/18 16:24:26","com_hamtec_mapper" +"003","2","微小銅線による脳血管性病変に対しての電気的凝固治療","20171018","NULL","NULL","NULL","NULL","NULL","NULL","2017/10/18 16:24:26","com_hamtec_mapper","2017/10/18 16:24:26","com_hamtec_mapper" +"004","1","顔面骨、頭蓋骨の観血的移動術","20171018","NULL","NULL","NULL","NULL","NULL","NULL","2017/10/18 16:24:26","com_hamtec_mapper","2017/10/18 16:24:26","com_hamtec_mapper" +"005","1","造血器腫瘍のDNA診断","20171018","NULL","NULL","NULL","NULL","NULL","NULL","2017/10/18 16:24:26","com_hamtec_mapper","2017/10/18 16:24:26","com_hamtec_mapper" +"006","1","培養細胞による先天性代謝異常診断(胎児又は新生児に係るものに限る)","20171018","NULL","NULL","NULL","NULL","NULL","NULL","2017/10/18 16:24:26","com_hamtec_mapper","2017/10/18 16:24:26","com_hamtec_mapper" diff --git a/ecs/jskult-batch-daily/tests/batch/ultmarc/utmp_tables/table_mapper/com_hamtec/expect_com_hamtec_update.csv b/ecs/jskult-batch-daily/tests/batch/ultmarc/utmp_tables/table_mapper/com_hamtec/expect_com_hamtec_update.csv new file mode 100644 index 00000000..1d9a61d4 --- /dev/null +++ b/ecs/jskult-batch-daily/tests/batch/ultmarc/utmp_tables/table_mapper/com_hamtec/expect_com_hamtec_update.csv @@ -0,0 +1,7 @@ +"hamtec_cd","hamtec_div","hamtec_name","regist_ymd","update_ymd","delete_ymd","regist_date","create_user","update_date","update_user","sys_regist_date","regist_prgm_id","sys_update_date","update_prgm_id" +"001","2","直流電流による骨電気治療法","20171018","NULL","NULL","NULL","NULL","NULL","NULL","2017/10/18 17:03:10","clsComHamtec","2017/10/18 17:03:10","clsComHamtec" +"002","1","電磁波温熱療法(放射線療法と併用しないもの)","20171018","20171018","NULL","NULL","NULL","NULL","NULL","2017/10/18 17:03:10","clsComHamtec","2017/10/18 17:08:06","com_hamtec_mapper" +"003","2","微小銅線による脳血管性病変に対しての電気的凝固治療","20171018","20171018","NULL","NULL","NULL","NULL","NULL","2017/10/18 17:03:10","clsComHamtec","2017/10/18 17:08:06","com_hamtec_mapper" +"004","1","顔面骨、頭蓋骨の観血的移動術","20171018","20171018","NULL","NULL","NULL","NULL","NULL","2017/10/18 17:03:10","clsComHamtec","2017/10/18 17:08:06","com_hamtec_mapper" +"005","1","培養細胞による先天性代謝異常診断(胎児又は新生児に係るものに限る)","20171018","20171018","NULL","NULL","NULL","NULL","NULL","2017/10/18 17:03:10","clsComHamtec","2017/10/18 17:08:06","com_hamtec_mapper" +"006","1","造血器腫瘍のDNA診断","20171018","20171018","NULL","NULL","NULL","NULL","NULL","2017/10/18 17:03:10","clsComHamtec","2017/10/18 17:08:06","com_hamtec_mapper" \ No newline at end of file diff --git a/ecs/jskult-batch-daily/tests/batch/ultmarc/utmp_tables/table_mapper/com_hamtec/test_com_hamtec_mapper.py b/ecs/jskult-batch-daily/tests/batch/ultmarc/utmp_tables/table_mapper/com_hamtec/test_com_hamtec_mapper.py new file mode 100644 index 00000000..08c773f9 --- /dev/null +++ b/ecs/jskult-batch-daily/tests/batch/ultmarc/utmp_tables/table_mapper/com_hamtec/test_com_hamtec_mapper.py @@ -0,0 +1,198 @@ +import os.path as path +from datetime import datetime + +import pytest + +from src.batch.common.batch_config import BatchConfig +from src.batch.ultmarc.utmp_tables.table_mapper.concrete import \ + com_hamtec_mapper +from src.db.database import Database +from tests.testing_utility import (assert_table_results, + create_db_data_from_csv, + create_delete_sql_with_parameter, + create_insert_sql_with_parameter, + create_ultmarc_table_mapper_sut, + create_ultmarc_test_data_from_csv) + + +class TestComHamtecMapper: + """レイアウト区分021: COM_高度先進医療""" + + db: Database + batch_config: BatchConfig + test_file_path: str = path.dirname(__file__) + + @pytest.fixture(autouse=True, scope='function') + def pre_test(self, database: Database): + """テスト実行前後処理""" + self.batch_config = BatchConfig.get_instance() + # setup + self.db = database + self.db.connect() + self.db.begin() + + # testing + yield + + # teardown + self.db.rollback() + self.db.disconnect() + + def test_insert_record(self): + """ + Cases: + COM_高度先進医療テーブルにレコードを登録する + Arranges: + - CSVデータを用意し、読み込む + - 追加対象となるレコードを削除する + Expects: + - 登録内容が期待値と一致すること + """ + + # Arrange + # 処理日設定 + self.batch_config.syor_date = datetime.strftime(datetime.now(), '%Y/%m/%d') + # テスト用のCSVを読み込む + test_dat_file = create_ultmarc_test_data_from_csv(path.join(self.test_file_path, 'com_hamtec_insert.csv')) + # 一旦全データをDBから削除 + delete_sql, delete_parameter = create_delete_sql_with_parameter('src05.com_hamtec', {'1': '1'}) + self.db.execute(delete_sql, delete_parameter) + + # Act + for line_number, line in enumerate(test_dat_file, start=1): + sut: com_hamtec_mapper.ComHamtecMapper = create_ultmarc_table_mapper_sut(line, self.db) + assert type(sut) is com_hamtec_mapper.ComHamtecMapper, f'{line_number}行目:マッパークラスが期通りか' + + sut.make_query() + sut.execute_queries() + + # Assert + # 期待値ファイルを読み込む + expect_data_list = create_db_data_from_csv(path.join(self.test_file_path, 'expect_com_hamtec_insert.csv')) + primary_keys = [f"'{primary_key['hamtec_cd']}'" for primary_key in expect_data_list] + actual_select_sql = f"SELECT * FROM src05.com_hamtec WHERE hamtec_cd IN ({','.join(primary_keys)})" + actual_data_list = self.db.execute_select(actual_select_sql) + # 期待値検査 + ignore_columns = ['regist_ymd', 'sys_update_date', 'sys_regist_date'] + assert_table_results(actual_data_list, expect_data_list, ignore_col_name=ignore_columns) + line_number = 0 + # 動的日付項目の個別確認 + for actual_row, expect_row in zip(actual_data_list, expect_data_list): + line_number += 1 + for actual_col_name, expect_col_name in zip(actual_row, expect_row): + if actual_col_name in ['regist_ymd', 'sys_regist_date', 'sys_update_date']: + assert actual_row[actual_col_name] >= expect_row[expect_col_name], f'{line_number}行目:{actual_col_name}が、期待値以降であること' + + def test_update_record(self): + """ + Cases: + COM_高度先進医療テーブルのレコードを更新する + Arranges: + - CSVデータを用意し、読み込む + - 更新対象となるレコードを登録する + Expects: + - 登録内容が期待値と一致すること + """ + + # Arrange + # 処理日設定 + self.batch_config.syor_date = datetime.strftime(datetime.now(), '%Y/%m/%d') + # テスト用のCSVを読み込む + test_dat_file = create_ultmarc_test_data_from_csv(path.join(self.test_file_path, 'com_hamtec_update.csv')) + # 一旦全データをDBから削除 + delete_sql, delete_parameter = create_delete_sql_with_parameter('src05.com_hamtec', {'1': '1'}) + self.db.execute(delete_sql, delete_parameter) + # テストデータをDBに登録 + # DBデータを読み込む + test_sql_data_list = create_db_data_from_csv(path.join(self.test_file_path, 'db_com_hamtec_before_update.csv')) + for test_data in test_sql_data_list: + insert_sql, insert_parameter = create_insert_sql_with_parameter( + 'src05.com_hamtec', + test_data.keys(), + test_data.values() + ) + self.db.execute(insert_sql, insert_parameter) + + # Act + for line_number, line in enumerate(test_dat_file, start=1): + sut: com_hamtec_mapper.ComHamtecMapper = create_ultmarc_table_mapper_sut(line, self.db) + assert type(sut) is com_hamtec_mapper.ComHamtecMapper, f'{line_number}行目:マッパークラスが期通りか' + sut.make_query() + sut.execute_queries() + + # Assert + # 期待値ファイルを読み込む + expect_data_list = create_db_data_from_csv(path.join(self.test_file_path, 'expect_com_hamtec_update.csv')) + primary_keys = [f"'{primary_key['hamtec_cd']}'" for primary_key in expect_data_list] + actual_select_sql = f"SELECT * FROM src05.com_hamtec WHERE hamtec_cd IN ({','.join(primary_keys)})" + actual_data_list = self.db.execute_select(actual_select_sql) + # 期待値検査 + ignore_columns = ['regist_ymd', 'update_ymd', 'sys_update_date', 'sys_regist_date'] + assert_table_results(actual_data_list, expect_data_list, ignore_col_name=ignore_columns) + line_number = 0 + # 動的日付項目の個別確認 + for actual_row, expect_row in zip(actual_data_list, expect_data_list): + line_number += 1 + for actual_col_name, expect_col_name in zip(actual_row, expect_row): + if actual_col_name in ignore_columns: + if expect_row[expect_col_name] is None: + assert actual_row[actual_col_name] is None, f'{line_number}行目:{actual_col_name}が、登録されていないこと' + else: + assert actual_row[actual_col_name] >= expect_row[expect_col_name], f'{line_number}行目:{actual_col_name}が、期待値以降であること' + + def test_logical_delete(self): + """ + Cases: + COM_高度先進医療テーブルのレコードを1件論理削除する + Arranges: + - CSVデータを用意し、読み込む + - 削除対象となるレコードを登録する + Expects: + - 登録内容が期待値と一致すること + """ + + # Arrange + # 処理日設定 + self.batch_config.syor_date = datetime.strftime(datetime.now(), '%Y/%m/%d') + # テスト用のCSVを読み込む + test_dat_file = create_ultmarc_test_data_from_csv(path.join(self.test_file_path, 'com_hamtec_delete.csv')) + # 一旦全データをDBから削除 + delete_sql, delete_parameter = create_delete_sql_with_parameter('src05.com_hamtec', {'1': '1'}) + self.db.execute(delete_sql, delete_parameter) + # テストデータをDBに登録 + # DBデータを読み込む + test_sql_data_list = create_db_data_from_csv(path.join(self.test_file_path, 'db_com_hamtec_before_delete.csv')) + for test_data in test_sql_data_list: + insert_sql, insert_parameter = create_insert_sql_with_parameter( + 'src05.com_hamtec', + test_data.keys(), + test_data.values() + ) + self.db.execute(insert_sql, insert_parameter) + + # Act + for line_number, line in enumerate(test_dat_file, start=1): + sut: com_hamtec_mapper.ComHamtecMapper = create_ultmarc_table_mapper_sut(line, self.db) + assert type(sut) is com_hamtec_mapper.ComHamtecMapper, f'{line_number}行目:マッパークラスが期通りか' + sut.make_query() + sut.execute_queries() + + # Assert + # 期待値ファイルを読み込む + expect_data_list = create_db_data_from_csv(path.join(self.test_file_path, 'expect_com_hamtec_delete.csv')) + primary_keys = [f"'{primary_key['hamtec_cd']}'" for primary_key in expect_data_list] + actual_select_sql = f"SELECT * FROM src05.com_hamtec WHERE hamtec_cd IN ({','.join(primary_keys)})" + actual_data_list = self.db.execute_select(actual_select_sql) + # 期待値検査 + ignore_columns = ['regist_ymd', 'update_ymd', 'delete_ymd', 'sys_update_date', 'sys_regist_date'] + assert_table_results(actual_data_list, expect_data_list, ignore_col_name=ignore_columns) + # 動的日付項目の個別確認 + line_number = 0 + for actual_row, expect_row in zip(actual_data_list, expect_data_list): + line_number += 1 + for actual_col_name, expect_col_name in zip(actual_row, expect_row): + if actual_col_name in ignore_columns: + if expect_row[expect_col_name] is None: + assert actual_row[actual_col_name] is None, f'{line_number}行目:{actual_col_name}が、登録されていないこと' + else: + assert actual_row[actual_col_name] >= expect_row[expect_col_name], f'{line_number}行目:{actual_col_name}が、期待値以降であること' diff --git a/ecs/jskult-batch-daily/tests/conftest.py b/ecs/jskult-batch-daily/tests/conftest.py new file mode 100644 index 00000000..a03a8638 --- /dev/null +++ b/ecs/jskult-batch-daily/tests/conftest.py @@ -0,0 +1,11 @@ +"""共通テストフィクスチャ""" + +import pytest + +from src.db.database import Database + + +@pytest.fixture +def database() -> Database: + """データベース接続モジュールを作成""" + return Database.get_instance() diff --git a/ecs/jskult-batch-daily/tests/testing_utility.py b/ecs/jskult-batch-daily/tests/testing_utility.py new file mode 100644 index 00000000..e95da8e7 --- /dev/null +++ b/ecs/jskult-batch-daily/tests/testing_utility.py @@ -0,0 +1,168 @@ +"""テスト用共通処理関数""" +import csv +import tempfile +from datetime import datetime + +from src.batch.ultmarc.datfile import DatFile, DatFileLine +from src.batch.ultmarc.utmp_tables.table_mapper.ultmarc_table_mapper import \ + UltmarcTableMapper +from src.batch.ultmarc.utmp_tables.ultmarc_table_mapper_factory import \ + UltmarcTableMapperFactory +from src.db.database import Database + + +def create_ultmarc_test_data_from_csv(file_path: str) -> DatFile: + """ファイルから、アルトマーク取り込み用のテストデータを作成する + + Args: + file_path (str): csvファイルのパス + + Returns: + DatFile: データファイルオブジェクト + """ + + # 一度、Shift-JISファイルで書き出す + with open(file_path, encoding='utf8') as csv_file, tempfile.NamedTemporaryFile('w', encoding='cp932') as tmp_file: + tmp_file.write(csv_file.read()) + tmp_file.seek(0) + tmpfile_path = tmp_file.name + dat_file = DatFile.from_path(tmpfile_path) + + return dat_file + + +def create_db_data_from_csv(file_path: str) -> list[dict]: + """ファイルから、DBの期待値データを作成する + + Args: + file_path (str): csvファイルのパス + + Returns: + DatFile: データファイルオブジェクト + """ + + with open(file_path, encoding='utf8') as csv_file: + # ヘッダ行を取得し、改行とクォートを取り除く。 + header = csv_file.readline().strip('\n').replace('"', '').split(',') + reader = csv.DictReader(csv_file, fieldnames=header) + rows = [r for r in reader] + + # データ型変換 + for row in rows: + for k, v in row.items(): + converted_value = v + if v == 'NULL': + converted_value = None + if is_valid_date_format(v, '%Y/%m/%d') is True: # YYYY/MM/DD + converted_value = datetime.strptime(v, '%Y/%m/%d').date() + if is_valid_date_format(v, '%Y-%m-%d') is True: # YYYY-MM-DD + converted_value = datetime.strptime(v, '%Y-%m-%d').date() + if is_valid_date_format(v, '%Y/%m/%d %H:%M:%S') is True: # YYYY/MM/DD HH:MM:SS + converted_value = datetime.strptime(v, '%Y/%m/%d %H:%M:%S') + if is_valid_date_format(v, '%Y-%m-%d %H:%M:%S') is True: # YYYY-MM-DD HH:MM:SS + converted_value = datetime.strptime(v, '%Y-%m-%d %H:%M:%S') + + row[k] = converted_value + + return rows + + +def create_insert_sql_with_parameter(table_name: str, column_names: list[str], test_data: list[str]) -> tuple[str, dict]: + """INSERT文と登録値のパラメータを返す + + Args: + table_name (str): スキーマ完全修飾のテーブル名(例:src05.com_alma) + column_names (list[str]): カラム名のリスト + test_data (list[str]): 値のリスト + + Returns: + tuple[str, dict]: [0]→INSERT文,[1]→値のパラメータ + """ + placeholders = ','.join([f':{column_name}' for column_name in column_names]) + insert_sql = f"INSERT INTO {table_name} ({','.join(column_names)}) VALUES({placeholders})" + parameter = {k: v for k, v in zip(column_names, test_data)} + + return insert_sql, parameter + + +def create_delete_sql_with_parameter(table_name: str, delete_parameter: dict[str, str]): + """DELETE文と削除条件値のパラメータを返す + + Args: + table_name (str): スキーマ完全修飾のテーブル名(例:src05.com_alma) + delete_parameter (dict[str, str]): 削除条件に使用するカラム名と値の辞書 + + Returns: + tuple[str, dict]: [0]→DELETE文,[1]→値のパラメータ + """ + where_clause_list = [] + for k in delete_parameter: + where_clause_list.append(f'{k} = :{k}') + where_clauses = ' AND '.join(where_clause_list) + delete_sql = f"DELETE FROM {table_name} WHERE {where_clauses}" + + return delete_sql, delete_parameter + + +def create_ultmarc_table_mapper_sut(line: DatFileLine, db: Database) -> UltmarcTableMapper: + """アルトマークテーブルマッパーのインスタンスを返す + + Args: + line (DatFileLine): テストデータの1行 + db (Database): 接続済みDBインスタンス + + Returns: + UltmarcTableMapper: マッパークラス + """ + layout_class = line.layout_class + factory = UltmarcTableMapperFactory() + sut = factory.create( + layout_class=layout_class, + records=line.records, + db=db + ) + + return sut + + +def is_valid_date_format(date_str: str, date_format): + """日付文字列が、与えられたフォーマットにマッチするかを検査する + + Args: + date_str (str): 日付文字列 + date_format (str, optional): 日付のフォーマット + + Returns: + _type_: 正しい日付文字列の場合、True、それ以外はFalse + """ + try: + datetime.strptime(date_str, date_format) + return True + except ValueError: + return False + + +def assert_table_results(actual_rows: list[dict], expect_rows: list[dict], ignore_col_name: list = None) -> None: + """テーブル同士の取得結果突き合わせ + + Args: + actual_rows (list[dict]): テスト結果の辞書リスト + expect_rows (list[dict]): 期待値の辞書リスト + ignore_col_name (list): 比較を無視するDBのカラム名. Default None. + """ + # 取得件数が一致すること + assert len(actual_rows) == len(expect_rows) + + line_number = 0 + # 1行ずつ調査 + for actual_row, expect_row in zip(actual_rows, expect_rows): + line_number += 1 + # 1カラムずつ調査 + for actual_col_name, expect_col_name in zip(actual_row, expect_row): + # テストメソッド側で個別に確認するものはスキップさせる + if ignore_col_name is not None and actual_col_name in ignore_col_name: + continue + else: + actual_value = actual_row[actual_col_name] + expect_value = expect_row[expect_col_name] + assert actual_value == expect_value, f'{line_number}行目:{actual_col_name}が、期待値と一致すること' diff --git a/ecs/jskult-webapp/src/db/database.py b/ecs/jskult-webapp/src/db/database.py index 8308438d..c639a82a 100644 --- a/ecs/jskult-webapp/src/db/database.py +++ b/ecs/jskult-webapp/src/db/database.py @@ -1,6 +1,5 @@ from sqlalchemy import (Connection, CursorResult, Engine, QueuePool, create_engine, text) -from sqlalchemy.engine.create import create_engine from sqlalchemy.engine.url import URL from src.error.exceptions import DBException @@ -16,8 +15,7 @@ class Database: __username: str = None __password: str = None __schema: str = None - __connection_string:str = None - + __connection_string: str = None def __init__(self, username: str, password: str, host: str, port: int, schema: str) -> None: """このクラスの新たなインスタンスを初期化します @@ -34,9 +32,9 @@ class Database: self.__host = host self.__port = int(port) self.__schema = schema - + self.__connection_string = URL.create( - drivername='mysql+pymysql', + drivername='mysql+pymysql', username=self.__username, password=self.__password, host=self.__host, @@ -44,12 +42,11 @@ class Database: database=self.__schema, query={"charset": "utf8mb4"} ) - + self.__engine = create_engine( self.__connection_string, pool_timeout=5, - poolclass=QueuePool, - isolation_level="AUTOCOMMIT" + poolclass=QueuePool ) @classmethod @@ -97,10 +94,18 @@ class Database: """ if self.__connection is None: raise DBException('DBに接続していません') + + result = None try: - result = self.__connection.execute(text(select_query), parameters=parameters) + # トランザクションが開始している場合は、トランザクションを引き継ぐ + 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(e) + result_rows = result.mappings().all() return result_rows @@ -119,10 +124,18 @@ class Database: """ if self.__connection is None: raise DBException('DBに接続していません') + + result = None try: - result = self.__connection.execute(text(query), parameters=parameters) + # トランザクションが開始している場合は、トランザクションを引き継ぐ + 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(e) + return result def begin(self): @@ -145,3 +158,14 @@ class Database: 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 diff --git a/rds_mysql/stored_procedure/src05/inst_merge_t_create.sql b/rds_mysql/stored_procedure/src05/inst_merge_t_create.sql index 3d12307a..0afdedad 100644 --- a/rds_mysql/stored_procedure/src05/inst_merge_t_create.sql +++ b/rds_mysql/stored_procedure/src05/inst_merge_t_create.sql @@ -2,30 +2,37 @@ CREATE PROCEDURE src05.inst_merge_t_create() SQL SECURITY INVOKER BEGIN + -- スキーマ名 + DECLARE schema_name VARCHAR(50) DEFAULT (SELECT DATABASE()); + -- プロシージャ名 + DECLARE procedure_name VARCHAR(100) DEFAULT 'inst_merge_t_create'; + -- プロシージャの引数 + DECLARE procedure_args JSON DEFAULT JSON_OBJECT(); + -- 例外処理 DECLARE EXIT HANDLER FOR SQLEXCEPTION BEGIN GET DIAGNOSTICS CONDITION 1 @error_state = RETURNED_SQLSTATE, @error_msg = MESSAGE_TEXT; - call medaca_common.put_error_log('internal05', 'src05.inst_merge_t_create', JSON_OBJECT(), - 'src05.inst_merge_t_createでエラーが発生', @error_state, @error_msg); + call medaca_common.put_error_log(schema_name, procedure_name, procedure_args, + 'inst_merge_t_createでエラーが発生', @error_state, @error_msg); SIGNAL SQLSTATE '45000' SET MYSQL_ERRNO = @error_state, MESSAGE_TEXT = @error_msg; END; SET @error_state = NULL, @error_msg = NULL; - call medaca_common.put_info_log('internal05', 'src05.inst_merge_t_create', JSON_OBJECT(), + call medaca_common.put_info_log(schema_name, procedure_name, procedure_args, 'アルトマーク施設統合マスタ(洗替処理一時テーブル)作成① 開始' ); TRUNCATE TABLE internal05.inst_merge_t; - call medaca_common.put_info_log('internal05', 'src05.inst_merge_t_create', JSON_OBJECT(), + call medaca_common.put_info_log(schema_name, procedure_name, procedure_args, 'アルトマーク施設統合マスタ(洗替処理一時テーブル)作成① 終了' ); - call medaca_common.put_info_log('internal05', 'src05.inst_merge_t_create', JSON_OBJECT(), + call medaca_common.put_info_log(schema_name, procedure_name, procedure_args, 'アルトマーク施設統合マスタ(洗替処理一時テーブル)作成② 開始' ); @@ -55,7 +62,7 @@ BEGIN AND dim.muko_flg = '0' AND dim.enabled_flg = 'Y'; - call medaca_common.put_info_log('internal05', 'src05.inst_merge_t_create', JSON_OBJECT(), + call medaca_common.put_info_log(schema_name, procedure_name, procedure_args, 'アルトマーク施設統合マスタ(洗替処理一時テーブル)作成② 終了' ); diff --git a/rds_mysql/stored_procedure/src05/v_inst_merge_t_create.sql b/rds_mysql/stored_procedure/src05/v_inst_merge_t_create.sql index 665c4ec5..d550d121 100644 --- a/rds_mysql/stored_procedure/src05/v_inst_merge_t_create.sql +++ b/rds_mysql/stored_procedure/src05/v_inst_merge_t_create.sql @@ -2,28 +2,35 @@ CREATE PROCEDURE src05.v_inst_merge_t_create() SQL SECURITY INVOKER BEGIN + -- スキーマ名 + DECLARE schema_name VARCHAR(50) DEFAULT (SELECT DATABASE()); + -- プロシージャ名 + DECLARE procedure_name VARCHAR(100) DEFAULT 'v_inst_merge_t_create'; + -- プロシージャの引数 + DECLARE procedure_args JSON DEFAULT JSON_OBJECT(); + -- 例外処理 DECLARE EXIT HANDLER FOR SQLEXCEPTION BEGIN GET DIAGNOSTICS CONDITION 1 @error_state = RETURNED_SQLSTATE, @error_msg = MESSAGE_TEXT; - call medaca_common.put_error_log('internal05', 'src05.v_inst_merge_t_create', JSON_OBJECT(), - 'src05.v_inst_merge_t_createでエラーが発生', @error_state, @error_msg); + call medaca_common.put_error_log(schema_name, procedure_name, procedure_args, + 'v_inst_merge_t_createでエラーが発生', @error_state, @error_msg); SIGNAL SQLSTATE '45000' SET MYSQL_ERRNO = @error_state, MESSAGE_TEXT = @error_msg; END; SET @error_state = NULL, @error_msg = NULL; - call medaca_common.put_info_log('internal05', 'src05.v_inst_merge_t_create', JSON_OBJECT(), + call medaca_common.put_info_log(schema_name, procedure_name, procedure_args, '【洗替】3:HCO施設コードの洗替① 開始'); TRUNCATE TABLE internal05.v_inst_merge_t; - call medaca_common.put_info_log('internal05', 'src05.v_inst_merge_t_create', JSON_OBJECT(), + call medaca_common.put_info_log(schema_name, procedure_name, procedure_args, '【洗替】3:HCO施設コードの洗替① 終了'); - call medaca_common.put_info_log('internal05', 'src05.v_inst_merge_t_create', JSON_OBJECT(), + call medaca_common.put_info_log(schema_name, procedure_name, procedure_args, '【洗替】3:HCO施設コードの洗替② 開始'); INSERT INTO @@ -62,7 +69,7 @@ BEGIN AND ((fmv.fcl_type IN ('A1','A0')) OR fmv.fcl_type BETWEEN '20' AND '29') AND fmv.rec_sts_kbn != '9'; - call medaca_common.put_info_log('internal05', 'src05.v_inst_merge_t_create', JSON_OBJECT(), + call medaca_common.put_info_log(schema_name, procedure_name, procedure_args, '【洗替】3:HCO施設コードの洗替② 終了' ); END diff --git a/s3/data/encise/settings/CLUFM_CLUMST.txt b/s3/data/encise/settings/CLUFM_CLUMST.txt index c2693b08..09d6f561 100644 --- a/s3/data/encise/settings/CLUFM_CLUMST.txt +++ b/s3/data/encise/settings/CLUFM_CLUMST.txt @@ -6,7 +6,7 @@ CRLF 1 12 対象期間,クラスターコード,クラスター名,都道府県コード,都道府県名,施設コード,施設名,更新日,更新事由,適用年月,セグメントコード,セグメント名 -data_period,cluster_code,cluster_name,pref_code,pref_name,HCO_coce,HCO_name,update_date,update_remarks,master_YM,segment_code,segment_name +data_period,cluster_code,cluster_name,pref_code,pref_name,HCO_code,HCO_name,update_date,update_remarks,master_YM,segment_code,segment_name src01.en_clufm_clumst org01.en_clufm_clumst CLUFM_CLUMST_ex.sql