diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..4d098418abbc7d3f2add29b562bb1d66c1a757f8 --- /dev/null +++ b/.gitignore @@ -0,0 +1,147 @@ +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py,cover +.hypothesis/ +.pytest_cache/ +cover/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 +db.sqlite3-journal + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +.pybuilder/ +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +# For a library or package, you might want to ignore these files since the code is +# intended to run in multiple environments; otherwise, check them in: +# .python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +#Pipfile.lock + +# PEP 582; used by e.g. github.com/David-OConnor/pyflow +__pypackages__/ + +# Celery stuff +celerybeat-schedule +celerybeat.pid + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ + +# pytype static type analyzer +.pytype/ +.idea +.vscode +# Cython debug symbols +cython_debug/ +.pytest_cache +geckodriver.log +file/screenshot/ +extract.yaml +Temp/ +Reports/ +allure-results/ +allure-report/ diff --git a/Interface/1.py b/Interface/1.py new file mode 100644 index 0000000000000000000000000000000000000000..9f097456222cd0569116063702ee1878c96a35e9 --- /dev/null +++ b/Interface/1.py @@ -0,0 +1,1213 @@ +# -*- coding:utf-8 -*- +# 作者:齐振鋆 +# 日期:2023/1/13 +# 描述: +import json +import re +import requests + +from urllib import parse +from unit.public.TimeUnit import TimeUnit + +tu = TimeUnit() +api = 'http://10.17.65.216:8088/portal/r/jd' +headers = { + 'Content-Type': 'application/x-www-form-urlencoded; charset=utf-8' +} +session = requests.session() + + +def gk_request(data): + response = session.post(api, headers=headers, data=parse.urlencode(data)).text + print('\n', response) + return response + + +# dHnoQcI1fnwGr67e7QwxqfQjhB5QxdWwyUPAO1GUdfvbmd1KzEeJ0tts8eCxOB+bwqGlE7+7LIxCXrLyzZMGxhRIsTiAlPgB3Y1wlMrv1aaii2yWyjQY5y/aIkkfGICLgCKwrVItTn7q8stkv30tPdTVq4e1k9hF5epnI+60nb8= +# 533fa49d3ab7e57c2454740a783a3f9b8a227a3ca3623dca6d2e07812c2ad077919502877537631668cd7da34a28b5a36e8ee0003609703864eec1dfb5ec344a780cdece3dcf61d49e2f8cf83929c361a604289a44158c5508f718ba661e97d7e203f7a74e21cf2d6969f8c3dc953833e556a548fd06bf8791ca9dbf0b68cc8d +def get_session(): + body = { + 'userid': 'qizhenjun', + 'pwd': 'dHnoQcI1fnwGr67e7QwxqfQjhB5QxdWwyUPAO1GUdfvbmd1KzEeJ0tts8eCxOB+bwqGlE7+7LIxCXrLyzZMGxhRIsTiAlPgB3Y1wlMrv1aaii2yWyjQY5y/aIkkfGICLgCKwrVItTn7q8stkv30tPdTVq4e1k9hF5epnI+60nb8=', + 'rememberMeUid': 'on', + 'mobile': '', + 'cmd': 'CLIENT_USER_LOGIN', + 'sid': '', + 'deviceType': 'pc', + '_CACHE_LOGIN_TIME_': '{}'.format(tu.get_timezone()), + 'pwdEncode': 'RSA', + 'timeZone': 8, + 'loginUrl': 'http://10.17.65.216:8088/portal/' + } + response = gk_request(body) + return json.loads(response)['data']['sid'] + + +def get_process_task_id(s_id): + body = { + 'cmd': 'CLIENT_BPM_WORKLIST_PROCESSINST_CREATE_AJAX_PREPAGE', + 'sid': s_id, + 'isDwCreate': True, + 'processGroupId': 'obj_fa7e36de0c254f3086ce43bc9dce75b7', + 'processDefId': 'obj_4fc09a3dd5bf430c80f29f75e1d8f793', + 'extParam': '"手术借出/手术请领单"' + } + response = gk_request(body) + processInstId = re.search('processInstId=(.*)&openState', response).group(1) + taskInstId = re.search('taskInstId=(.*)&', response).group(1) + return processInstId, taskInstId + + +def get_bo_def_id(s_id, p_i_id, t_i_id): + body = { + 'sid': s_id, + 'cmd': 'CLIENT_BPM_FORM_MAIN_PAGE_JSON', + 'processInstId': p_i_id, + 'taskInstId': t_i_id, + 'currentPage': 1, + 'openState': 1, + 'formDefId': '10feec89-c9c8-4b7e-b9a0-e6dbd6eef59e', + 'boId': '', + 'displayToolbar': True, + 'extParam': { + "isDisplayToolbar": True, + "isInitTaskOpen": False, + "displayToolbar": "true", + "isVue": "true", + "openState": "1", + "extParam": "", + "formDefId": "", + "boId": "", + "serverName": "10.17.65.216", + "taskInstId": t_i_id, + "navFunctionName": "com.awspaas.user.apps.cmdc.surgery/手术跟台手术请领流程", + "firstOpen": True, + "responseType": "W", + "param": "", + "clientIp": "10.17.73.97", + "processInstId": p_i_id, + "currentPage": "", + "lang": "" + } + } + response = gk_request(body) + jsonData = json.loads(response) + return jsonData['data']['processContext']['boId'], jsonData['data']['processContext']['boDefId'], jsonData['data']['usertaskComment']['commentId'] + + +def ssqld(s_id, process_inst_id, task_inst_id, bo_id, bo_def_id, c_id): + body = { + 'cmd': 'CLIENT_BPM_FORM_PAGE_P_SAVE_DATA', + 'processInstId': process_inst_id, + 'taskInstId': task_inst_id, + 'openState': '1', + 'formDefId': '10feec89-c9c8-4b7e-b9a0-e6dbd6eef59e', # 请领单创建固定 + 'formData': { + "F_ORDER_STATUS": "100", + "F_REMARK": "testtesttestremark", + "F_BUSINESS_CODE": "122006", + "F_LOAN_ENTREPOT_CODE": "", + "F_OPERATION_KIND": "A", + "F_PHONE": "13333333333", + "F_SALESMAN_NAME": "段炼", + "F_CONTACT": "test", + "F_DISTRIBUTE_CUST_NO": "1000591", + "F_DISTRIBUTE_CUST_NAME": "南京医科大学附属逸夫医院", + "F_OPERATION_DATE": "2023-01-31", + "ID": bo_id, + "F_BORROW_ENTREPOT_NAME": "", + "F_SUCCESSION": "", + "F_TAX_RATE_AREA": "", + "F_RETURNIN_ENTREPOT_NAME": "", + "F_EPARTMENE_DESC": "", + "F_CST_ENQUIRY_NO": "自动生成无需填写", + "F_SALESMAN_CODE": "88020206", + "F_OPERATION_TYPE": "B", + "F_COMPANY_NAME": "国药集团四川省医疗器械有限公司", + "F_LOAN_ENTREPOT_NAME": "", + "F_BUSINESS_NAME": "商务部", + "F_EUDXIG6E": "0", + "F_CUST_NAME": "南京医科大学附属逸夫医院", + "F_CUST_CODE": "1000591", + "F_TAX_RATE": "", + "F_EPARTMENE": "", + "F_COMPANY_CODE": "00122", + "F_BORROW_ENTREPOT_CODE": "", + "F_OPERATION_DOCTOR": "test", + "F_LOAN_TYPE": "A", + "F_ORDER_NO": "自动生成无需填写", + "F_TERMS_PAYMENT": "", + "F_RETURNIN_ENTREPOT_CODE": "" + }, + 'formDataExtends': { + "F_ORDER_STATUS": { + "displayValue": "100", + "extends": {} + }, + "F_REMARK": { + "displayValue": "testtesttestremark", + "extends": {} + }, + "F_BUSINESS_CODE": { + "displayValue": "122006", + "extends": {} + }, + "F_LOAN_ENTREPOT_CODE": { + "displayValue": "", + "extends": {} + }, + "F_OPERATION_KIND": { + "displayValue": "踝关节", + "extends": {} + }, + "F_PHONE": { + "displayValue": "13333333333", + "extends": {} + }, + "F_SALESMAN_NAME": { + "displayValue": "段炼", + "extends": {} + }, + "F_CONTACT": { + "displayValue": "test", + "extends": {} + }, + "F_DISTRIBUTE_CUST_NO": { + "displayValue": "1000591", + "extends": {} + }, + "F_DISTRIBUTE_CUST_NAME": { + "displayValue": "南京医科大学附属逸夫医院", + "extends": {} + }, + "F_OPERATION_DATE": { + "displayValue": "2023-01-31", + "extends": {} + }, + "F_BORROW_ENTREPOT_NAME": { + "displayValue": "", + "extends": {} + }, + "F_SUCCESSION": { + "displayValue": "", + "extends": {} + }, + "F_TAX_RATE_AREA": { + "displayValue": "", + "extends": {} + }, + "F_RETURNIN_ENTREPOT_NAME": { + "displayValue": "", + "extends": {} + }, + "F_EPARTMENE_DESC": { + "displayValue": "", + "extends": {} + }, + "F_CST_ENQUIRY_NO": { + "displayValue": "自动生成无需填写", + "extends": {} + }, + "F_SALESMAN_CODE": { + "displayValue": "88020206", + "extends": {} + }, + "F_OPERATION_TYPE": { + "displayValue": "翻修手术", + "extends": {} + }, + "F_COMPANY_NAME": { + "displayValue": "国药集团四川省医疗器械有限公司", + "extends": {} + }, + "F_LOAN_ENTREPOT_NAME": { + "displayValue": "", + "extends": {} + }, + "F_BUSINESS_NAME": { + "displayValue": "商务部", + "extends": {} + }, + "F_EUDXIG6E": { + "displayValue": "0", + "extends": {} + }, + "F_CUST_NAME": { + "displayValue": "南京医科大学附属逸夫医院", + "extends": {} + }, + "F_CUST_CODE": { + "displayValue": "1000591", + "extends": {} + }, + "F_TAX_RATE": { + "displayValue": "", + "extends": {} + }, + "F_EPARTMENE": { + "displayValue": "", + "extends": {} + }, + "F_COMPANY_CODE": { + "displayValue": "00122", + "extends": {} + }, + "F_BORROW_ENTREPOT_CODE": { + "displayValue": "", + "extends": {} + }, + "F_OPERATION_DOCTOR": { + "displayValue": "test", + "extends": {} + }, + "F_LOAN_TYPE": { + "displayValue": "手术借出", + "extends": {} + }, + "F_ORDER_NO": { + "displayValue": "自动生成无需填写", + "extends": {} + }, + "F_TERMS_PAYMENT": { + "displayValue": "", + "extends": {} + }, + "F_RETURNIN_ENTREPOT_CODE": { + "displayValue": "", + "extends": {} + } + }, + 'oldFormData': '', + 'oldFormDataExtend': '', + 'gridData': { + "56a7292d-5c67-4ea1-829e-152cafe50381": { + "boDefName": "BO_EU_SURGERY_IOR_DETAIL", + "boDefId": bo_def_id, + "oldData": [], + "oldDataExtend": {}, + "items": [ + { + "F_PACKAGE_NUM": "", + "F_IS_MBA": "N", + "F_APPLY_NUM": "52", + "F_BUSINESS_CODE": "", + "F_STE_NUM": "", + "F_LOAN_ENTREPOT_CODE": "", + "F_LOSE_DATE": "", + "F_OPERATION_KIND": "", + "F_PHONE": "", + "F_PRO_TXT": "", + "F_PRO_NUM": "", + "F_PRO_REMARK": "", + "F_MANVENDER_CODE": "7127515", + "F_IS_IMPORT": "0", + "F_PRODUCR_DATE": "", + "F_UNIT_COST": "", + "F_OPERATION_DATE": "", + "ID": "3aae3ee4-19ac-4696-a4af-54a4c302ed75", + "F_UN_DISTRI_QTY": "52", + "F_BORROW_ENTREPOT_NAME": "", + "F_SUCCESSION": "", + "F_PUR_ENT_COA": "", + "ORGID": "f59d724b-8991-4c87-9e91-45a280b6f677", + "F_RETURNIN_ENTREPOT_NAME": "", + "F_OVERSEAS_MAN_NAME": "", + "F_ENTRUSTED_LICENCE": "", + "F_CST_ENQUIRY_NO": "", + "F_QIPU": "52", + "CREATEDATE": "2023-01-11 14:51:57", + "F_UDI": "", + "F_BUSINESS_NAME": "", + "F_TOTAL_COST": "", + "F_COMMODITY_CODE": "10174665", + "F_SERIAL_MANGE_FLAG": "N", + "F_PRO_LICENCE": "", + "F_TAX_RATE": "", + "F_TOTAL_CX": "", + "F_LOAN_TYPE_DISPLAYVALUE": "", + "F_COMPANY_CODE": "", + "F_BORROW_ENTREPOT_CODE": "", + "F_REG_CER": "", + "UPDATEDATE": "2023-01-11 14:52:00", + "F_MANVENDER_NAME": "", + "F_AREA_CODE": "", + "F_SALES_VOLUMES": "52", + "F_PUR_PROJECT_CODE": "", + "F_SALEUNIT_TXT": "个", + "UPDATEUSER": "qizhenjun", + "F_STE_DATE": "", + "F_FACMAT_CODE": "", + "F_SUPPLIER_CODE": "", + "F_ENTRUSTED_NAME": "", + "F_COMMODITY_NAME": "通风管---蒋林玲", + "F_REFERENCE": "", + "F_SALESMAN_NAME": "", + "F_CONTACT": "", + "BINDID": process_inst_id, + "F_DISTRIBUTE_CUST_NO": "", + "CREATEUSER": "qizhenjun", + "F_DISTRIBUTE_CUST_NAME": "", + "F_CARGO_NAME": "", + "F_QW8KJ0WR": "", + "F_STE_VALID_PERIOD": "", + "F_SUPPLIER_REMARK": "", + "F_SPECIFICATION": "1016011", + "F_PUR_PROJECT_DESC": "", + "F_TAX_RATE_AREA": "", + "F_LOCATION": "", + "F_EPARTMENE_DESC": "", + "F_ENTRUSTED_CODE": "", + "F_SALESMAN_CODE": "", + "F_MAINUNIT_CODE": "EA", + "F_AREA_NAME": "", + "F_COMPANY_NAME": "", + "F_LOAN_ENTREPOT_NAME": "", + "F_OPERATION_TYPE": "", + "F_SALEUNIT_CODE": "EA", + "F_CUST_NAME": "", + "F_CUST_CODE": "", + "F_MAINUNIT_TXT": "", + "F_EPARTMENE": "", + "F_STORE_COND": "999", + "F_OPERATION_DOCTOR": "", + "F_SUPPLIER_NAME": "", + "F_LOAN_TYPE": "", + "F_LINE_NUM": "1", + "F_BATCH_NO": "", + "F_TERMS_PAYMENT": "", + "F_ORDER_NO": "", + "F_RETURNIN_ENTREPOT_CODE": "", + "ISEND": False, + "F_LINE_TYPE": "", + "F_ENTRUST_INS": "", + "F_DTL_STATUS": "100", + "FORM_EDITGRID_DATA_ATTR_COLUMN": { + "isCreate": False, + "readonly": False, + "isDetail": "false", + "remove": True + }, + "PROCESSDEFID": "obj_4fc09a3dd5bf430c80f29f75e1d8f793" + }, + { + "F_PACKAGE_NUM": "", + "F_IS_MBA": "N", + "F_APPLY_NUM": "52", + "F_BUSINESS_CODE": "", + "F_STE_NUM": "", + "F_LOAN_ENTREPOT_CODE": "", + "F_LOSE_DATE": "", + "F_OPERATION_KIND": "", + "F_PHONE": "", + "F_PRO_TXT": "", + "F_PRO_NUM": "", + "F_PRO_REMARK": "", + "F_MANVENDER_CODE": "7024263", + "F_IS_IMPORT": "0", + "F_PRODUCR_DATE": "", + "F_UNIT_COST": "", + "F_OPERATION_DATE": "", + "ID": "ab331446-c3aa-4bd0-8c9f-2c8070290ce9", + "F_UN_DISTRI_QTY": "52", + "F_BORROW_ENTREPOT_NAME": "", + "F_SUCCESSION": "", + "F_PUR_ENT_COA": "", + "ORGID": "f59d724b-8991-4c87-9e91-45a280b6f677", + "F_RETURNIN_ENTREPOT_NAME": "", + "F_OVERSEAS_MAN_NAME": "", + "F_ENTRUSTED_LICENCE": "", + "F_CST_ENQUIRY_NO": "", + "F_QIPU": "52", + "CREATEDATE": "2023-01-11 14:51:58", + "F_UDI": "", + "F_BUSINESS_NAME": "", + "F_TOTAL_COST": "", + "F_COMMODITY_CODE": "10154871", + "F_SERIAL_MANGE_FLAG": "N", + "F_PRO_LICENCE": "", + "F_TAX_RATE": "", + "F_TOTAL_CX": "", + "F_LOAN_TYPE_DISPLAYVALUE": "", + "F_COMPANY_CODE": "", + "F_BORROW_ENTREPOT_CODE": "", + "F_REG_CER": "", + "UPDATEDATE": "2023-01-11 14:52:00", + "F_MANVENDER_NAME": "", + "F_AREA_CODE": "", + "F_SALES_VOLUMES": "52", + "F_PUR_PROJECT_CODE": "", + "F_SALEUNIT_TXT": "个", + "UPDATEUSER": "qizhenjun", + "F_STE_DATE": "", + "F_FACMAT_CODE": "1011", + "F_SUPPLIER_CODE": "", + "F_ENTRUSTED_NAME": "", + "F_COMMODITY_NAME": "旋转铰链膝关节系统组件", + "F_REFERENCE": "", + "F_SALESMAN_NAME": "", + "F_CONTACT": "", + "BINDID": process_inst_id, + "F_DISTRIBUTE_CUST_NO": "", + "CREATEUSER": "qizhenjun", + "F_DISTRIBUTE_CUST_NAME": "", + "F_CARGO_NAME": "", + "F_QW8KJ0WR": "", + "F_STE_VALID_PERIOD": "", + "F_SUPPLIER_REMARK": "", + "F_SPECIFICATION": "623401L", + "F_PUR_PROJECT_DESC": "", + "F_TAX_RATE_AREA": "", + "F_LOCATION": "", + "F_EPARTMENE_DESC": "", + "F_ENTRUSTED_CODE": "", + "F_SALESMAN_CODE": "", + "F_MAINUNIT_CODE": "EA", + "F_AREA_NAME": "", + "F_COMPANY_NAME": "", + "F_LOAN_ENTREPOT_NAME": "", + "F_OPERATION_TYPE": "", + "F_SALEUNIT_CODE": "EA", + "F_CUST_NAME": "", + "F_CUST_CODE": "", + "F_MAINUNIT_TXT": "", + "F_EPARTMENE": "", + "F_STORE_COND": "999", + "F_OPERATION_DOCTOR": "", + "F_SUPPLIER_NAME": "", + "F_LOAN_TYPE": "", + "F_LINE_NUM": "2", + "F_BATCH_NO": "", + "F_TERMS_PAYMENT": "", + "F_ORDER_NO": "", + "F_RETURNIN_ENTREPOT_CODE": "", + "ISEND": False, + "F_LINE_TYPE": "", + "F_ENTRUST_INS": "", + "F_DTL_STATUS": "100", + "FORM_EDITGRID_DATA_ATTR_COLUMN": { + "isCreate": False, + "readonly": False, + "isDetail": "false", + "remove": True + }, + "PROCESSDEFID": "obj_4fc09a3dd5bf430c80f29f75e1d8f793" + } + ], + "itemsExtend": { + "ab331446-c3aa-4bd0-8c9f-2c8070290ce9": { + "F_PACKAGE_NUM": { + "displayValue": "", + "extends": {} + }, + "F_IS_MBA": { + "displayValue": "N", + "extends": {} + }, + "F_APPLY_NUM": { + "displayValue": "52", + "extends": {} + }, + "F_BUSINESS_CODE": { + "displayValue": "", + "extends": {} + }, + "F_STE_NUM": { + "displayValue": "", + "extends": {} + }, + "F_LOAN_ENTREPOT_CODE": { + "displayValue": "", + "extends": {} + }, + "F_LOSE_DATE": { + "displayValue": "", + "extends": {} + }, + "F_OPERATION_KIND": { + "displayValue": "", + "extends": {} + }, + "F_PHONE": { + "displayValue": "", + "extends": {} + }, + "F_PRO_TXT": { + "displayValue": "", + "extends": {} + }, + "F_PRO_NUM": { + "displayValue": "", + "extends": {} + }, + "F_PRO_REMARK": { + "displayValue": "", + "extends": {} + }, + "F_MANVENDER_CODE": { + "displayValue": "7024263", + "extends": {} + }, + "F_IS_IMPORT": { + "displayValue": "0", + "extends": {} + }, + "F_PRODUCR_DATE": { + "displayValue": "", + "extends": {} + }, + "F_UNIT_COST": { + "displayValue": "", + "extends": {} + }, + "F_OPERATION_DATE": { + "displayValue": "", + "extends": {} + }, + "F_UN_DISTRI_QTY": { + "displayValue": "52", + "extends": {} + }, + "F_BORROW_ENTREPOT_NAME": { + "displayValue": "", + "extends": {} + }, + "F_SUCCESSION": { + "displayValue": "", + "extends": {} + }, + "F_PUR_ENT_COA": { + "displayValue": "", + "extends": {} + }, + "F_RETURNIN_ENTREPOT_NAME": { + "displayValue": "", + "extends": {} + }, + "F_OVERSEAS_MAN_NAME": { + "displayValue": "", + "extends": {} + }, + "F_ENTRUSTED_LICENCE": { + "displayValue": "", + "extends": {} + }, + "F_CST_ENQUIRY_NO": { + "displayValue": "", + "extends": {} + }, + "F_QIPU": { + "displayValue": "52", + "extends": {} + }, + "F_UDI": { + "displayValue": "", + "extends": {} + }, + "F_BUSINESS_NAME": { + "displayValue": "", + "extends": {} + }, + "F_TOTAL_COST": { + "displayValue": "", + "extends": {} + }, + "F_COMMODITY_CODE": { + "displayValue": "10154871", + "extends": {} + }, + "F_SERIAL_MANGE_FLAG": { + "displayValue": "N", + "extends": {} + }, + "F_PRO_LICENCE": { + "displayValue": "", + "extends": {} + }, + "F_TAX_RATE": { + "displayValue": "", + "extends": {} + }, + "F_TOTAL_CX": { + "displayValue": "", + "extends": {} + }, + "F_COMPANY_CODE": { + "displayValue": "", + "extends": {} + }, + "F_BORROW_ENTREPOT_CODE": { + "displayValue": "", + "extends": {} + }, + "F_REG_CER": { + "displayValue": "", + "extends": {} + }, + "F_MANVENDER_NAME": { + "displayValue": "", + "extends": {} + }, + "F_AREA_CODE": { + "displayValue": "", + "extends": {} + }, + "F_SALES_VOLUMES": { + "displayValue": "52", + "extends": {} + }, + "F_PUR_PROJECT_CODE": { + "displayValue": "", + "extends": {} + }, + "F_SALEUNIT_TXT": { + "displayValue": "个", + "extends": {} + }, + "F_STE_DATE": { + "displayValue": "", + "extends": {} + }, + "F_FACMAT_CODE": { + "displayValue": "1011", + "extends": {} + }, + "F_SUPPLIER_CODE": { + "displayValue": "", + "extends": {} + }, + "F_ENTRUSTED_NAME": { + "displayValue": "", + "extends": {} + }, + "F_COMMODITY_NAME": { + "displayValue": "旋转铰链膝关节系统组件", + "extends": {} + }, + "F_REFERENCE": { + "displayValue": "", + "extends": {} + }, + "F_SALESMAN_NAME": { + "displayValue": "", + "extends": {} + }, + "F_CONTACT": { + "displayValue": "", + "extends": {} + }, + "F_DISTRIBUTE_CUST_NO": { + "displayValue": "", + "extends": {} + }, + "F_DISTRIBUTE_CUST_NAME": { + "displayValue": "", + "extends": {} + }, + "F_CARGO_NAME": { + "displayValue": "", + "extends": {} + }, + "F_QW8KJ0WR": { + "displayValue": "", + "extends": {} + }, + "F_STE_VALID_PERIOD": { + "displayValue": "", + "extends": {} + }, + "F_SUPPLIER_REMARK": { + "displayValue": "", + "extends": {} + }, + "F_SPECIFICATION": { + "displayValue": "623401L", + "extends": {} + }, + "F_PUR_PROJECT_DESC": { + "displayValue": "", + "extends": {} + }, + "F_TAX_RATE_AREA": { + "displayValue": "", + "extends": {} + }, + "F_LOCATION": { + "displayValue": "", + "extends": {} + }, + "F_EPARTMENE_DESC": { + "displayValue": "", + "extends": {} + }, + "F_ENTRUSTED_CODE": { + "displayValue": "", + "extends": {} + }, + "F_SALESMAN_CODE": { + "displayValue": "", + "extends": {} + }, + "F_MAINUNIT_CODE": { + "displayValue": "EA", + "extends": {} + }, + "F_AREA_NAME": { + "displayValue": "", + "extends": {} + }, + "F_COMPANY_NAME": { + "displayValue": "", + "extends": {} + }, + "F_LOAN_ENTREPOT_NAME": { + "displayValue": "", + "extends": {} + }, + "F_OPERATION_TYPE": { + "displayValue": "", + "extends": {} + }, + "F_SALEUNIT_CODE": { + "displayValue": "EA", + "extends": {} + }, + "F_CUST_NAME": { + "displayValue": "", + "extends": {} + }, + "F_CUST_CODE": { + "displayValue": "", + "extends": {} + }, + "F_MAINUNIT_TXT": { + "displayValue": "", + "extends": {} + }, + "F_EPARTMENE": { + "displayValue": "", + "extends": {} + }, + "F_STORE_COND": { + "displayValue": "999", + "extends": {} + }, + "F_OPERATION_DOCTOR": { + "displayValue": "", + "extends": {} + }, + "F_SUPPLIER_NAME": { + "displayValue": "", + "extends": {} + }, + "F_LOAN_TYPE": { + "displayValue": "", + "extends": {} + }, + "F_LINE_NUM": { + "displayValue": "2", + "extends": {} + }, + "F_BATCH_NO": { + "displayValue": "", + "extends": {} + }, + "F_TERMS_PAYMENT": { + "displayValue": "", + "extends": {} + }, + "F_ORDER_NO": { + "displayValue": "", + "extends": {} + }, + "F_RETURNIN_ENTREPOT_CODE": { + "displayValue": "", + "extends": {} + }, + "F_LINE_TYPE": { + "displayValue": "", + "extends": {} + }, + "F_ENTRUST_INS": { + "displayValue": "", + "extends": {} + }, + "F_DTL_STATUS": { + "displayValue": "100", + "extends": {} + } + }, + "3aae3ee4-19ac-4696-a4af-54a4c302ed75": { + "F_PACKAGE_NUM": { + "displayValue": "", + "extends": {} + }, + "F_IS_MBA": { + "displayValue": "N", + "extends": {} + }, + "F_APPLY_NUM": { + "displayValue": "52", + "extends": {} + }, + "F_BUSINESS_CODE": { + "displayValue": "", + "extends": {} + }, + "F_STE_NUM": { + "displayValue": "", + "extends": {} + }, + "F_LOAN_ENTREPOT_CODE": { + "displayValue": "", + "extends": {} + }, + "F_LOSE_DATE": { + "displayValue": "", + "extends": {} + }, + "F_OPERATION_KIND": { + "displayValue": "", + "extends": {} + }, + "F_PHONE": { + "displayValue": "", + "extends": {} + }, + "F_PRO_TXT": { + "displayValue": "", + "extends": {} + }, + "F_PRO_NUM": { + "displayValue": "", + "extends": {} + }, + "F_PRO_REMARK": { + "displayValue": "", + "extends": {} + }, + "F_MANVENDER_CODE": { + "displayValue": "7127515", + "extends": {} + }, + "F_IS_IMPORT": { + "displayValue": "0", + "extends": {} + }, + "F_PRODUCR_DATE": { + "displayValue": "", + "extends": {} + }, + "F_UNIT_COST": { + "displayValue": "", + "extends": {} + }, + "F_OPERATION_DATE": { + "displayValue": "", + "extends": {} + }, + "F_UN_DISTRI_QTY": { + "displayValue": "52", + "extends": {} + }, + "F_BORROW_ENTREPOT_NAME": { + "displayValue": "", + "extends": {} + }, + "F_SUCCESSION": { + "displayValue": "", + "extends": {} + }, + "F_PUR_ENT_COA": { + "displayValue": "", + "extends": {} + }, + "F_RETURNIN_ENTREPOT_NAME": { + "displayValue": "", + "extends": {} + }, + "F_OVERSEAS_MAN_NAME": { + "displayValue": "", + "extends": {} + }, + "F_ENTRUSTED_LICENCE": { + "displayValue": "", + "extends": {} + }, + "F_CST_ENQUIRY_NO": { + "displayValue": "", + "extends": {} + }, + "F_QIPU": { + "displayValue": "52", + "extends": {} + }, + "F_UDI": { + "displayValue": "", + "extends": {} + }, + "F_BUSINESS_NAME": { + "displayValue": "", + "extends": {} + }, + "F_TOTAL_COST": { + "displayValue": "", + "extends": {} + }, + "F_COMMODITY_CODE": { + "displayValue": "10174665", + "extends": {} + }, + "F_SERIAL_MANGE_FLAG": { + "displayValue": "N", + "extends": {} + }, + "F_PRO_LICENCE": { + "displayValue": "", + "extends": {} + }, + "F_TAX_RATE": { + "displayValue": "", + "extends": {} + }, + "F_TOTAL_CX": { + "displayValue": "", + "extends": {} + }, + "F_COMPANY_CODE": { + "displayValue": "", + "extends": {} + }, + "F_BORROW_ENTREPOT_CODE": { + "displayValue": "", + "extends": {} + }, + "F_REG_CER": { + "displayValue": "", + "extends": {} + }, + "F_MANVENDER_NAME": { + "displayValue": "", + "extends": {} + }, + "F_AREA_CODE": { + "displayValue": "", + "extends": {} + }, + "F_SALES_VOLUMES": { + "displayValue": "52", + "extends": {} + }, + "F_PUR_PROJECT_CODE": { + "displayValue": "", + "extends": {} + }, + "F_SALEUNIT_TXT": { + "displayValue": "个", + "extends": {} + }, + "F_STE_DATE": { + "displayValue": "", + "extends": {} + }, + "F_FACMAT_CODE": { + "displayValue": "", + "extends": {} + }, + "F_SUPPLIER_CODE": { + "displayValue": "", + "extends": {} + }, + "F_ENTRUSTED_NAME": { + "displayValue": "", + "extends": {} + }, + "F_COMMODITY_NAME": { + "displayValue": "通风管---蒋林玲", + "extends": {} + }, + "F_REFERENCE": { + "displayValue": "", + "extends": {} + }, + "F_SALESMAN_NAME": { + "displayValue": "", + "extends": {} + }, + "F_CONTACT": { + "displayValue": "", + "extends": {} + }, + "F_DISTRIBUTE_CUST_NO": { + "displayValue": "", + "extends": {} + }, + "F_DISTRIBUTE_CUST_NAME": { + "displayValue": "", + "extends": {} + }, + "F_CARGO_NAME": { + "displayValue": "", + "extends": {} + }, + "F_QW8KJ0WR": { + "displayValue": "", + "extends": {} + }, + "F_STE_VALID_PERIOD": { + "displayValue": "", + "extends": {} + }, + "F_SUPPLIER_REMARK": { + "displayValue": "", + "extends": {} + }, + "F_SPECIFICATION": { + "displayValue": "1016011", + "extends": {} + }, + "F_PUR_PROJECT_DESC": { + "displayValue": "", + "extends": {} + }, + "F_TAX_RATE_AREA": { + "displayValue": "", + "extends": {} + }, + "F_LOCATION": { + "displayValue": "", + "extends": {} + }, + "F_EPARTMENE_DESC": { + "displayValue": "", + "extends": {} + }, + "F_ENTRUSTED_CODE": { + "displayValue": "", + "extends": {} + }, + "F_SALESMAN_CODE": { + "displayValue": "", + "extends": {} + }, + "F_MAINUNIT_CODE": { + "displayValue": "EA", + "extends": {} + }, + "F_AREA_NAME": { + "displayValue": "", + "extends": {} + }, + "F_COMPANY_NAME": { + "displayValue": "", + "extends": {} + }, + "F_LOAN_ENTREPOT_NAME": { + "displayValue": "", + "extends": {} + }, + "F_OPERATION_TYPE": { + "displayValue": "", + "extends": {} + }, + "F_SALEUNIT_CODE": { + "displayValue": "EA", + "extends": {} + }, + "F_CUST_NAME": { + "displayValue": "", + "extends": {} + }, + "F_CUST_CODE": { + "displayValue": "", + "extends": {} + }, + "F_MAINUNIT_TXT": { + "displayValue": "", + "extends": {} + }, + "F_EPARTMENE": { + "displayValue": "", + "extends": {} + }, + "F_STORE_COND": { + "displayValue": "999", + "extends": {} + }, + "F_OPERATION_DOCTOR": { + "displayValue": "", + "extends": {} + }, + "F_SUPPLIER_NAME": { + "displayValue": "", + "extends": {} + }, + "F_LOAN_TYPE": { + "displayValue": "", + "extends": {} + }, + "F_LINE_NUM": { + "displayValue": "1", + "extends": {} + }, + "F_BATCH_NO": { + "displayValue": "", + "extends": {} + }, + "F_TERMS_PAYMENT": { + "displayValue": "", + "extends": {} + }, + "F_ORDER_NO": { + "displayValue": "", + "extends": {} + }, + "F_RETURNIN_ENTREPOT_CODE": { + "displayValue": "", + "extends": {} + }, + "F_LINE_TYPE": { + "displayValue": "", + "extends": {} + }, + "F_ENTRUST_INS": { + "displayValue": "", + "extends": {} + }, + "F_DTL_STATUS": { + "displayValue": "100", + "extends": {} + } + } + } + } + }, + 'boId': bo_id, + 'boDefId': bo_def_id, + 'isCreate': True, + 'commentInfo': { + "msg": "", + "isSelected": True, + "isValidateForm": True, + "commentOption": "提交", + "commentId": c_id, + "isCommentCreate": True, + "hasFiles": False, + "setComments": False, + "processDefId": "obj_4fc09a3dd5bf430c80f29f75e1d8f793" + }, + 'isTransact': True, + 'isValidateForm': True, + 'currentPage': '1', + 'sid': s_id + } + response = gk_request(body) + + +if __name__ == '__main__': + sid = get_session() + # print(tu.get_timezone()) + # pId, tId = get_process_task_id(sid) + # boId, boDefId, commentId = get_bo_def_id(sid, pId, tId) + # ssqld(sid, pId, tId, boId, boDefId, commentId) + + diff --git a/Interface/__init__.py b/Interface/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..4414c0230e8b86b5d991f8e380870565a22e835f --- /dev/null +++ b/Interface/__init__.py @@ -0,0 +1,4 @@ +# -*- coding:utf-8 -*- +# 作者:齐振鋆 +# 日期:2023/1/9 +# 描述: diff --git a/README.md b/README.md index 6af6b1ff3779536428d728e960b981d418965448..c74c4689ba13f016097a653361f9ca3ebe7a8f75 100644 --- a/README.md +++ b/README.md @@ -1,92 +1,10 @@ -# autotest-airtest-web-sc-airtest +# 分布式执行 +## 启动selenium server +>java -jar selenium-server-standalone-3.141.0.jar -role hub -host 0.0.0.0 +## 启动selenium client +>cd c:\ +>java -Dwebdriver.chrome.driver="C:\chromedriver.exe" -jar selenium-server-standalone-3.141.0.jar -role node -port 5555 -hub http://10.17.73.97:4444/grid/register/ -## Getting started - -To make it easy for you to get started with GitLab, here's a list of recommended next steps. - -Already a pro? Just edit this README.md and make it your own. Want to make it easy? [Use the template at the bottom](#editing-this-readme)! - -## Add your files - -- [ ] [Create](https://docs.gitlab.com/ee/user/project/repository/web_editor.html#create-a-file) or [upload](https://docs.gitlab.com/ee/user/project/repository/web_editor.html#upload-a-file) files -- [ ] [Add files using the command line](https://docs.gitlab.com/ee/gitlab-basics/add-file.html#add-a-file-using-the-command-line) or push an existing Git repository with the following command: - -``` -cd existing_repo -git remote add origin http://10.17.65.20/gitlab/test/autotest-airtest-web-sc-airtest.git -git branch -M main -git push -uf origin main -``` - -## Integrate with your tools - -- [ ] [Set up project integrations](http://10.17.65.20/gitlab/test/autotest-airtest-web-sc-airtest/-/settings/integrations) - -## Collaborate with your team - -- [ ] [Invite team members and collaborators](https://docs.gitlab.com/ee/user/project/members/) -- [ ] [Create a new merge request](https://docs.gitlab.com/ee/user/project/merge_requests/creating_merge_requests.html) -- [ ] [Automatically close issues from merge requests](https://docs.gitlab.com/ee/user/project/issues/managing_issues.html#closing-issues-automatically) -- [ ] [Enable merge request approvals](https://docs.gitlab.com/ee/user/project/merge_requests/approvals/) -- [ ] [Automatically merge when pipeline succeeds](https://docs.gitlab.com/ee/user/project/merge_requests/merge_when_pipeline_succeeds.html) - -## Test and Deploy - -Use the built-in continuous integration in GitLab. - -- [ ] [Get started with GitLab CI/CD](https://docs.gitlab.com/ee/ci/quick_start/index.html) -- [ ] [Analyze your code for known vulnerabilities with Static Application Security Testing(SAST)](https://docs.gitlab.com/ee/user/application_security/sast/) -- [ ] [Deploy to Kubernetes, Amazon EC2, or Amazon ECS using Auto Deploy](https://docs.gitlab.com/ee/topics/autodevops/requirements.html) -- [ ] [Use pull-based deployments for improved Kubernetes management](https://docs.gitlab.com/ee/user/clusters/agent/) -- [ ] [Set up protected environments](https://docs.gitlab.com/ee/ci/environments/protected_environments.html) - -*** - -# Editing this README - -When you're ready to make this README your own, just edit this file and use the handy template below (or feel free to structure it however you want - this is just a starting point!). Thank you to [makeareadme.com](https://www.makeareadme.com/) for this template. - -## Suggestions for a good README -Every project is different, so consider which of these sections apply to yours. The sections used in the template are suggestions for most open source projects. Also keep in mind that while a README can be too long and detailed, too long is better than too short. If you think your README is too long, consider utilizing another form of documentation rather than cutting out information. - -## Name -Choose a self-explaining name for your project. - -## Description -Let people know what your project can do specifically. Provide context and add a link to any reference visitors might be unfamiliar with. A list of Features or a Background subsection can also be added here. If there are alternatives to your project, this is a good place to list differentiating factors. - -## Badges -On some READMEs, you may see small images that convey metadata, such as whether or not all the tests are passing for the project. You can use Shields to add some to your README. Many services also have instructions for adding a badge. - -## Visuals -Depending on what you are making, it can be a good idea to include screenshots or even a video (you'll frequently see GIFs rather than actual videos). Tools like ttygif can help, but check out Asciinema for a more sophisticated method. - -## Installation -Within a particular ecosystem, there may be a common way of installing things, such as using Yarn, NuGet, or Homebrew. However, consider the possibility that whoever is reading your README is a novice and would like more guidance. Listing specific steps helps remove ambiguity and gets people to using your project as quickly as possible. If it only runs in a specific context like a particular programming language version or operating system or has dependencies that have to be installed manually, also add a Requirements subsection. - -## Usage -Use examples liberally, and show the expected output if you can. It's helpful to have inline the smallest example of usage that you can demonstrate, while providing links to more sophisticated examples if they are too long to reasonably include in the README. - -## Support -Tell people where they can go to for help. It can be any combination of an issue tracker, a chat room, an email address, etc. - -## Roadmap -If you have ideas for releases in the future, it is a good idea to list them in the README. - -## Contributing -State if you are open to contributions and what your requirements are for accepting them. - -For people who want to make changes to your project, it's helpful to have some documentation on how to get started. Perhaps there is a script that they should run or some environment variables that they need to set. Make these steps explicit. These instructions could also be useful to your future self. - -You can also document commands to lint the code or run tests. These steps help to ensure high code quality and reduce the likelihood that the changes inadvertently break something. Having instructions for running tests is especially helpful if it requires external setup, such as starting a Selenium server for testing in a browser. - -## Authors and acknowledgment -Show your appreciation to those who have contributed to the project. - -## License -For open source projects, say how it is licensed. - -## Project status -If you have run out of energy or time for your project, put a note at the top of the README saying that development has slowed down or stopped completely. Someone may choose to fork your project or volunteer to step in as a maintainer or owner, allowing your project to keep going. You can also make an explicit request for maintainers. +# \ No newline at end of file diff --git a/__init__.py b/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..9cce890cc1bc06cb6df91f2388d03e1fe063e15e --- /dev/null +++ b/__init__.py @@ -0,0 +1,3 @@ +# -*- coding:utf-8 -*- +# 作者:齐振鋆 +# 日期:2022/8/11 diff --git a/args_command.py b/args_command.py new file mode 100644 index 0000000000000000000000000000000000000000..6d78b2f943b10017d725d6d2ddf8c48a79b3c809 --- /dev/null +++ b/args_command.py @@ -0,0 +1,39 @@ +# -*- coding:utf-8 -*- +# 作者:齐振鋆 +# 日期:2023/3/27 +# 描述: +import argparse + +from pytest_run import py_run +from unit.public.DataDic import DataDic + +dd = DataDic() + + +def get_command_args(): + """命令行参数解析""" + parser = argparse.ArgumentParser(description=u'可选择参数:') + parser.add_argument("--client", default='localhost', help="client:客户端IP") + parser.add_argument("--project", default='GuKeYiTiHua', help="project:项目") + # url: 'http://10.17.65.216:8088/portal/' 'http://10.17.65.200:8088/portal/' + parser.add_argument("--url", default='http://10.17.65.216:8088/portal/', help="url: 地址") + # ;手术跟台: surgery | 采购管理:purchase | 调拨管理: Transfer | 库存管理:inventory | 调试:debug + parser.add_argument("--module", default='purchase', help="module:模块") + parser.add_argument("--tab", default='purchase', help="tab:标记") + parser.add_argument("--order", help="order: 单据编码") + parser.add_argument("--co", help="co: 公司") + parser.add_argument("--wh", help="wh: 仓库") + parser.add_argument("--good", help="good: 商品") + parser.add_argument("--num", help="num: 数量") + args = parser.parse_args() + dd.set_value('client', args.client) + dd.set_value('project', args.project) + dd.set_value('url', args.url) + dd.set_value('module', args.module) + dd.set_value('tab', args.tab) + dd.set_value('order', args.order) + dd.set_value('company', args.co) + dd.set_value('warehouse', args.wh) + dd.set_value('custGood', args.good) + dd.set_value('custNum', args.num) + py_run() diff --git a/args_ui.py b/args_ui.py new file mode 100644 index 0000000000000000000000000000000000000000..634158aaa7b04cc56220200313ebe424446431dd --- /dev/null +++ b/args_ui.py @@ -0,0 +1,114 @@ +# -*- coding:utf-8 -*- +# 作者:齐振鋆 +# 日期:2023/3/27 +# 描述: + +from flet import ResponsiveRow, Column, ElevatedButton, Text, TextField, Dropdown, icons, FilePickerResultEvent, \ + FilePicker, alignment, Container, dropdown, KeyboardType +from flet import Ref + +from pytest_run import py_run +from unit.public.DataDic import DataDic + +dd = DataDic() + + +def get_ui_args(page): + page.title = "国药自动化测试启动器" + + client_ip = Ref[TextField]() + test_url = Ref[TextField]() + project_name = Ref[Dropdown]() + module_name = Ref[Dropdown]() + tab_name = Ref[Dropdown]() + test_file = Ref[TextField]() + greetings = Ref[Column]() + + def run(e): + greetings.current.controls.append( + Text(f"【测试环境】:{test_url.current.value}") + ) + greetings.current.controls.append( + Text(f"【项目】:{project_name.current.value}-【模块】:{module_name.current.value}-【标签】:{tab_name.current.value}") + ) + page.update() + dd.set_value('client', client_ip.current.value) + p_name = project_name.current.value + p_code = 'GuKeYiTiHua' if p_name == '骨科一体化' else 'TestProject' + dd.set_value('project', p_code) + dd.set_value('url', test_url.current.value) + m_name = module_name.current.value + m_code = 'purchase' if m_name == '采购管理' \ + else 'surgery' if m_name == '手术跟台' \ + else 'transfer' if m_name == '调拨管理' \ + else None + dd.set_value('module', m_code) + + t_name = tab_name.current.value + t_code = 'all' if t_name == '全量' else 'smoking' if t_name == '冒烟' else 'debug' if t_name == '调试' else None + dd.set_value('tab', t_code) + py_run() + + def stop(e): + dd.get_value('driver').close() + dd.get_value('driver').quit() + + def module_update(e): + m_options = [] + module_list = ['采购管理', '手术跟台', '调拨管理'] if project_name.current.value == '骨科一体化' \ + else ['模块1', '模块2', '模块3'] if project_name.current.value == '测试项目' \ + else [] + for m_item in module_list: + m_options.append(dropdown.Option(m_item)) + module.options = m_options + page.update() + + def pick_files_result(e: FilePickerResultEvent): + selected_files.value = ( + e.files[0].path if e.files else "Cancelled!" + ) + selected_files.update() + test_data_file = test_file.current.value + dd.set_value('test_data_file', test_data_file) + + client = TextField(ref=client_ip, label="客户端地址", icon=icons.BOY, autofocus=True, value='localhost', + read_only=True, ) + url = TextField(ref=test_url, label="测试环境", icon=icons.HTTP, keyboard_type=KeyboardType.URL, value='http://10.17.65.216:8088/portal/r/w') + project_options = [] + for item in ['骨科一体化', '测试项目']: + project_options.append(dropdown.Option(item)) + project = Dropdown(ref=project_name, label="项目名称", icon=icons.HOUSE, options=project_options, + on_change=module_update) + module_options = [] + module = Dropdown(ref=module_name, label="模块名称", icon=icons.MOOD, options=module_options) + tab_options = [] + for item in ['全量', '冒烟', '调试']: + tab_options.append(dropdown.Option(item)) + tab = Dropdown(ref=tab_name, label="标签名称", icon=icons.TAB, options=tab_options) + file = ElevatedButton( + "测试数据文件", + on_click=lambda _: pick_files_dialog.pick_files( + allow_multiple=False, + allowed_extensions=["yaml"] + ), + ) + + pick_files_dialog = FilePicker(on_result=pick_files_result) + selected_files = TextField(ref=test_file, label="测试数据", icon=icons.DATASET, read_only=True, ) + page.overlay.append(pick_files_dialog) + page.add( + Container(client, col={"sm": 6, "md": 4, "xl": 2}), + Container(url, col={"sm": 6, "md": 4, "xl": 2}), + Container(project, col={"sm": 6, "md": 4, "xl": 2}), + Container(module, col={"sm": 6, "md": 4, "xl": 2}), + Container(tab, col={"sm": 6, "md": 4, "xl": 2}), + ResponsiveRow([ + Container(selected_files, col={"sm": 10}), + Container(file, col={"sm": 2}), + ]), + ResponsiveRow([ + Container(ElevatedButton("运行", on_click=run), col={"sm": 1}, alignment=alignment.center), + Container(ElevatedButton("停止", on_click=stop), col={"sm": 1}, alignment=alignment.center), + ]), + Container(Column(ref=greetings), ) + ) diff --git a/cases/Interface/__init__.py b/cases/Interface/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..4709a7ce60ec6df70eb918e545aa98ac74a5d2ed --- /dev/null +++ b/cases/Interface/__init__.py @@ -0,0 +1,4 @@ +# -*- coding:utf-8 -*- +# 作者:齐振鋆 +# 日期:2023/2/22 +# 描述: diff --git a/cases/UI/GuKeYiTiHua/__init__.py b/cases/UI/GuKeYiTiHua/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..4af61da40ce9c2f92fa8bf908cc0df34b23d7d56 --- /dev/null +++ b/cases/UI/GuKeYiTiHua/__init__.py @@ -0,0 +1,6 @@ +# -*- coding:utf-8 -*- +# 作者:齐振鋆 +# 日期:2023/2/22 +# 描述: + +PROJECTNAME = '骨科一体化项目' diff --git a/cases/UI/GuKeYiTiHua/conftest.py b/cases/UI/GuKeYiTiHua/conftest.py new file mode 100644 index 0000000000000000000000000000000000000000..58bb3b76240cd51e19714115d14eb53a08efe6a9 --- /dev/null +++ b/cases/UI/GuKeYiTiHua/conftest.py @@ -0,0 +1,21 @@ +# -*- coding:utf-8 -*- +# 作者:齐振鋆 +# 日期:2022/9/27 +import logging +import pytest + +from page.GuKeYiTiHua.Public.loginPage import LoginPage +from unit.public.DataDic import DataDic + +log = logging.getLogger(__name__) +dd = DataDic() + + +@pytest.fixture(scope="session", autouse=True) +def login(): + dd.set_value('project_name', '骨科一体化项目') + login = LoginPage() + login.login() + yield + dd.get_value('db').final() + dd.get_value('driver').quit() diff --git a/cases/UI/GuKeYiTiHua/debug/__init__.py b/cases/UI/GuKeYiTiHua/debug/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..c11325d446a1272a2be4a7ba344682efd0611405 --- /dev/null +++ b/cases/UI/GuKeYiTiHua/debug/__init__.py @@ -0,0 +1,4 @@ +# -*- coding:utf-8 -*- +# 作者:齐振鋆 +# 日期:2023/3/14 +# 描述: diff --git a/cases/UI/GuKeYiTiHua/debug/test_debug.py b/cases/UI/GuKeYiTiHua/debug/test_debug.py new file mode 100644 index 0000000000000000000000000000000000000000..d0472f03e0e2c8b64d0d73fe07e6f20ffad17ecd --- /dev/null +++ b/cases/UI/GuKeYiTiHua/debug/test_debug.py @@ -0,0 +1,84 @@ +# -*- coding:utf-8 -*- +# 作者:齐振鋆 +# 日期:2023/3/14 +# 描述: + +import os + +from datetime import datetime + +import pytest +import allure +import logging + +from ddt import ddt, file_data + +from cases.UI.GuKeYiTiHua import PROJECTNAME +from component.GuKeYiTiHua.StorageManage.StorageIn.warehouse_accept import WarehouseVerify +from component.GuKeYiTiHua.StorageManage.StorageIn.warehouse_take import WarehouseTake +from component.GuKeYiTiHua.StorageManage.StorageIn.warehouse_up import WarehouseUp +from component.GuKeYiTiHua.StorageManage.StorageOut.storage_out_integration import StorageOut +from component.GuKeYiTiHua.StorageManage.StorageOut.warehouse_check import WarehouseCheck +from component.GuKeYiTiHua.StorageManage.StorageOut.warehouse_pick import WarehousePick +from component.GuKeYiTiHua.SurgeryFollow.SurgeryBack.apolegamy_back import ApolegamyBack +from component.GuKeYiTiHua.SurgeryFollow.SurgeryBack.apolegamy_out import ApolegamyOut +from component.GuKeYiTiHua.SurgeryFollow.SurgeryBack.orthopedic_take import OrthopedicTake +from component.GuKeYiTiHua.SurgeryFollow.SurgeryBack.surgery_back import SurgeryBack +from component.GuKeYiTiHua.SurgeryFollow.SurgeryLend.apolegamy_borrow import ApolegamyBorrow +from component.GuKeYiTiHua.SurgeryFollow.SurgeryLend.apolegamy_take import ApolegamyTake +from component.GuKeYiTiHua.SurgeryFollow.SurgeryLend.orthopedic_lend import OrthopedicLend +from component.GuKeYiTiHua.SurgeryFollow.SurgeryLend.out_ledger import OutLedger +from component.GuKeYiTiHua.SurgeryFollow.SurgeryLend.surgery_distribute import SurgeryDistribute +from component.GuKeYiTiHua.SurgeryFollow.SurgeryLend.surgery_require import SurgeryRequire + +from page.GuKeYiTiHua.DBQuery.db_query import DBQuery +from page.GuKeYiTiHua.Public.common import CommonElement +from unit.public.DataDic import DataDic + +log = logging.getLogger(__name__) + + +@pytest.mark.incremental +@ddt +@allure.epic(PROJECTNAME) +@allure.feature('Debug模块') +class TestDebug(object): + dd = DataDic() + + def setup_class(self): + self.dbq = DBQuery() + self.common = CommonElement() + self.sr = SurgeryRequire() + self.sd = SurgeryDistribute() + self.ol = OrthopedicLend() + self.wp = WarehousePick() + self.so = StorageOut() + self.ole = OutLedger() + self.ab = ApolegamyBorrow() + self.at = ApolegamyTake() + self.sb = SurgeryBack() + self.ot = OrthopedicTake() + self.wc = WarehouseCheck() + self.abk = ApolegamyBack() + self.aot = ApolegamyOut() + self.wt = WarehouseTake() + self.wv = WarehouseVerify() + self.wu = WarehouseUp() + + @allure.description('测试时间:{}'.format(datetime.now())) + @allure.story('调试专用') + @allure.severity(allure.severity_level.BLOCKER) + @pytest.mark.run(order=10) + @pytest.mark.debug + @file_data('{}/data/purchaseTestData.yaml'.format(os.getcwd())) + def test_debug1(self, **kwargs): + self.dd.set_value('test_data_info', kwargs) + order_code = 'OP230529000012' + # log.info(kwargs) + # self.wt.take_menu_open() + # self.wt.take_pool_take(order_code=order_code) + # self.wt.take_confirm(order_code=order_code) + self.wv.open_verify_menu() + self.wv.verify_edit_and_confirm(order_code=order_code) + # self.wu.open_up_menu() + # self.wu.up_confirm(order_code=order_code) diff --git a/cases/UI/GuKeYiTiHua/envConfig.yaml b/cases/UI/GuKeYiTiHua/envConfig.yaml new file mode 100644 index 0000000000000000000000000000000000000000..c7969fea309730438cd2f10aaa9a3c6518477333 --- /dev/null +++ b/cases/UI/GuKeYiTiHua/envConfig.yaml @@ -0,0 +1,11 @@ +dbinfo: + 'DB_HOST': '10.17.65.215' + 'DB_PORT': 3306 + 'DB_USER': 'aws' + 'DB_PASSWD': 'admins' + 'DB_NAME': 'aws' +userinfo: # 登录用户信息 + username: 'qizhenjun' + password: 'Gyxc1234' +verificationCode: 0 # 验证码识别:1开启|0关闭 +minNum: 2 \ No newline at end of file diff --git a/cases/UI/GuKeYiTiHua/purchase/__init__.py b/cases/UI/GuKeYiTiHua/purchase/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..4709a7ce60ec6df70eb918e545aa98ac74a5d2ed --- /dev/null +++ b/cases/UI/GuKeYiTiHua/purchase/__init__.py @@ -0,0 +1,4 @@ +# -*- coding:utf-8 -*- +# 作者:齐振鋆 +# 日期:2023/2/22 +# 描述: diff --git a/cases/UI/GuKeYiTiHua/purchase/test_purchase_op.py b/cases/UI/GuKeYiTiHua/purchase/test_purchase_op.py new file mode 100644 index 0000000000000000000000000000000000000000..0e368a8ccc081bb19072f6f8e88af6e6d2c0b565 --- /dev/null +++ b/cases/UI/GuKeYiTiHua/purchase/test_purchase_op.py @@ -0,0 +1,101 @@ +# -*- coding:utf-8 -*- +# 作者:齐振鋆 +# 日期:2023/2/22 +# 描述: 采购OP +import os +from datetime import datetime +from time import sleep + +import pytest +import allure +import logging + +from ddt import ddt, file_data + +from component.GuKeYiTiHua.StorageManage.StorageIn.warehouse_accept import WarehouseVerify +from component.GuKeYiTiHua.StorageManage.StorageIn.warehouse_take import WarehouseTake +from component.GuKeYiTiHua.StorageManage.StorageIn.warehouse_up import WarehouseUp +from component.GuKeYiTiHua.StorageManage.StorageInfo.serial_storage import SerialStorage +from component.GuKeYiTiHua.StorageManage.StorageOut.warehouse_check import WarehouseCheck +from component.GuKeYiTiHua.StorageManage.StorageOut.warehouse_delivery import WarehouseDelivery +from component.GuKeYiTiHua.StorageManage.StorageOut.warehouse_pick import WarehousePick +from component.GuKeYiTiHua.SurgeryFollow.SurgeryLend.orthopedic_lend import OrthopedicLend +from component.GuKeYiTiHua.SurgeryFollow.SurgeryLend.surgery_distribute import SurgeryDistribute +from component.GuKeYiTiHua.SurgeryFollow.SurgeryLend.surgery_require import SurgeryRequire +from component.GuKeYiTiHua.purchaseManage.purchaseIn.purchase_op import PurchaseOP +from page.GuKeYiTiHua.DBQuery.db_query import DBQuery +from page.GuKeYiTiHua.Public.common import CommonElement +from unit.public.DataDic import DataDic + +log = logging.getLogger(__name__) + + +@pytest.mark.incremental +@ddt +class TestPurchaseOrder(object): + dd = DataDic() + + def setup_class(self): + self.dbq = DBQuery() + self.common = CommonElement() + self.po = PurchaseOP() + self.wt = WarehouseTake() + self.wa = WarehouseVerify() + self.wu = WarehouseUp() + self.ss = SerialStorage() + + @allure.feature('采购管理') + @allure.story('采购OP') + @allure.title('测试标题') + # @pytest.mark.skip(reason='调试通过') + @allure.description('测试时间:{}'.format(datetime.now())) + @pytest.mark.purchase + @pytest.mark.run(order=10) + @file_data('{}/data/{}TestData.yaml'.format(os.getcwd(), dd.get_value('module'))) + def test_purchase_op(self, **kwargs): + with allure.step("测试数据准备..."): + log.info(kwargs) + company = self.dd.get_value('company') + warehouse = self.dd.get_value('warehouse') + if company is not None and warehouse is not None: + kwargs['company'] = company + kwargs['warehouse'] = warehouse + elif (company is None and warehouse is not None) or (company is not None and warehouse is None): + pytest.fail("公司及仓库参数需同时传入.") + cust_good = self.dd.get_value('custGood') + if cust_good is not None: + kwargs['goods'] = [[cust_good, int(self.dd.get_value('custNum'))]] + self.dd.set_value('test_data_info', kwargs) + purchase_op_code = None + + with allure.step("采购订单(OP)"): + self.po.open_menu_purchase_op() + self.po.purchase_op_create(purchase_op_code) + purchase_op_code = self.dd.get_value('purchase_op_code') + self.po.purchase_op_transact(purchase_op_code) + self.common.close_tap() + + with allure.step("仓库:收货"): + self.wt.take_menu_open() + self.wt.take_pool_take(purchase_op_code) + self.wt.take_confirm(purchase_op_code) + self.common.close_tap() + + with allure.step("仓库:验收"): + self.wa.open_verify_menu() + self.wa.verify_edit_and_confirm(purchase_op_code) + self.common.close_tap() + + with allure.step("仓库:上架"): + self.wu.open_up_menu() + self.wu.up_confirm(purchase_op_code) + self.common.close_tap() + + with allure.step("序列号库存查询"): + self.ss.open_menu_serial_storage() + total = 0 + for good in kwargs['goods']: + if self.dbq.get_serial_flag(warehouse, good[0]) == 'Y': + total += good[1] + self.ss.serial_storage_search(text=purchase_op_code, count=total) + self.common.close_tap() diff --git a/cases/UI/GuKeYiTiHua/surgery/__init__.py b/cases/UI/GuKeYiTiHua/surgery/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..c8a104d9aa57693f8723c4468ce568b90ffce6a8 --- /dev/null +++ b/cases/UI/GuKeYiTiHua/surgery/__init__.py @@ -0,0 +1,4 @@ +# -*- coding:utf-8 -*- +# 作者:齐振鋆 +# 日期:2023/1/18 +# 描述: diff --git a/cases/UI/GuKeYiTiHua/surgery/conftest.py b/cases/UI/GuKeYiTiHua/surgery/conftest.py new file mode 100644 index 0000000000000000000000000000000000000000..3ebe0148c87778a7c214ee311afb2fc482b7c221 --- /dev/null +++ b/cases/UI/GuKeYiTiHua/surgery/conftest.py @@ -0,0 +1,15 @@ +# -*- coding:utf-8 -*- +# 作者:齐振鋆 +# 日期:2022/9/27 +from time import sleep + +import pytest + + +@pytest.fixture(scope="function", autouse=True) +def function_setup_teardown(): + # scope:function, class, module, package/session + sleep(0.1) + yield + sleep(0.1) + diff --git a/cases/UI/GuKeYiTiHua/surgery/test_surgery_follow.py b/cases/UI/GuKeYiTiHua/surgery/test_surgery_follow.py new file mode 100644 index 0000000000000000000000000000000000000000..57a266daedb7d1932242906f497e85b341c6a077 --- /dev/null +++ b/cases/UI/GuKeYiTiHua/surgery/test_surgery_follow.py @@ -0,0 +1,184 @@ +# -*- coding:utf-8 -*- +# 作者:齐振鋆 +# 日期:2023/2/15 +# 描述: +import os +import pytest +import allure +import logging + +from ddt import ddt, file_data +from datetime import datetime + +from cases.UI.GuKeYiTiHua import PROJECTNAME +from component.GuKeYiTiHua.StorageManage.StorageIn.warehouse_accept import WarehouseVerify +from component.GuKeYiTiHua.StorageManage.StorageIn.warehouse_up import WarehouseUp +from component.GuKeYiTiHua.StorageManage.StorageOut.storage_out_integration import StorageOut +from component.GuKeYiTiHua.StorageManage.StorageOut.warehouse_pick import WarehousePick +from component.GuKeYiTiHua.SurgeryFollow.SurgeryBack.apolegamy_back import ApolegamyBack +from component.GuKeYiTiHua.SurgeryFollow.SurgeryBack.apolegamy_out import ApolegamyOut +from component.GuKeYiTiHua.SurgeryFollow.SurgeryBack.orthopedic_take import OrthopedicTake +from component.GuKeYiTiHua.SurgeryFollow.SurgeryBack.surgery_back import SurgeryBack +from component.GuKeYiTiHua.SurgeryFollow.SurgeryLend.apolegamy_borrow import ApolegamyBorrow +from component.GuKeYiTiHua.SurgeryFollow.SurgeryLend.apolegamy_take import ApolegamyTake +from component.GuKeYiTiHua.SurgeryFollow.SurgeryLend.orthopedic_lend import OrthopedicLend +from component.GuKeYiTiHua.SurgeryFollow.SurgeryLend.out_ledger import OutLedger +from component.GuKeYiTiHua.SurgeryFollow.SurgeryLend.surgery_distribute import SurgeryDistribute +from component.GuKeYiTiHua.SurgeryFollow.SurgeryLend.surgery_require import SurgeryRequire + +from page.GuKeYiTiHua.DBQuery.db_query import DBQuery +from page.GuKeYiTiHua.Public.common import CommonElement +from unit.public.DataDic import DataDic + +log = logging.getLogger(__name__) + + +@pytest.mark.incremental +@ddt +@allure.epic(PROJECTNAME) +@allure.feature('手术跟台模块') +class TestSurgeryFollow(object): + dd = DataDic() + + def setup_class(self): + self.dbq = DBQuery() + self.common = CommonElement() + self.sr = SurgeryRequire() + self.sd = SurgeryDistribute() + self.ol = OrthopedicLend() + self.wp = WarehousePick() + self.so = StorageOut() + self.ole = OutLedger() + self.ab = ApolegamyBorrow() + self.at = ApolegamyTake() + + self.sb = SurgeryBack() + self.ot = OrthopedicTake() + + self.wa = WarehouseVerify() + self.wu = WarehouseUp() + + self.abk = ApolegamyBack() + self.aot = ApolegamyOut() + + @allure.story('手术跟台流程') + @allure.title('借出-还回-销售') + @allure.severity(allure.severity_level.BLOCKER) + @allure.description('测试时间:{}'.format(datetime.now())) + @pytest.mark.surgery + @pytest.mark.run(order=10) + # @file_data('{}/data/{}TestData.yaml'.format(os.getcwd(), dd.get_value('module'))) + @file_data(dd.get_value('test_data_file')) + def test_surgery_normal(self, **kwargs): + with allure.step('测试数据准备...'): + log.info(kwargs) + self.dd.set_value('test_data_info', kwargs) + goods = kwargs['goods'] + process_type = kwargs['process_type'] + + if process_type == 1: + with allure.step('手术请领单'): + self.sr.surgery_require_menu_open() + self.sr.surgery_require_create() + ql_code = self.dd.get_value('ql_code') + self.sr.surgery_require_search('已办', ql_code) + self.common.close_tap() + + with allure.step('请领单配货'): + self.sd.surgery_distribute_menu_open() + self.sd.surgery_distribute_search(order_code=ql_code) + self.sd.surgery_require_distribute(order_code=ql_code) + self.sd.surgery_distribute_search(tap_name='已办', order_code=ql_code) + self.common.close_tap() + + with allure.step('骨科仓借出单'): + self.ol.orthopedic_lend_menu_open() + if process_type == 1: + self.ol.orthopedic_lend_search(ot='QL', order_code=ql_code) + self.ol.orthopedic_lend_edit_submit() + else: + self.ol.orthopedic_lend_create() + jc_code = self.dd.get_value('jc_code') + self.ol.orthopedic_lend_search(order_code=jc_code) + self.ol.orthopedic_lend_transact(jc_code) + self.ol.orthopedic_lend_search('已办', order_code=jc_code) + self.common.close_tap() + + with allure.step("仓库:发货-拣货-复核"): + self.so.storage_out_integration(jc_code, len(goods)) + + with allure.step("借出单出库台账"): + self.ole.open_menu_out_ledger() + self.ole.out_ledger_search(order_code=jc_code) + self.common.close_tap() + + with allure.step("选配类借入单"): + self.ab.open_menu_apolegamy_borrow() + self.ab.apolegamy_borrow_search(order_code=jc_code) + self.ab.get_apolegamy_borrow_code(jc_code) + self.common.close_tap() + + with allure.step("选配类收货单"): + self.at.open_menu_apolegamy_take() + jr_code = self.dd.get_value('jr_code') + self.at.apolegamy_take_search(order_code=jr_code) + self.common.close_tap() + + with allure.step("手术跟台还回单"): + self.sb.open_menu_surgery_back() + self.sb.surgery_back_search(order_code=jc_code) + self.sb.get_surgery_back_code(jc_code) + self.common.close_tap() + + with allure.step("骨科仓归还收货"): + self.ot.open_menu_orthopedic_take() + follow = kwargs['follow'] + self.ot.orthopedic_take_create(None, jc_code, follow) + self.ot.orthopedic_take_search(tap_name='已办', order_code=self.dd.get_value('hhsh_code')) + self.common.close_tap() + + with allure.step("仓库:验收"): + self.wa.open_verify_menu() + hh_code = self.dd.get_value('hh_code') + self.wa.verify_edit_and_confirm(order_code=hh_code, order_type='HH') if follow == 'N' else 0 + self.wa.verify_order_search('已办', order_code=hh_code) + self.common.close_tap() + + with allure.step("仓库:上架"): + self.wu.open_up_menu() + self.wu.up_confirm(order_code=hh_code) if follow == 'N' else 0 + self.wu.up_order_search('已办', order_code=hh_code) + self.common.close_tap() + + with allure.step("选配类还回出库"): + self.abk.open_menu_apolegamy_back() + self.abk.apolegamy_back_search(order_code=hh_code) + self.abk.get_apolegamy_out_code(order_code=hh_code) + self.common.close_tap() + + with allure.step("选配类还回出库单出库"): + self.aot.open_menu_apolegamy_out() + self.aot.apolegamy_out_search(order_code=self.dd.get_value('fh_code')) + self.common.close_tap() + + # 连台新流程 + if follow == 'Y': + with allure.step("连台:请领单"): + self.sr.surgery_require_menu_open() + new_ql_code = self.dbq.get_follow_ql_code(hh_code) + log.info('连台生成请领单号:【{}】'.format(new_ql_code)) + self.sr.surgery_require_search('已办', new_ql_code) + self.common.close_tap() + + with allure.step("连台:借出单"): + self.ol.orthopedic_lend_menu_open() + self.ol.orthopedic_lend_search(ot='QL', order_code=new_ql_code) + self.ol.orthopedic_lend_edit_submit(follow) + self.common.close_tap() + + with allure.step("连台:仓库:拣货"): + self.wp.open_menu_warehouse_pick() + self.wp.pick_order_search(tap_name='待办', order_code=self.dd.get_value('new_jc_code')) + self.common.close_tap() + + # 选配类转销售单 diff --git a/cases/UI/GuKeYiTiHua/transfer/__init__.py b/cases/UI/GuKeYiTiHua/transfer/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..7736bb9c3ddb93188271545120bba2b5343812d2 --- /dev/null +++ b/cases/UI/GuKeYiTiHua/transfer/__init__.py @@ -0,0 +1,4 @@ +# -*- coding:utf-8 -*- +# 作者:齐振鋆 +# 日期:2023/3/12 +# 描述: diff --git a/cases/UI/GuKeYiTiHua/transfer/test_transfer_01out.py b/cases/UI/GuKeYiTiHua/transfer/test_transfer_01out.py new file mode 100644 index 0000000000000000000000000000000000000000..77fa896aab114339648e71bb622223396b3a3af9 --- /dev/null +++ b/cases/UI/GuKeYiTiHua/transfer/test_transfer_01out.py @@ -0,0 +1,60 @@ +''' +@Project :gukeyitihua +@File :1.py +@IDE :PyCharm +@Author :何凯 +@Date :2023/3/12 10:35 +''' + + +import os +import logging +import allure +import pytest as pytest +from ddt import ddt, file_data + +from page.GuKeYiTiHua.Public.common import CommonElement +from unit.public.DataDic import DataDic +from component.GuKeYiTiHua.Transfer.transfer_out import TransferOut +from component.GuKeYiTiHua.StorageManage.StorageOut.storage_out_integration import StorageOut +from component.GuKeYiTiHua.StorageManage.StorageOut.warehouse_check import WarehouseCheck +from component.GuKeYiTiHua.StorageManage.StorageOut.warehouse_delivery import WarehouseDelivery +from component.GuKeYiTiHua.StorageManage.StorageOut.warehouse_pick import WarehousePick +log = logging.getLogger(__name__) + +@pytest.mark.incremental +@ddt +class TestBoundOrder(object): + def setup_class(self): + self.dd = DataDic() + self.sr = TransferOut() + self.so = StorageOut() + self.wd = WarehouseDelivery() + self.wp = WarehousePick() + self.wc = WarehouseCheck() + self.common = CommonElement() + + @allure.feature('出库') + @allure.story('调拨出库单') + @allure.title('调拨出库单创建') + # @pytest.mark.skip(reason='调试通过') + @allure.description('选择公司->选择业务员->选择调拨出库仓->选择调拨入库仓->保存->添加商品->输入数量->提交') + @pytest.mark.transfer + @pytest.mark.run(order=10) + @file_data('{}/data/transferTestData.yaml'.format(os.getcwd())) + def test_Outboundorder(self, **kwargs): + log.info(kwargs) + self.dd.set_value('test_data_info', kwargs) + goods = kwargs['goods'] + #创建调拨出库单 + self.sr.open_menu_transfer_out() + self.sr.transfer_out_code_create() + transfer_out_code = self.dd.get_value('transfer_out_code') + #审核 + self.sr.transfer_out_code_transact(transfer_out_code) + self.common.close_tap() + #库存管理-发货-拣货-复核 + transfer_out_code = self.dd.get_value('transfer_out_code') + self.so.storage_out_integration(transfer_out_code, goods) + + diff --git a/cases/UI/GuKeYiTiHua/transfer/test_transfer_02in.py b/cases/UI/GuKeYiTiHua/transfer/test_transfer_02in.py new file mode 100644 index 0000000000000000000000000000000000000000..a9fc2502e83b1bd0b0e049f0a19d1356e221e39a --- /dev/null +++ b/cases/UI/GuKeYiTiHua/transfer/test_transfer_02in.py @@ -0,0 +1,70 @@ +''' +@Project :test_guke +@File :test_transfer_02in.py +@IDE :PyCharm +@Author :何凯 +@Date :2023/3/17 15:58 +''' +import os +import logging +import allure +import pytest as pytest +from ddt import ddt, file_data + +from component.GuKeYiTiHua.StorageManage.StorageIn.warehouse_accept import WarehouseVerify +from component.GuKeYiTiHua.StorageManage.StorageIn.warehouse_take import WarehouseTake +from component.GuKeYiTiHua.StorageManage.StorageIn.warehouse_up import WarehouseUp +from component.GuKeYiTiHua.Transfer.transfer_in import TransferIn +from page.GuKeYiTiHua.Public.common import CommonElement +from unit.public.DataDic import DataDic +from component.GuKeYiTiHua.StorageManage.StorageOut.storage_out_integration import StorageOut +from component.GuKeYiTiHua.StorageManage.StorageOut.warehouse_check import WarehouseCheck +from component.GuKeYiTiHua.StorageManage.StorageOut.warehouse_delivery import WarehouseDelivery +from component.GuKeYiTiHua.StorageManage.StorageOut.warehouse_pick import WarehousePick +log = logging.getLogger(__name__) + +@pytest.mark.incremental +@ddt +class TestBoundOrder(object): + def setup_class(self): + self.dd = DataDic() + self.dr = TransferIn() + self.so = StorageOut() + self.wd = WarehouseDelivery() + self.wp = WarehousePick() + self.wc = WarehouseCheck() + self.common = CommonElement() + self.wt = WarehouseTake() + self.wa = WarehouseVerify() + self.wu = WarehouseUp() + + @allure.feature('入库') + @allure.story('调拨入库单') + @allure.title('调拨出库单提交') + # @pytest.mark.skip(reason='调试通过') + @allure.description('打开调拨入库单->提交') + @pytest.mark.transferin + @pytest.mark.run(order=10) + def test_Inboundorder(self): + # 调拨入库单提交 + # transfer_out_code = self.dd.get_value('transfer_out_code') + self.dr.open_menu_transfer_in() + self.dr.transfer_in_code_create('ST2023031400006') + transfer_in_code = self.dd.get_value('transfer_in_code') + self.dd.set_value('test_data_info', {'goods': ['10005528']}) + self.dr.transfer_in_code_cancel('ST2023031400006') + self.common.close_tap() + + # # 收货 + # self.wt.take_menu_open() + # self.wt.take_pool_take(transfer_in_code) + # self.wt.take_confirm(transfer_in_code) + # self.common.close_tap() + # # 验收 + # self.wa.open_verify_menu() + # self.wa.verify_edit_and_confirm(transfer_in_code) + # self.common.close_tap() + # # 上架 + # self.wu.open_up_menu() + # self.wu.up_confirm(transfer_in_code) + # self.common.close_tap() diff --git a/cases/UI/GuKeYiTiHua/transfer/test_transfer_out_red.py b/cases/UI/GuKeYiTiHua/transfer/test_transfer_out_red.py new file mode 100644 index 0000000000000000000000000000000000000000..ff05c77d72b77de7ce0b35d92d9974897acc3152 --- /dev/null +++ b/cases/UI/GuKeYiTiHua/transfer/test_transfer_out_red.py @@ -0,0 +1,77 @@ +''' +@Project :test_guke +@File :test_transfer_out_red.py +@IDE :PyCharm +@Author :何凯 +@Date :2023/3/25 11:36 +''' + + +import os +import logging +import allure +import pytest as pytest +from ddt import ddt, file_data + +from component.GuKeYiTiHua.StorageManage.StorageIn.warehouse_accept import WarehouseVerify +from component.GuKeYiTiHua.StorageManage.StorageIn.warehouse_take import WarehouseTake +from component.GuKeYiTiHua.StorageManage.StorageIn.warehouse_up import WarehouseUp +from component.GuKeYiTiHua.Transfer.transfer_in import TransferIn +from component.GuKeYiTiHua.Transfer.transfer_out_red import TransferOutRed +from page.GuKeYiTiHua.Public.common import CommonElement +from unit.public.DataDic import DataDic +from component.GuKeYiTiHua.Transfer.transfer_out import TransferOut +from component.GuKeYiTiHua.StorageManage.StorageOut.storage_out_integration import StorageOut +from component.GuKeYiTiHua.StorageManage.StorageOut.warehouse_check import WarehouseCheck +from component.GuKeYiTiHua.StorageManage.StorageOut.warehouse_delivery import WarehouseDelivery +from component.GuKeYiTiHua.StorageManage.StorageOut.warehouse_pick import WarehousePick +log = logging.getLogger(__name__) + +@pytest.mark.incremental +@ddt +class TestBoundOrder(object): + def setup_class(self): + self.dd = DataDic() + self.sr = TransferOut() + self.dr = TransferIn() + self.dc = TransferOutRed() + self.so = StorageOut() + self.wd = WarehouseDelivery() + self.wp = WarehousePick() + self.wc = WarehouseCheck() + self.common = CommonElement() + self.wt = WarehouseTake() + self.wa = WarehouseVerify() + self.wu = WarehouseUp() + @allure.feature('出库') + @allure.story('调拨出库单') + @allure.title('调拨出库单创建') + # @pytest.mark.skip(reason='调试通过') + @allure.description('选择公司->选择业务员->选择调拨出库仓->选择调拨入库仓->保存->添加商品->输入数量->提交') + @pytest.mark.transferoutred + @pytest.mark.run(order=10) + @file_data('{}/data/transferTestData.yaml'.format(os.getcwd())) + def test_Outboundorder_Red(self, **kwargs): + log.info(kwargs) + # self.dd.set_value('test_data_info', kwargs) + # goods = kwargs['goods'] + # #创建调拨出库单 + # self.sr.open_menu_transfer_out() + # self.sr.transfer_out_code_create() + # transfer_out_code = self.dd.get_value('transfer_out_code') + # #审核 + # self.sr.transfer_out_code_transact(transfer_out_code) + # self.common.close_tap() + # #库存管理-发货-拣货-复核 + # transfer_out_code = self.dd.get_value('transfer_out_code') + # self.so.storage_out_integration(transfer_out_code, goods) + # #调拨入库单提交 + # transfer_out_code = self.dd.get_value('transfer_out_code') + # self.dr.open_menu_transfer_in() + # self.dr.transfer_in_code_create('transfer_out_code') + # #调拨入库单整单取消 + # self.dr.transfer_in_code_cancel(transfer_out_code) + # self.common.close_tap() + #创建调拨出库红冲单 + self.dc.open_menu_transfer_out_red() + self.dc.transfer_out_red_code_create() \ No newline at end of file diff --git a/cases/UI/__init__.py b/cases/UI/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..4709a7ce60ec6df70eb918e545aa98ac74a5d2ed --- /dev/null +++ b/cases/UI/__init__.py @@ -0,0 +1,4 @@ +# -*- coding:utf-8 -*- +# 作者:齐振鋆 +# 日期:2023/2/22 +# 描述: diff --git a/cases/UI/conftest.py b/cases/UI/conftest.py new file mode 100644 index 0000000000000000000000000000000000000000..f1f338d6877537f04a4a6f7b62d8f7c67f50250b --- /dev/null +++ b/cases/UI/conftest.py @@ -0,0 +1,55 @@ +# -*- coding:utf-8 -*- +# 作者:齐振鋆 +# 日期:2023/2/23 +# 描述: +import logging +import os + +import pytest +from selenium import webdriver +from webdriver_manager.chrome import ChromeDriverManager + +from unit.public.DBUnit import MysqlDataBase +from unit.public.DataDic import DataDic +from unit.public.YamlUtil import UtilYaml + +log = logging.getLogger(__name__) +dd = DataDic() + + +@pytest.fixture(scope="session", autouse=True) +def init_browser(pytestconfig): + """初始化测试""" + log.info('初始化浏览器......') + client = dd.get_value('client') + chrome_options = webdriver.ChromeOptions() + # chrome_options.add_argument('--user-agent=""') # 设置请求头的User-Agent + # chrome_options.add_argument('--window-size=1280x1024') # 设置浏览器分辨率(窗口大小) + chrome_options.add_argument('--start-maximized') # 最大化运行(全屏窗口),不设置,取元素会报错 + chrome_options.add_experimental_option("excludeSwitches", ['enable-automation']) # 禁用浏览器正在被自动化程序控制的提示 + chrome_options.add_argument('--incognito') # 隐身模式(无痕模式) + # chrome_options.add_argument('--hide-scrollbars') # 隐藏滚动条, 应对一些特殊页面 + # chrome_options.add_argument('--disable-javascript') # 禁用javascript + # chrome_options.add_argument('--blink-settings=imagesEnabled=false') # 不加载图片, 提升速度 + # chrome_options.add_argument('--headless') # 浏览器不提供可视化页面 + chrome_options.add_argument('--ignore-certificate-errors') # 禁用扩展插件并实现窗口最大化 + # chrome_options.add_argument('--disable-gpu') # 禁用GPU加速 + # chrome_options.add_argument('–disable-software-rasterizer') + # chrome_options.add_argument('--disable-extensions') + # driver = webdriver.Chrome(executable_path=os.path.join(dd.get_value('root_path'), 'driver', 'chromedriver.exe')) if test_host == 'localhost' else webdriver.Remote(command_executor='http://{}:5555/wd/hub'.format(test_host), options=chrome_options) + driver = webdriver.Chrome(ChromeDriverManager().install())if client == 'localhost' else webdriver.Remote(command_executor='http://{}:5555/wd/hub'.format(client), options=chrome_options) + dd.set_value('driver', driver) + driver.maximize_window() + + log.info('读取项目配置文件......') + project_conf_path = os.path.join(dd.get_value('root_path'), 'cases', 'UI', dd.get_value('project'), 'envConfig.yaml') + project_conf = UtilYaml(project_conf_path).load_yaml() + dd.set_value('project_conf', project_conf) + dd.set_value('minNum', project_conf['minNum']) + + log.info('初始化数据库连接......') + dd.set_value('db', MysqlDataBase(project_conf['dbinfo'])) + + url = dd.get_value('url') + log.info('开打网址:{}'.format(url)) + driver.get(url) diff --git a/cases/__init__.py b/cases/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..9cce890cc1bc06cb6df91f2388d03e1fe063e15e --- /dev/null +++ b/cases/__init__.py @@ -0,0 +1,3 @@ +# -*- coding:utf-8 -*- +# 作者:齐振鋆 +# 日期:2022/8/11 diff --git a/component/GuKeYiTiHua/StorageManage/StorageIn/__init__.py b/component/GuKeYiTiHua/StorageManage/StorageIn/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..fc471755f7f9ac2aa1c3fa938adabeebf793f565 --- /dev/null +++ b/component/GuKeYiTiHua/StorageManage/StorageIn/__init__.py @@ -0,0 +1,4 @@ +# -*- coding:utf-8 -*- +# 作者:齐振鋆 +# 日期:2023/2/20 +# 描述: diff --git a/component/GuKeYiTiHua/StorageManage/StorageIn/warehouse_accept.py b/component/GuKeYiTiHua/StorageManage/StorageIn/warehouse_accept.py new file mode 100644 index 0000000000000000000000000000000000000000..ea860dcb536fd3cca5db6e7f913ef0e7a9b10c97 --- /dev/null +++ b/component/GuKeYiTiHua/StorageManage/StorageIn/warehouse_accept.py @@ -0,0 +1,136 @@ +# -*- coding:utf-8 -*- +# 作者:齐振鋆 +# 日期:2023/2/27 +# 描述: 仓库验收 +import logging +import os +import allure +import pytest +import pyautogui + +from random import randint +from time import sleep, time + +from component.GuKeYiTiHua import iframe, menu, list_page, button, order_detail_main, modal, dbq, table +from component.GuKeYiTiHua.StorageManage import first_menu +from page.GuKeYiTiHua.Public.orderDetailPage import OrderDetailTable, ScanTable +from unit.public.YamlUtil import UtilYaml + +log = logging.getLogger(__name__) +pyautogui.FAILSAFE = False + + +class WarehouseVerify(object): + third_menu = '仓库验收' + + def __init__(self): + self.dbq = dbq + self.iframe = iframe + self.menu = menu + self.list_page = list_page + self.button = button + self.table = table + self.order_detail_main = order_detail_main + self.order_detail_table = OrderDetailTable() + self.scan_table = ScanTable() + self.modal = modal + + @allure.step('打开菜单:{}'.format(third_menu)) + def open_verify_menu(self): + self.iframe.out_frame() + self.menu.open_menu(first_menu, self.third_menu) + + @allure.step('查询:{}'.format(third_menu)) + def verify_order_search(self, tap_name='待办', order_code=None, count=1): + self.list_page.order_search(self.third_menu, tap_name, '订单号', order_code, count) + + @allure.step('扫码录入商品') + def scan_input_goods(self, good_code, bar_code, order_type='OP', serial=None): + if order_type == 'OP': + bar = bar_code.split(' ') + self.order_detail_main.text_input_item('第一条码 ', bar[0], enter=False) + self.order_detail_main.text_input_item('第二条码 ', bar[1], enter=True) + if self.menu.wait_element("//h4[text()='选择商品']", wait_time=3) is True: + self.modal.search_and_choose_items(title='选择商品', text=good_code) + while self.menu.wait_element("//h4[text()='选择商品']/ancestor::div[@class='el-overlay']", + wait_time=3) is True: + sleep(1) + serial_number = 'YC{}'.format(self.menu.tu.get_datetime('MS')) + else: + serial_number = serial + self.order_detail_main.text_input_item('序列号 ', serial_number, enter=True) + while self.menu.wait_element(self.order_detail_main.get_element_text('生产批号 ', get=True), + 3) is True: + sleep(1) + + @allure.step('{}'.format(third_menu)) + def verify_edit_and_confirm(self, order_code, order_type='OP'): + log.info("验收信息录入并提交.") + self.verify_order_search(order_code=order_code) + self.list_page.open_order(order_code=order_code) + company = self.order_detail_main.get_element_text('公司编码 ') + warehouse = self.order_detail_main.get_element_text('仓库编码 ') + self.menu.zoom('-', 6) + if order_type == 'OP': + goods = self.order_detail_table.get_details(['商品编码', '到货数量']) + for good in goods: + good_code = good[0] + good_serial_flag = self.dbq.get_serial_flag(warehouse, good_code) + take_number = int(good[1]) + if good_serial_flag == 'Y': + good_sn_dic = UtilYaml('{}/data/goods_sn_data.yaml'.format(os.getcwd())).load_yaml() + try: + bar_code = good_sn_dic[good_code] + self.button.scan_bar() + self.iframe.to_bar_iframe(name='验收扫码') + for i in range(take_number): + self.scan_input_goods(good_code, bar_code) + self.button.click_button("//div[@class='form-item-view']", '提交') + self.iframe.to_parent_frame() + sleep(3) + except KeyError: + pytest.fail('有未维护的商品条码信息') + else: + take_number = int(self.order_detail_table.get_cell_text('到货数量', good_code)) + self.order_detail_table.input_text('验收数量', good_code, take_number) + stock_cargo_flag = self.dbq.get_stock_cargo(warehouse) + if stock_cargo_flag == 'Y': + sc_ph = self.dbq.get_pro_num(warehouse, good_code) + if sc_ph is None or sc_ph == '': + pytest.fail('启用货位管理的仓库:{},未配置商品:{}的货位.'.format(warehouse, good_code)) + else: + sc_ph = 'S{}'.format(int(time() * 100)) + self.order_detail_table.input_text('生产批号', good_code, sc_ph) + self.order_detail_table.input_text('生产日期', good_code, self.menu.tu.get_date_str(-1)) + self.order_detail_table.input_text('有效期/失效日期', good_code, self.menu.tu.get_date_str(5)) + sto_ste = self.dbq.get_storage_sterilization_flag(company, good_code) + if sto_ste[0] == '001': + self.order_detail_table.input_text('启运温度 (摄氏度)', good_code, '{}'.format(randint(-5, 5))) + self.order_detail_table.input_text('到货温度(摄氏度)', good_code, '{}'.format(randint(-5, 5))) + self.order_detail_table.input_text('启运日期', good_code, self.menu.tu.get_date_str()) + self.order_detail_table.input_text('启运时间', good_code, self.menu.tu.get_time_str(-1)) + self.order_detail_table.input_text('到货时间', good_code, self.menu.tu.get_time_str(1)) + self.order_detail_table.choose_item('运输工具说明', good_code, '冷藏车') + if sto_ste[1] == 'Y': + self.order_detail_table.input_text('灭菌批号', good_code, 'M{}'.format(int(time() * 100))) + self.order_detail_table.input_text('灭菌日期', good_code, self.menu.tu.get_date_str()) + self.order_detail_table.input_text('灭菌失效日期', good_code, self.menu.tu.get_date_str(5)) + else: + back_info = self.menu.dd.get_value('back_info') + for back_item in back_info: + if back_item['sf'] == 'Y': + scan_sns = back_item['used_serial'] + self.button.scan_bar() + self.iframe.to_bar_iframe(name='验收扫码') + for i in range(len(scan_sns)): + self.scan_input_goods(back_item['good'], bar_code=None, order_type=order_type, + serial=scan_sns[i]) + self.button.click_button("//div[@class='form-item-view']", '提交') + self.iframe.to_parent_frame() + sleep(3) + else: + take_number = int(self.order_detail_table.get_cell_text('到货数量', back_item['good'])) + self.order_detail_table.input_text('验收数量', back_item['good'], take_number) + self.menu.zoom('+', 6) + self.button.click_button("//div[@id='process-toolbar']", '提交') + self.list_page.edit_iframe_is_show() diff --git a/component/GuKeYiTiHua/StorageManage/StorageIn/warehouse_take.py b/component/GuKeYiTiHua/StorageManage/StorageIn/warehouse_take.py new file mode 100644 index 0000000000000000000000000000000000000000..00338977a4d4c34f0818bf45ba90f5744a71c435 --- /dev/null +++ b/component/GuKeYiTiHua/StorageManage/StorageIn/warehouse_take.py @@ -0,0 +1,54 @@ +# -*- coding:utf-8 -*- +# 作者:齐振鋆 +# 日期:2023/2/27 +# 描述: 仓库收货 +import logging +import allure + +from time import sleep +from selenium.common.exceptions import TimeoutException +from component.GuKeYiTiHua import iframe, menu, list_page, button, order_detail_main, modal +from component.GuKeYiTiHua.StorageManage import first_menu + +log = logging.getLogger(__name__) + + +class WarehouseTake(object): + third_menu = '仓库收货' + + def __init__(self): + self.iframe = iframe + self.menu = menu + self.list_page = list_page + self.button = button + self.order_detail_main = order_detail_main + self.modal = modal + + @allure.step('打开菜单:{}'.format(third_menu)) + def take_menu_open(self): + self.iframe.out_frame() + self.menu.open_menu(first_menu, self.third_menu) + + @allure.step('查询:{}'.format(third_menu)) + def take_order_search(self, tap_name='待办', order_code=None, count=1): + self.list_page.order_search(self.third_menu, tap_name, '订单号', order_code, count) + + @allure.step('订单池收货') + def take_pool_take(self, order_code): + log.info('订单池收货') + self.take_order_search('收货订单池', order_code, count=len(self.menu.dd.get_value('test_data_info')['goods'])) + self.list_page.checked_order(0) + self.button.click_button(button_name='收货') + try: + self.button.click_button("//div[contains(@class, 'is-message-box')]", '确定') + except TimeoutException: + pass + sleep(1) + + @allure.step('{}'.format(third_menu)) + def take_confirm(self, order_code): + log.info('收货确认') + self.take_order_search(order_code=order_code) + self.list_page.open_order('订单号') + self.button.submit() + self.list_page.edit_iframe_is_show() diff --git a/component/GuKeYiTiHua/StorageManage/StorageIn/warehouse_up.py b/component/GuKeYiTiHua/StorageManage/StorageIn/warehouse_up.py new file mode 100644 index 0000000000000000000000000000000000000000..04faed8b0690467786c23c0ea8929414c0dccce0 --- /dev/null +++ b/component/GuKeYiTiHua/StorageManage/StorageIn/warehouse_up.py @@ -0,0 +1,42 @@ +# -*- coding:utf-8 -*- +# 作者:齐振鋆 +# 日期:2023/2/27 +# 描述: 仓库上架 +import logging +import allure + +from component.GuKeYiTiHua import iframe, menu, list_page, button, order_detail_main, modal +from component.GuKeYiTiHua.StorageManage import first_menu +from page.GuKeYiTiHua.Public.orderDetailPage import OrderDetailTable + +log = logging.getLogger(__name__) + + +class WarehouseUp(object): + third_menu = '仓库上架' + + def __init__(self): + self.iframe = iframe + self.menu = menu + self.list_page = list_page + self.button = button + self.order_detail_main = order_detail_main + self.order_detail_table = OrderDetailTable() + self.modal = modal + + @allure.step('打开菜单:{}'.format(third_menu)) + def open_up_menu(self): + self.iframe.out_frame() + self.menu.open_menu(first_menu, self.third_menu) + + @allure.step('查询:{}'.format(third_menu)) + def up_order_search(self, tap_name='待办', order_code=None, count=1): + self.list_page.order_search(self.third_menu, tap_name, '订单号', order_code, count) + + @allure.step('{}'.format(third_menu)) + def up_confirm(self, order_code): + log.info('上架办理') + self.up_order_search(order_code=order_code) + self.list_page.open_order('订单号') + self.button.transact() + self.list_page.edit_iframe_is_show() diff --git a/component/GuKeYiTiHua/StorageManage/StorageInfo/__init__.py b/component/GuKeYiTiHua/StorageManage/StorageInfo/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..7736bb9c3ddb93188271545120bba2b5343812d2 --- /dev/null +++ b/component/GuKeYiTiHua/StorageManage/StorageInfo/__init__.py @@ -0,0 +1,4 @@ +# -*- coding:utf-8 -*- +# 作者:齐振鋆 +# 日期:2023/3/12 +# 描述: diff --git a/component/GuKeYiTiHua/StorageManage/StorageInfo/available_storage.py b/component/GuKeYiTiHua/StorageManage/StorageInfo/available_storage.py new file mode 100644 index 0000000000000000000000000000000000000000..3419ae650627018914a6075bd232e91b48d86316 --- /dev/null +++ b/component/GuKeYiTiHua/StorageManage/StorageInfo/available_storage.py @@ -0,0 +1,35 @@ +# -*- coding:utf-8 -*- +# 作者:齐振鋆 +# 日期:2023/3/12 +# 描述: 现有库存 +import logging +import allure + +from component.GuKeYiTiHua import iframe, list_page, menu, button, order_detail_table +from component.GuKeYiTiHua.StorageManage import first_menu + +log = logging.getLogger(__name__) + + +class AvailableStorage(object): + third_menu = '现有库存' + + def __init__(self): + self.iframe = iframe + self.menu = menu + self.list_page = list_page + self.button = button + + @allure.step('打开菜单:{}'.format(third_menu)) + def open_menu_available_storage(self): + self.iframe.out_frame() + self.menu.open_menu(first_menu, self.third_menu) + + @allure.step('查询:{}-批次库存'.format(third_menu)) + def available_storage_batch_search(self, tap_name='批次库存', field='批次/序列', text=None, count=1): + self.list_page.order_search(self.third_menu, tap_name, field, text, count) + + @allure.step('查询:{}-商品库存'.format(third_menu)) + def available_storage_good_search(self, tap_name='商品库存', field=None, text=None, count=1): + field = ['仓库编码', '商品编码'] if field is None else field + self.list_page.order_search(self.third_menu, tap_name, field, text, count) diff --git a/component/GuKeYiTiHua/StorageManage/StorageInfo/serial_access_record.py b/component/GuKeYiTiHua/StorageManage/StorageInfo/serial_access_record.py new file mode 100644 index 0000000000000000000000000000000000000000..5717a1cfb7e0cd6f8966532a8a3909010f594554 --- /dev/null +++ b/component/GuKeYiTiHua/StorageManage/StorageInfo/serial_access_record.py @@ -0,0 +1,30 @@ +# -*- coding:utf-8 -*- +# 作者:齐振鋆 +# 日期:2023/3/12 +# 描述: 序列号出入记录 +import logging +import allure + +from component.GuKeYiTiHua import iframe, list_page, menu, button, order_detail_table +from component.GuKeYiTiHua.StorageManage import first_menu + +log = logging.getLogger(__name__) + + +class SerialAccessRecord(object): + third_menu = '序列号出入记录' + + def __init__(self): + self.iframe = iframe + self.menu = menu + self.list_page = list_page + self.button = button + + @allure.step('打开菜单:{}'.format(third_menu)) + def open_menu_serial_access_record(self): + self.iframe.out_frame() + self.menu.open_menu(first_menu, self.third_menu) + + @allure.step('查询:{}'.format(third_menu)) + def serial_access_record_search(self, tap_name=None, field='订单号', text=None, count=1): + self.list_page.order_search(self.third_menu, tap_name, field, text, count) diff --git a/component/GuKeYiTiHua/StorageManage/StorageInfo/serial_storage.py b/component/GuKeYiTiHua/StorageManage/StorageInfo/serial_storage.py new file mode 100644 index 0000000000000000000000000000000000000000..bb94479d6944cf68d45132808f3aba847eec6b3e --- /dev/null +++ b/component/GuKeYiTiHua/StorageManage/StorageInfo/serial_storage.py @@ -0,0 +1,32 @@ +# -*- coding:utf-8 -*- +# 作者:齐振鋆 +# 日期:2023/3/12 +# 描述: 序列号库存 +import logging +import allure + +from component.GuKeYiTiHua import iframe, list_page, menu, button, order_detail_table +from component.GuKeYiTiHua.StorageManage import first_menu + +log = logging.getLogger(__name__) + + +class SerialStorage(object): + third_menu = '序列号库存' + + def __init__(self): + self.iframe = iframe + self.menu = menu + self.list_page = list_page + self.button = button + + @allure.step('打开菜单:{}'.format(third_menu)) + def open_menu_serial_storage(self): + self.iframe.out_frame() + self.menu.open_menu(first_menu, self.third_menu) + + @allure.step('查询:{}'.format(third_menu)) + def serial_storage_search(self, tap_name=None, field='订单号', text=None, count=1): + self.iframe.to_main_iframe() + self.menu.click("//a[text()='展开 ']") + self.list_page.order_search(self.third_menu, tap_name, field, text, count) diff --git a/component/GuKeYiTiHua/StorageManage/StorageInfo/storage_access_record.py b/component/GuKeYiTiHua/StorageManage/StorageInfo/storage_access_record.py new file mode 100644 index 0000000000000000000000000000000000000000..ccf3ee9833acf4ec60dc303253e823a312cd2314 --- /dev/null +++ b/component/GuKeYiTiHua/StorageManage/StorageInfo/storage_access_record.py @@ -0,0 +1,30 @@ +# -*- coding:utf-8 -*- +# 作者:齐振鋆 +# 日期:2023/3/12 +# 描述: 库存出入记录 +import logging +import allure + +from component.GuKeYiTiHua import iframe, list_page, menu, button, order_detail_table +from component.GuKeYiTiHua.StorageManage import first_menu + +log = logging.getLogger(__name__) + + +class StorageAccessRecord(object): + third_menu = '库存出入记录' + + def __init__(self): + self.iframe = iframe + self.menu = menu + self.list_page = list_page + self.button = button + + @allure.step('打开菜单:{}'.format(third_menu)) + def open_menu_storage_access_record(self): + self.iframe.out_frame() + self.menu.open_menu(first_menu, self.third_menu) + + @allure.step('查询:{}'.format(third_menu)) + def storage_access_record_search(self, tap_name=None, field='订单号', text=None, count=1): + self.list_page.order_search(self.third_menu, tap_name, field, text, count) diff --git a/component/GuKeYiTiHua/StorageManage/StorageInfo/storage_info_integration.py b/component/GuKeYiTiHua/StorageManage/StorageInfo/storage_info_integration.py new file mode 100644 index 0000000000000000000000000000000000000000..00df42036c470d6ae86b1a373fc3c2a7a61c2815 --- /dev/null +++ b/component/GuKeYiTiHua/StorageManage/StorageInfo/storage_info_integration.py @@ -0,0 +1,15 @@ +# -*- coding:utf-8 -*- +# 作者:齐振鋆 +# 日期:2023/3/12 +# 描述: 库存信息校验集成 + +from page.GuKeYiTiHua.Public.common import CommonElement +from unit.public.DataDic import DataDic + + +class StorageInfo(object): + def __init__(self): + pass + + def storage_info_check(self): + pass diff --git a/component/GuKeYiTiHua/StorageManage/StorageInfo/storage_occupy_record.py b/component/GuKeYiTiHua/StorageManage/StorageInfo/storage_occupy_record.py new file mode 100644 index 0000000000000000000000000000000000000000..cb3e6565230c1e143dd88d9e02d777cd17a15683 --- /dev/null +++ b/component/GuKeYiTiHua/StorageManage/StorageInfo/storage_occupy_record.py @@ -0,0 +1,34 @@ +# -*- coding:utf-8 -*- +# 作者:齐振鋆 +# 日期:2023/3/12 +# 描述: 库存占用记录 +import logging +import allure + +from component.GuKeYiTiHua import iframe, list_page, menu, button, order_detail_table +from component.GuKeYiTiHua.StorageManage import first_menu + +log = logging.getLogger(__name__) + + +class StorageOccupyRecord(object): + third_menu = '库存占用记录' + + def __init__(self): + self.iframe = iframe + self.menu = menu + self.list_page = list_page + self.button = button + + @allure.step('打开菜单:{}'.format(third_menu)) + def open_menu_storage_occupy_record(self): + self.iframe.out_frame() + self.menu.open_menu(first_menu, self.third_menu) + + @allure.step('查询:{}'.format(third_menu)) + def storage_occupy_record_search(self, tap_name='库存占用', field='订单号', text=None, count=1): + """ + param tap_name: 库存占用、序列号占用、库存占用历史、序列号占用历史 + """ + self.menu.click("//a[text()='展开 ']") + self.list_page.order_search(self.third_menu, tap_name, field, text, count) diff --git a/component/GuKeYiTiHua/StorageManage/StorageOut/__init__.py b/component/GuKeYiTiHua/StorageManage/StorageOut/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..fc471755f7f9ac2aa1c3fa938adabeebf793f565 --- /dev/null +++ b/component/GuKeYiTiHua/StorageManage/StorageOut/__init__.py @@ -0,0 +1,4 @@ +# -*- coding:utf-8 -*- +# 作者:齐振鋆 +# 日期:2023/2/20 +# 描述: diff --git a/component/GuKeYiTiHua/StorageManage/StorageOut/storage_out_integration.py b/component/GuKeYiTiHua/StorageManage/StorageOut/storage_out_integration.py new file mode 100644 index 0000000000000000000000000000000000000000..25ea123bbcb5136fdd523ed389561a792e20d6ca --- /dev/null +++ b/component/GuKeYiTiHua/StorageManage/StorageOut/storage_out_integration.py @@ -0,0 +1,47 @@ +# -*- coding:utf-8 -*- +# 作者:齐振鋆 +# 日期:2023/2/23 +# 描述: 仓库出库集成 +import allure + +from component.GuKeYiTiHua.StorageManage.StorageOut.warehouse_check import WarehouseCheck +from component.GuKeYiTiHua.StorageManage.StorageOut.warehouse_delivery import WarehouseDelivery +from component.GuKeYiTiHua.StorageManage.StorageOut.warehouse_pick import WarehousePick +from page.GuKeYiTiHua.Public.common import CommonElement +from unit.public.DataDic import DataDic + + +class StorageOut(object): + def __init__(self): + self.dd = DataDic() + self.common = CommonElement() + self.wd = WarehouseDelivery() + self.wp = WarehousePick() + self.wc = WarehouseCheck() + + def storage_out_integration(self, order_code, lines): + """ + parameter field_value: 订单号 + parameter check_data: [[商品编码, 发货数量, 复核数量], ...] + """ + # 仓库发货 + with allure.step("仓库:发货"): + self.wd.open_menu_surgery_require() + self.wd.all_order_delivery(order_code, lines) + self.wd.delivery_confirm(order_code=order_code) + self.wd.out_order_search(tap_name='已办', order_code=order_code) + self.common.close_tap() + + # 仓库拣货 + with allure.step("仓库:拣货"): + self.wp.open_menu_warehouse_pick() + self.wp.pick_confirm(order_code) + self.wp.pick_order_search(tap_name='已办', order_code=order_code) + self.common.close_tap() + + # 出库复核 + with allure.step("仓库:复核"): + self.wc.open_menu_warehouse_check() + self.wc.check_confirm(order_code) + self.wc.check_order_search(tap_name='已办', order_code=order_code) + self.common.close_tap() diff --git a/component/GuKeYiTiHua/StorageManage/StorageOut/warehouse_check.py b/component/GuKeYiTiHua/StorageManage/StorageOut/warehouse_check.py new file mode 100644 index 0000000000000000000000000000000000000000..e8f47c1b4a4daaa3d7921631b02c5ed7b3b87d72 --- /dev/null +++ b/component/GuKeYiTiHua/StorageManage/StorageOut/warehouse_check.py @@ -0,0 +1,96 @@ +# -*- coding:utf-8 -*- +# 作者:齐振鋆 +# 日期:2023/2/20 +# 描述: 出库复核页面 +import logging +import allure +import pytest + +from time import sleep +from component.GuKeYiTiHua import iframe, menu, list_page, button, order_detail_main, modal, \ + order_detail_table, dbq +from component.GuKeYiTiHua.StorageManage import first_menu +from page.GuKeYiTiHua.Public.orderDetailPage import ScanTable + +log = logging.getLogger(__name__) + + +class WarehouseCheck(object): + third_menu = '出库复核' + + def __init__(self): + self.dbq = dbq + self.iframe = iframe + self.menu = menu + self.list_page = list_page + self.button = button + self.order_detail_main = order_detail_main + self.order_detail_table = order_detail_table + self.modal = modal + self.scan_table = ScanTable() + + @allure.step('打开菜单:{}'.format(third_menu)) + def open_menu_warehouse_check(self): + self.iframe.out_frame() + self.menu.open_menu(first_menu, self.third_menu) + + @allure.step('查询:{}'.format(third_menu)) + def check_order_search(self, tap_name='待办', order_code=None, count=1): + self.list_page.order_search(self.third_menu, tap_name, '订单号', order_code, count) + + @allure.step('{}'.format(third_menu)) + def check_confirm(self, order_code): + """ + param check_data: [[商品编码,复核数量], ...] + """ + log.info('复核确认') + self.check_order_search(order_code=order_code) + self.list_page.open_order(order_code=order_code) + warehouse = self.order_detail_main.get_element_text('仓库编码 ') + goods_batch_info = [] + goods_list = self.order_detail_table.get_details(['商品编码', '拣货数量', '批次/序号']) + for good in goods_list: + good_code = good[0] + pick_number = int(good[1]) + check_number = pick_number + batch_no = good[2] + serial = [] + good_serial_flag = self.dbq.get_serial_flag(warehouse, good_code) + if good_serial_flag != 'Y': + self.order_detail_table.input_text('复核数量', good_code, check_number) + else: + # 序列号商品扫码 + self.button.click_button(button_name='复核扫码', end_str='') + self.iframe.to_bar_iframe(name='出库复核扫码') + # 通过数据库查询可用序列号 + serial_info = self.dbq.get_enable_serial(warehouse, good_code, batch_no, check_number) + log.info('序列号info:\n{}'.format(serial_info)) + # 商品序列号不足测试结束 + pytest.fail('商品【{}】可用序列号不足'.format(good_code)) if len(serial_info) < check_number else 0 + for serial_item in serial_info: + serial.append(serial_item[0]) + for i in range(check_number): + self.order_detail_main.text_input_item('序列号 ', serial[i], enter=True) + while self.scan_table.check_enter_result(serial[i]) is False: + sleep(1) + self.button.click_button(button_name='提交') + while self.menu.wait_element("//span[text()='验收扫码']/ancestor::div[@class='el-overlay']", + wait_time=3) is True: + sleep(1) + goods_batch_info.append({ + 'good': good_code, + 'sf': good_serial_flag, + 'batch': batch_no, + 'check': check_number, + 'serial': serial + }) + self.iframe.out_frame() + self.iframe.to_main_iframe() + self.iframe.to_edit_iframe() + if pick_number > check_number: + self.order_detail_table.input_text('差异数量', good_code, pick_number - check_number) + self.order_detail_table.input_text('差异原因', good_code, '复核差异') + log.info('商品序列号信息:{}'.format(goods_batch_info)) + self.menu.dd.set_value('goods_batch_info', goods_batch_info) + self.button.click_button(button_name='复核确认') + self.list_page.edit_iframe_is_show() diff --git a/component/GuKeYiTiHua/StorageManage/StorageOut/warehouse_delivery.py b/component/GuKeYiTiHua/StorageManage/StorageOut/warehouse_delivery.py new file mode 100644 index 0000000000000000000000000000000000000000..6864c1adba20958b3052ea9cbd2b35e4a3adac6b --- /dev/null +++ b/component/GuKeYiTiHua/StorageManage/StorageOut/warehouse_delivery.py @@ -0,0 +1,46 @@ +# -*- coding:utf-8 -*- +# 作者:齐振鋆 +# 日期:2023/2/20 +# 描述: 仓库发货页面 +import logging +import allure + +from component.GuKeYiTiHua import iframe, menu, list_page, button, order_detail_main, modal +from component.GuKeYiTiHua.StorageManage import first_menu + +log = logging.getLogger(__name__) + + +class WarehouseDelivery(object): + third_menu = '仓库发货' + + def __init__(self): + self.iframe = iframe + self.menu = menu + self.list_page = list_page + self.button = button + self.order_detail_main = order_detail_main + self.modal = modal + + @allure.step('打开菜单:{}'.format(third_menu)) + def open_menu_surgery_require(self): + self.iframe.out_frame() + self.menu.open_menu(first_menu, self.third_menu) + + @allure.step('查询:{}'.format(third_menu)) + def out_order_search(self, tap_name='待办', order_code=None, count=1): + self.list_page.order_search(self.third_menu, tap_name, '订单号', order_code, count) + + @allure.step('全选当前数据') + def all_order_delivery(self, order_code, count): + self.out_order_search('出库订单池', order_code, count) + self.list_page.checked_order(0) + self.button.all_delivery() + self.button.click_button("//*[contains(string(), '提示')]/ancestor::div[@class='el-message-box']", '确定') + + @allure.step('{}'.format(third_menu)) + def delivery_confirm(self, order_code): + self.out_order_search(order_code=order_code) + self.list_page.open_order('出货订单号') + self.button.click_button(button_name='发货确认') + self.list_page.edit_iframe_is_show() diff --git a/component/GuKeYiTiHua/StorageManage/StorageOut/warehouse_pick.py b/component/GuKeYiTiHua/StorageManage/StorageOut/warehouse_pick.py new file mode 100644 index 0000000000000000000000000000000000000000..6838dd3421301015b9c98d093a731a73e5e73f28 --- /dev/null +++ b/component/GuKeYiTiHua/StorageManage/StorageOut/warehouse_pick.py @@ -0,0 +1,39 @@ +# -*- coding:utf-8 -*- +# 作者:齐振鋆 +# 日期:2023/2/20 +# 描述: 仓库拣货页面 +import logging +import allure + +from component.GuKeYiTiHua import iframe, menu, list_page, button, order_detail_main, modal +from component.GuKeYiTiHua.StorageManage import first_menu + +log = logging.getLogger(__name__) + + +class WarehousePick(object): + third_menu = '仓库拣货' + + def __init__(self): + self.iframe = iframe + self.menu = menu + self.list_page = list_page + self.button = button + self.order_detail_main = order_detail_main + self.modal = modal + + @allure.step('打开菜单:{}'.format(third_menu)) + def open_menu_warehouse_pick(self): + self.iframe.out_frame() + self.menu.open_menu(first_menu, self.third_menu) + + @allure.step('查询:{}'.format(third_menu)) + def pick_order_search(self, tap_name='待办', order_code=None, count=1): + self.list_page.order_search(self.third_menu, tap_name, '订单号', order_code, count) + + @allure.step('{}'.format(third_menu)) + def pick_confirm(self, order_code): + self.pick_order_search(order_code=order_code) + self.list_page.open_order('拣货单号') + self.button.click_button(button_name='拣货确认') + self.list_page.edit_iframe_is_show() diff --git a/component/GuKeYiTiHua/StorageManage/__init__.py b/component/GuKeYiTiHua/StorageManage/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..5978355aa1f22f318b43f503cc0765b64a168042 --- /dev/null +++ b/component/GuKeYiTiHua/StorageManage/__init__.py @@ -0,0 +1,6 @@ +# -*- coding:utf-8 -*- +# 作者:齐振鋆 +# 日期:2023/2/20 +# 描述: + +first_menu = '库存管理' diff --git a/component/GuKeYiTiHua/SurgeryFollow/SaleSettlement/__init__.py b/component/GuKeYiTiHua/SurgeryFollow/SaleSettlement/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..0c4ffda395f6decda62a2a3f31fa498f510221c9 --- /dev/null +++ b/component/GuKeYiTiHua/SurgeryFollow/SaleSettlement/__init__.py @@ -0,0 +1,4 @@ +# -*- coding:utf-8 -*- +# 作者:齐振鋆 +# 日期:2023/2/14 +# 描述: diff --git a/component/GuKeYiTiHua/SurgeryFollow/SaleSettlement/optional_resale.py b/component/GuKeYiTiHua/SurgeryFollow/SaleSettlement/optional_resale.py new file mode 100644 index 0000000000000000000000000000000000000000..bca9e880b004153d7917f657aee803a82ce281ff --- /dev/null +++ b/component/GuKeYiTiHua/SurgeryFollow/SaleSettlement/optional_resale.py @@ -0,0 +1,91 @@ +# -*- coding:utf-8 -*- +# 作者:齐振鋆 +# 日期:2023/3/20 +# 描述: 选配类转销售 + +import allure +import logging +from time import sleep + +from component.GuKeYiTiHua import iframe, menu, list_page, order_detail_main, button, modal, order_detail_table, dbq +from component.GuKeYiTiHua.SurgeryFollow import first_menu +from unit.public.YamlUtil import UtilYaml + +log = logging.getLogger(__name__) + + +class OptionalResale(object): + third_menu = '选配类转销售单' + + def __init__(self): + self.dbq = dbq + self.iframe = iframe + self.menu = menu + self.button = button + self.list_page = list_page + self.order_detail_main = order_detail_main + self.order_detail_table = order_detail_table + self.modal = modal + + @allure.step('打开菜单:{}'.format(third_menu)) + def open_menu_optional_resale(self): + self.iframe.out_frame() + self.menu.open_menu(first_menu, self.third_menu) + + @allure.step('查询:{}'.format(third_menu)) + def optional_resale_search(self, tap_name='待办', order_code=None, count=1): + self.list_page.order_search(self.third_menu, tap_name, '销售订单号', order_code, count) + + @allure.step('新建:{}'.format(third_menu)) + def optional_resale_create(self, order_code): + """潜在问题,JC单中序列号数量过多时,会导致需要翻页,点不到的情况""" + test_data_info = self.menu.dd.get_value('test_data_info') + self.iframe.to_main_iframe() + if order_code is None: + self.button.new() + else: + self.optional_resale_search(order_code=order_code) + self.list_page.open_order(order_code=order_code) + self.order_detail_main.choose_tap('主体信息') + self.order_detail_main.some_click_item('公司名称 ') + self.modal.search_and_choose_items(text=test_data_info['company']) + self.order_detail_main.some_click_item('业务员名称 ') + self.modal.search_and_choose_items(text=test_data_info['salesman']) + self.order_detail_main.some_click_item('出库仓库 ') + self.modal.search_and_choose_items(text=test_data_info['warehouse_borrow']) + self.order_detail_main.date_input_item('手术日期 ', self.menu.tu.get_date_str()) + self.order_detail_main.choose_tap('客户及合同信息') + self.order_detail_main.some_click_item('合同号 ') + self.modal.search_and_choose_items(text=test_data_info['agreement']) + self.order_detail_main.choose_tap('主体信息') + self.button.save() + while self.order_detail_main.get_element_text('销售订单号 ').startswith('XS') is False: + sleep(1) + xs_code = self.order_detail_main.get_element_text('销售订单号 ') + UtilYaml(self.menu.dd.get_value('extract_path')).write_yaml({'xs_code': xs_code}) + log.info('销售订单号:【{}】'.format(xs_code)) + self.menu.dd.set_value('xs_code', xs_code) + self.button.click_button(button_name='借出单明细') + jc_code = self.menu.dd.get_value('jc_code') + self.modal.search_and_choose_items(placeholder='模糊检索:借出单号,商品名称,规格型号,批次号,序列号,原始订单类型', + text=jc_code, sing_choose=False) + click_item = [] + back_info = self.menu.dd.get_value('back_info') + for item in back_info: + if item['sf'] != 'Y' and item['check'] - item['back'] > 0: + click_item += [item['good']] + if item['sf'] == 'Y' and item['check'] - item['back'] > 0: + click_item += item['serial'] + for item in click_item: + self.modal.click_cell(text=item) + self.button.click_button( + "//div[@tabindex='-1']/ancestor::div[contains(@class, 'el-overlay') and not(ancestor-or-self::*[contains(@style,'display: none;')])]", + '确定', "/parent::button[@style='']") + self.button.submit() + self.list_page.edit_iframe_is_show() + + @allure.step('办理:{}'.format(third_menu)) + def optional_resale_transact(self, order_code): + self.optional_resale_search(order_code=order_code) + self.list_page.open_order(order_code=order_code) + self.button.submit() diff --git a/component/GuKeYiTiHua/SurgeryFollow/SaleSettlement/sale_out.py b/component/GuKeYiTiHua/SurgeryFollow/SaleSettlement/sale_out.py new file mode 100644 index 0000000000000000000000000000000000000000..ac64a7cef74c8179a3a63fb4aa840f6b78f01b66 --- /dev/null +++ b/component/GuKeYiTiHua/SurgeryFollow/SaleSettlement/sale_out.py @@ -0,0 +1,30 @@ +# -*- coding:utf-8 -*- +# 作者:齐振鋆 +# 日期:2023/3/21 +# 描述: 销售结算出库单 + +import logging +import allure + +from component.GuKeYiTiHua import iframe, menu, list_page, order_detail_main, button, modal, order_detail_table, dbq +from component.GuKeYiTiHua.SurgeryFollow import first_menu + +log = logging.getLogger(__name__) + + +class SaleOutStorage(object): + third_menu = '销售结算出库单' + + def __init__(self): + self.iframe = iframe + self.menu = menu + self.list_page = list_page + + @allure.step('打开菜单:{}'.format(third_menu)) + def open_menu_sale_out(self): + self.iframe.out_frame() + self.menu.open_menu(first_menu, self.third_menu) + + @allure.step('查询:{}'.format(third_menu)) + def sale_out_search(self, tap_name='已办', order_code=None, count=1): + self.list_page.order_search(self.third_menu, tap_name, '关联销售结算单号', order_code, count) diff --git a/component/GuKeYiTiHua/SurgeryFollow/SaleSettlement/surgery_reporting.py b/component/GuKeYiTiHua/SurgeryFollow/SaleSettlement/surgery_reporting.py new file mode 100644 index 0000000000000000000000000000000000000000..cda2329d420e8a39a89c809e78df81f6f4573110 --- /dev/null +++ b/component/GuKeYiTiHua/SurgeryFollow/SaleSettlement/surgery_reporting.py @@ -0,0 +1,85 @@ +# -*- coding:utf-8 -*- +# 作者:齐振鋆 +# 日期:2023/3/21 +# 描述: 手术报台 + +import logging +from time import sleep + +import allure + +from component.GuKeYiTiHua import iframe, menu, list_page, order_detail_main, button, modal, order_detail_table, dbq, em +from component.GuKeYiTiHua.SurgeryFollow import first_menu +from unit.public.YamlUtil import UtilYaml + +log = logging.getLogger(__name__) + + +class SurgeryReporting(object): + third_menu = '手术报台' + + def __init__(self): + self.dbq = dbq + self.iframe = iframe + self.menu = menu + self.button = button + self.em = em + self.list_page = list_page + self.order_detail_main = order_detail_main + self.order_detail_table = order_detail_table + self.modal = modal + + @allure.step('打开菜单:{}'.format(third_menu)) + def open_menu_surgery_reporting(self): + self.iframe.out_frame() + self.menu.open_menu(first_menu, self.third_menu) + + @allure.step('查询:{}'.format(third_menu)) + def surgery_reporting_search(self, tap_name='待办', order_code=None, count=1): + self.list_page.order_search(self.third_menu, tap_name, '手术报台单号', order_code, count) + + @allure.step('新建:{}'.format(third_menu)) + def surgery_reporting_create(self, order_code=None): + log.info('手术报台创建') + test_data_info = self.menu.dd.get_value('test_data_info') + self.iframe.out_frame() + self.iframe.to_main_iframe() + if order_code is None: + self.button.new() + else: + self.surgery_reporting_search(order_code=order_code) + self.list_page.open_order('借出单号') + self.em.check_message() + + self.order_detail_main.choose_tap('主体信息') + self.order_detail_main.some_click_item('公司名称 ') + company_code = test_data_info['company'] + self.modal.search_and_choose_items(placeholder='模糊检索:公司名称,公司编码', text=company_code) + self.button.click_button("//*[contains(string(), '提示')]/ancestor::div[@class='el-message-box']", '确定') + self.order_detail_main.drop_choose_item('手术类型 ', '翻修手术') + self.order_detail_main.drop_choose_item('手术种类 ', '中型手术') + self.order_detail_main.date_input_item('手术日期 ', self.menu.tu.get_date_str()) + self.order_detail_main.text_input_item('手术医生 ', '测试医生') + + self.order_detail_main.choose_tap('其他信息') + self.order_detail_main.text_input_item('病人姓名 ', '测试病人') + self.order_detail_main.text_input_item('病人年龄 ', 18) + self.order_detail_main.text_input_item('床位号 ', 66) + self.order_detail_main.text_input_item('住院号 ', 99) + + self.order_detail_main.choose_tap('主体信息') + self.button.save() + log.info('获取报台单号&存储') + bt_code = '' + while bt_code.startswith('BT') is False: + sleep(1) + bt_code = self.order_detail_main.get_element_text('手术报台单号 ') + log.info('手术报台单号:【{}】'.format(bt_code)) + self.menu.dd.set_value('bt_code', bt_code) + UtilYaml(self.menu.dd.get_value('extract_path')).write_yaml({'bt_code': bt_code}) + + log.info('添加商品') + self.button.click_button(button_name='添加') + self.modal.search_and_choose_items(placeholder='销售单单号', text=self.menu.dd.get_value('xs_code'), all_choose=True) + self.button.submit() + self.list_page.edit_iframe_is_show() diff --git a/component/GuKeYiTiHua/SurgeryFollow/SurgeryBack/__init__.py b/component/GuKeYiTiHua/SurgeryFollow/SurgeryBack/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..0c4ffda395f6decda62a2a3f31fa498f510221c9 --- /dev/null +++ b/component/GuKeYiTiHua/SurgeryFollow/SurgeryBack/__init__.py @@ -0,0 +1,4 @@ +# -*- coding:utf-8 -*- +# 作者:齐振鋆 +# 日期:2023/2/14 +# 描述: diff --git a/component/GuKeYiTiHua/SurgeryFollow/SurgeryBack/apolegamy_back.py b/component/GuKeYiTiHua/SurgeryFollow/SurgeryBack/apolegamy_back.py new file mode 100644 index 0000000000000000000000000000000000000000..c73c8323d65b816a92093cc9271ad9d588445fa2 --- /dev/null +++ b/component/GuKeYiTiHua/SurgeryFollow/SurgeryBack/apolegamy_back.py @@ -0,0 +1,39 @@ +# -*- coding:utf-8 -*- +# 作者:齐振鋆 +# 日期:2023/3/4 +# 描述: 选配类还回出库 +import logging +import allure + +from component.GuKeYiTiHua import iframe, menu, list_page, order_detail_main +from component.GuKeYiTiHua.SurgeryFollow import first_menu +from unit.public.YamlUtil import UtilYaml + +log = logging.getLogger(__name__) + + +class ApolegamyBack(object): + third_menu = '选配类还回出库' + + def __init__(self): + self.iframe = iframe + self.menu = menu + self.list_page = list_page + self.order_detail_main = order_detail_main + + @allure.step('打开菜单:{}'.format(third_menu)) + def open_menu_apolegamy_back(self): + self.iframe.out_frame() + self.menu.open_menu(first_menu, self.third_menu) + + @allure.step('查询:{}'.format(third_menu)) + def apolegamy_back_search(self, tap_name='已办', order_code=None, count=1): + self.list_page.order_search(self.third_menu, tap_name, '关联还回单号', order_code, count) + + @allure.step('获取{}单号'.format(third_menu)) + def get_apolegamy_out_code(self, order_code): + self.list_page.open_order(order_code=order_code) + fh_code = self.order_detail_main.get_element_text('还回出库单号 ') + UtilYaml(self.menu.dd.get_value('extract_path')).write_yaml({'fh_code': fh_code}) + log.info('还回出库单号:【{}】'.format(fh_code)) + self.menu.dd.set_value('fh_code', fh_code) diff --git a/component/GuKeYiTiHua/SurgeryFollow/SurgeryBack/apolegamy_out.py b/component/GuKeYiTiHua/SurgeryFollow/SurgeryBack/apolegamy_out.py new file mode 100644 index 0000000000000000000000000000000000000000..a7187535a79a75d5f4559f18de7d4136ee20e19e --- /dev/null +++ b/component/GuKeYiTiHua/SurgeryFollow/SurgeryBack/apolegamy_out.py @@ -0,0 +1,29 @@ +# -*- coding:utf-8 -*- +# 作者:齐振鋆 +# 日期:2023/3/4 +# 描述: 选配类还回出库单出库 +import logging +import allure + +from component.GuKeYiTiHua import iframe, menu, list_page +from component.GuKeYiTiHua.SurgeryFollow import first_menu + +log = logging.getLogger(__name__) + + +class ApolegamyOut(object): + third_menu = '选配类还回出库单出库' + + def __init__(self): + self.iframe = iframe + self.menu = menu + self.list_page = list_page + + @allure.step('打开菜单:{}'.format(third_menu)) + def open_menu_apolegamy_out(self): + self.iframe.out_frame() + self.menu.open_menu(first_menu, self.third_menu) + + @allure.step('查询:{}'.format(third_menu)) + def apolegamy_out_search(self, tap_name='已办', order_code=None, count=1): + self.list_page.order_search(self.third_menu, tap_name, '还回出库单号', order_code, count) diff --git a/component/GuKeYiTiHua/SurgeryFollow/SurgeryBack/in_ledger.py b/component/GuKeYiTiHua/SurgeryFollow/SurgeryBack/in_ledger.py new file mode 100644 index 0000000000000000000000000000000000000000..f2db86254e63fd9688de3515f06da0cdf78f48de --- /dev/null +++ b/component/GuKeYiTiHua/SurgeryFollow/SurgeryBack/in_ledger.py @@ -0,0 +1,29 @@ +# -*- coding:utf-8 -*- +# 作者:齐振鋆 +# 日期:2023/2/24 +# 描述: 还回单入库台账 +import logging +import allure + +from component.GuKeYiTiHua import iframe, menu, list_page +from component.GuKeYiTiHua.SurgeryFollow import first_menu + +log = logging.getLogger(__name__) + + +class InLedger(object): + third_menu = '手术跟台还回单入库台账' + + def __init__(self): + self.iframe = iframe + self.menu = menu + self.list_page = list_page + + @allure.step('打开菜单:{}'.format(third_menu)) + def open_menu_in_ledger(self): + self.iframe.out_frame() + self.menu.open_menu(first_menu, self.third_menu) + + @allure.step('查询:{}'.format(third_menu)) + def in_ledger_search(self, tap_name='表头数据', order_code=None, count=1): + self.list_page.order_search(self.third_menu, tap_name, '还回单号', order_code, count) diff --git a/component/GuKeYiTiHua/SurgeryFollow/SurgeryBack/orthopedic_take.py b/component/GuKeYiTiHua/SurgeryFollow/SurgeryBack/orthopedic_take.py new file mode 100644 index 0000000000000000000000000000000000000000..c42e919254b6f3d83c8c95457bed07124d983eaf --- /dev/null +++ b/component/GuKeYiTiHua/SurgeryFollow/SurgeryBack/orthopedic_take.py @@ -0,0 +1,119 @@ +# -*- coding:utf-8 -*- +# 作者:齐振鋆 +# 日期:2023/3/6 +# 描述: 骨科仓归还收货单 +import logging +import allure + +from random import randint +from time import sleep +from selenium.common.exceptions import TimeoutException +from component.GuKeYiTiHua import iframe, menu, list_page, order_detail_main, button, modal, order_detail_table, dbq +from component.GuKeYiTiHua.SurgeryFollow import first_menu +from unit.public.YamlUtil import UtilYaml + +log = logging.getLogger(__name__) + + +class OrthopedicTake(object): + third_menu = '骨科仓归还收货' + + def __init__(self): + self.dbq = dbq + self.iframe = iframe + self.menu = menu + self.button = button + self.list_page = list_page + self.order_detail_main = order_detail_main + self.order_detail_table = order_detail_table + self.modal = modal + + @allure.step('打开菜单:{}'.format(third_menu)) + def open_menu_orthopedic_take(self): + self.iframe.out_frame() + self.menu.open_menu(first_menu, self.third_menu) + + @allure.step('查询:{}'.format(third_menu)) + def orthopedic_take_search(self, tap_name='待办', order_code=None, count=1): + self.list_page.order_search(self.third_menu, tap_name, '收货单号', order_code, count) + + @allure.step('新建:{}'.format(third_menu)) + def orthopedic_take_create(self, order_code=None, jc_code=None, follow='N'): + """潜在问题,JC单中序列号数量过多时,会导致需要翻页,点不到的情况""" + test_data_info = self.menu.dd.get_value('test_data_info') + self.iframe.to_main_iframe() + if order_code is None: + self.button.new() + else: + self.orthopedic_take_search(order_code=order_code) + self.list_page.open_order(order_code=order_code) + self.order_detail_main.some_click_item('公司名称 ') + self.modal.search_and_choose_items(text=test_data_info['company']) + try: + self.button.click_button("//*[text()='温馨提示']/ancestor::div[@class='el-message-box']", '确定') + except TimeoutException: + pass + self.order_detail_main.some_click_item('还回仓库名称 ') + self.modal.search_and_choose_items(title='选择还回仓库', + text=test_data_info['warehouse_lend']) + self.order_detail_main.some_click_item('客户名称 ') + self.modal.search_and_choose_items(title='选择客户', text=test_data_info['customer']) + + lt = self.order_detail_main.some_click_item(name='连台标记 ', end_str='label', get=True) + self.order_detail_main.some_click_item(name='连台标记 ', end_str='label') \ + if (follow == 'Y' and 'is-checked' not in self.menu.get_attribute(lt, 'class')) or \ + (follow == 'N' and 'is-checked' in self.menu.get_attribute(lt, 'class')) else 0 + self.button.save() + while self.order_detail_main.get_element_text('收货单号 ').startswith('HHSH') is False: + sleep(1) + hhsh_code = self.order_detail_main.get_element_text('收货单号 ') + UtilYaml(self.menu.dd.get_value('extract_path')).write_yaml({'hhsh_code': hhsh_code}) + log.info('还回收货单号:【{}】'.format(hhsh_code)) + self.menu.dd.set_value('hhsh_code', hhsh_code) + self.button.click_button(button_name='添加') + self.modal.search_and_choose_items(placeholder='模糊检索:还回单号,借出单号,商品编码,商品名称,序列号', + text=jc_code, sing_choose=False) + click_item = [] + # back_info = self.menu.dd.get_value('goods_batch_info') if back_info is None else back_info + back_info = [] + for line in self.dbq.get_jr_info(jc_code): + good = line[0] + sf = line[1] + batch = line[2] + serial = [] + if sf == 'Y': + for s in self.dbq.get_surgery_serial(jc_code, good, batch): + serial.append(s[0]) + back_info.append({ + 'good': line[0], + 'sf': line[1], + 'batch': line[2], + 'check': line[3], + 'serial': serial + }) + for index, item in enumerate(back_info): + batch_num = item['batch'] + check_number = item['check'] + back_number = randint(1, check_number) + if item['sf'] != 'Y': + click_item.append(batch_num) + else: + sds = [] + for i in range(randint(1, len(item['serial']))): + s = back_info[index]['serial'].pop() + sds.append(s) + click_item.append(s) + back_info[index].setdefault('used_serial', sds) + back_info[index].setdefault('back', back_number) + for item in click_item: + self.modal.click_cell(text=item) + self.button.click_button( + "//div[@tabindex='-1']/ancestor::div[contains(@class, 'el-overlay') and not(ancestor-or-self::*[contains(@style,'display: none;')])]", + '确定', "/parent::button[@style='']") + self.menu.dd.set_value('back_info', back_info) + log.info('还回信息:{}'.format(back_info)) + for item in back_info: + self.order_detail_table.input_text('收货数量', item['good'], + item['back']) if item['sf'] != 'Y' else 0 + self.button.submit() + self.list_page.edit_iframe_is_show() diff --git a/component/GuKeYiTiHua/SurgeryFollow/SurgeryBack/surgery_back.py b/component/GuKeYiTiHua/SurgeryFollow/SurgeryBack/surgery_back.py new file mode 100644 index 0000000000000000000000000000000000000000..30869f73f0f8c55d4850904a2a0d7b746c1e65fb --- /dev/null +++ b/component/GuKeYiTiHua/SurgeryFollow/SurgeryBack/surgery_back.py @@ -0,0 +1,39 @@ +# -*- coding:utf-8 -*- +# 作者:齐振鋆 +# 日期:2023/3/6 +# 描述: 手术跟台还回单 +import logging +import allure + +from component.GuKeYiTiHua import iframe, menu, list_page, order_detail_main +from component.GuKeYiTiHua.SurgeryFollow import first_menu +from unit.public.YamlUtil import UtilYaml + +log = logging.getLogger(__name__) + + +class SurgeryBack(object): + third_menu = '手术跟台还回单' + + def __init__(self): + self.iframe = iframe + self.menu = menu + self.list_page = list_page + self.order_detail_main = order_detail_main + + @allure.step('打开菜单:{}'.format(third_menu)) + def open_menu_surgery_back(self): + self.iframe.out_frame() + self.menu.open_menu(first_menu, self.third_menu) + + @allure.step('查询:{}'.format(third_menu)) + def surgery_back_search(self, tap_name='表头数据', order_code=None, count=1): + self.list_page.order_search(self.third_menu, tap_name, '关联借出单号', order_code, count) + + @allure.step('获取{}单号'.format(third_menu)) + def get_surgery_back_code(self, order_code): + self.list_page.open_order(order_code=order_code) + hh_code = self.order_detail_main.get_element_text('还回订单号 ') + log.info('还回单号:【{}】'.format(hh_code)) + UtilYaml(self.menu.dd.get_value('extract_path')).write_yaml({'hh_code': hh_code}) + self.menu.dd.set_value('hh_code', hh_code) diff --git a/component/GuKeYiTiHua/SurgeryFollow/SurgeryLend/__init__.py b/component/GuKeYiTiHua/SurgeryFollow/SurgeryLend/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..317be9b389f0b476174706f35aedc342597dd3dc --- /dev/null +++ b/component/GuKeYiTiHua/SurgeryFollow/SurgeryLend/__init__.py @@ -0,0 +1,4 @@ +# -*- coding:utf-8 -*- +# 作者:齐振鋆 +# 日期:2023/2/14 +# 描述: 手术借出 diff --git a/component/GuKeYiTiHua/SurgeryFollow/SurgeryLend/apolegamy_borrow.py b/component/GuKeYiTiHua/SurgeryFollow/SurgeryLend/apolegamy_borrow.py new file mode 100644 index 0000000000000000000000000000000000000000..aac63a8f7e1a5dc793c5f5f4f28810253339a880 --- /dev/null +++ b/component/GuKeYiTiHua/SurgeryFollow/SurgeryLend/apolegamy_borrow.py @@ -0,0 +1,38 @@ +# -*- coding:utf-8 -*- +# 作者:齐振鋆 +# 日期:2023/3/4 +# 描述: 选配类借入单 +import logging +import allure + +from component.GuKeYiTiHua import iframe, menu, list_page, order_detail_main +from component.GuKeYiTiHua.SurgeryFollow import first_menu +from unit.public.YamlUtil import UtilYaml + +log = logging.getLogger(__name__) + + +class ApolegamyBorrow(object): + third_menu = '选配类借入单' + + def __init__(self): + self.iframe = iframe + self.menu = menu + self.list_page = list_page + self.order_detail_main = order_detail_main + + @allure.step('打开菜单:{}'.format(third_menu)) + def open_menu_apolegamy_borrow(self): + self.iframe.out_frame() + self.menu.open_menu(first_menu, self.third_menu) + + @allure.step('查询:{}'.format(third_menu)) + def apolegamy_borrow_search(self, tap_name='已办', order_code=None, count=1): + self.list_page.order_search(self.third_menu, tap_name, '关联借出单号', order_code, count) + + @allure.step('获取{}单号'.format(third_menu)) + def get_apolegamy_borrow_code(self, order_code): + self.list_page.open_order(order_code=order_code) + jr_code = self.order_detail_main.get_element_text('借入订单号 ') + UtilYaml(self.menu.dd.get_value('extract_path')).write_yaml({'jr_code': jr_code}) + self.menu.dd.set_value('jr_code', jr_code) diff --git a/component/GuKeYiTiHua/SurgeryFollow/SurgeryLend/apolegamy_take.py b/component/GuKeYiTiHua/SurgeryFollow/SurgeryLend/apolegamy_take.py new file mode 100644 index 0000000000000000000000000000000000000000..8ad29af9e06b59f35db27310f137fba14d84d2f2 --- /dev/null +++ b/component/GuKeYiTiHua/SurgeryFollow/SurgeryLend/apolegamy_take.py @@ -0,0 +1,29 @@ +# -*- coding:utf-8 -*- +# 作者:齐振鋆 +# 日期:2023/3/4 +# 描述: 选配类收货单 +import logging +import allure + +from component.GuKeYiTiHua import iframe, menu, list_page +from component.GuKeYiTiHua.SurgeryFollow import first_menu + +log = logging.getLogger(__name__) + + +class ApolegamyTake(object): + third_menu = '选配类收货单' + + def __init__(self): + self.iframe = iframe + self.menu = menu + self.list_page = list_page + + @allure.step('打开菜单:{}'.format(third_menu)) + def open_menu_apolegamy_take(self): + self.iframe.out_frame() + self.menu.open_menu(first_menu, self.third_menu) + + @allure.step('查询:{}'.format(third_menu)) + def apolegamy_take_search(self, tap_name='已办', order_code=None, count=1): + self.list_page.order_search(self.third_menu, tap_name, '关联借入订单号', order_code, count) diff --git a/component/GuKeYiTiHua/SurgeryFollow/SurgeryLend/orthopedic_lend.py b/component/GuKeYiTiHua/SurgeryFollow/SurgeryLend/orthopedic_lend.py new file mode 100644 index 0000000000000000000000000000000000000000..ab8fe8e6207b5e89f0be14c80232e35904c638db --- /dev/null +++ b/component/GuKeYiTiHua/SurgeryFollow/SurgeryLend/orthopedic_lend.py @@ -0,0 +1,143 @@ +# -*- coding:utf-8 -*- +# 作者:齐振鋆 +# 日期:2023/2/14 +# 描述: 骨科仓借出单 +import allure +import logging +from random import randint +from time import sleep + +from selenium.common.exceptions import TimeoutException + +from component.GuKeYiTiHua.SurgeryFollow import first_menu +from component.GuKeYiTiHua import iframe, menu, list_page, button, order_detail_main, order_detail_table, \ + modal, em, dbq +from unit.public.YamlUtil import UtilYaml + +log = logging.getLogger(__name__) + + +class OrthopedicLend(object): + third_menu = '骨科仓借出单' + + def __init__(self): + self.dbq = dbq + self.em = em + self.iframe = iframe + self.menu = menu + self.list_page = list_page + self.button = button + self.order_detail_main = order_detail_main + self.order_detail_table = order_detail_table + self.modal = modal + + @allure.step('打开菜单:{}'.format(third_menu)) + def orthopedic_lend_menu_open(self): + self.iframe.out_frame() + self.menu.open_menu(first_menu, self.third_menu) + + @allure.step('查询:{}'.format(third_menu)) + def orthopedic_lend_search(self, tap_name='待办', ot='JC', order_code=None, count=1): + order_obj = { + 'JC': '借出单号', + 'QL': '请领单号' + } + self.list_page.order_search(self.third_menu, tap_name, order_obj[ot], order_code, count) + + @allure.step('新建:{}'.format(third_menu)) + def orthopedic_lend_create(self, order_code=None): + test_data_info = self.menu.dd.get_value('test_data_info') + log.info('骨科仓借出单创建') + self.iframe.out_frame() + self.iframe.to_main_iframe() + if order_code is None: + self.button.new() + else: + self.orthopedic_lend_search(order_code=order_code) + self.list_page.open_order('借出单号') + self.em.check_message() + self.order_detail_main.choose_tap('主体信息') + # 公司 + self.order_detail_main.some_click_item('公司名称 ') + company_code = test_data_info['company'] + self.modal.search_and_choose_items(placeholder='模糊检索:公司名称,公司编码', text=company_code) + try: + self.button.click_button("//*[contains(string(), '提示')]/ancestor::div[@class='el-message-box']", '确定') + except TimeoutException: + pass + self.order_detail_main.drop_choose_item('手术类型 ', '翻修手术') + self.order_detail_main.drop_choose_item('手术种类 ', '踝关节') + self.order_detail_main.some_click_item('业务员名称 ') + self.modal.search_and_choose_items(title='根据公司编码选择员工信息', text=test_data_info['salesman']) + # 手术日期 + date_str = self.menu.tu.get_date_str(1) + self.order_detail_main.date_input_item('手术日期 ', date_str) + self.order_detail_main.text_input_item('手术医生 ', '张三丰主任医师') + self.order_detail_main.choose_tap('仓库信息') + lend_warehouse_code = test_data_info['warehouse_lend'] + borrow_warehouse_code = test_data_info['warehouse_borrow'] + return_warehouse_code = test_data_info['warehouse_return'] + self.order_detail_main.some_click_item('借出仓库名称 ') + self.modal.search_and_choose_items(title='选择借出仓库', text=lend_warehouse_code) + self.order_detail_main.some_click_item('借入仓库名称 ') + self.modal.search_and_choose_items(title='选择借入仓库', text=borrow_warehouse_code) + if lend_warehouse_code != return_warehouse_code: + self.order_detail_main.some_click_item('还回仓库名称 ') + self.modal.search_and_choose_items(title='选择还回仓库', text=return_warehouse_code) + self.order_detail_main.choose_tap('合同信息') + self.order_detail_main.some_click_item('合同号 ') + self.modal.search_and_choose_items(title='选择合同协议', text=test_data_info['agreement']) + # 保存获得请领单号 + self.order_detail_main.choose_tap('主体信息') + self.button.save() + log.info('获取请领单号&存储') + jc_code = '' + while jc_code.startswith('JC') is False: + sleep(1) + jc_code = self.order_detail_main.get_element_text('借出单号 ') + log.info('借出单号:【{}】'.format(jc_code)) + self.menu.dd.set_value('jc_code', jc_code) + UtilYaml(self.menu.dd.get_value('extract_path')).write_yaml({'jc_code': jc_code}) + + log.info('添加商品') + self.button.click_button(button_name='商品信息') + goods = test_data_info['goods'] + goods_code_list = [] + for good in goods: + goods_code_list.append(good) + self.modal.search_and_choose_items(placeholder='模糊检索:商品编码,商品名称,规格型号,厂家物料编码,存储条件', text=goods_code_list) + sleep(3 * len(goods)) + self.order_detail_table.get_cell_text('商品名称', goods_code_list[0]) + min_num = self.menu.dd.get_value('minNum') + for good in goods: + good_number = randint(min_num, 5) if self.dbq.get_serial_flag(lend_warehouse_code, + good) != 'Y' else randint(min_num, 2) + self.order_detail_table.input_text('数量', good, good_number) + self.button.submit() + self.list_page.edit_iframe_is_show() + + @allure.step('编辑:{}'.format(third_menu)) + def orthopedic_lend_edit_submit(self, follow='N'): + log.info('骨科仓借出单编辑&提交') + self.list_page.open_order('借出单号') + self.order_detail_main.choose_tap('主体信息') + log.info('获取借出单号&保存') + jc_code = self.order_detail_main.get_element_text('借出单号 ') + self.menu.dd.set_value('jc_code', jc_code) if follow == 'N' else self.menu.dd.set_value('new_jc_code', jc_code) + log.info('借出单号:【{}】'.format(jc_code)) + UtilYaml(self.menu.dd.get_value('extract_path')).write_yaml({'jc_code': jc_code}) + self.order_detail_main.drop_choose_item('手术种类 ', '髋关节') + self.order_detail_main.text_input_item('手术医生 ', '张三丰主任医师') + self.order_detail_main.choose_tap('其他信息') + self.order_detail_main.text_input_item('联系人 ', '高启强') + self.order_detail_main.text_input_item('联系电话 ', '13333333333') + self.button.submit() + self.list_page.edit_iframe_is_show() + + @allure.step('办理:{}'.format(third_menu)) + def orthopedic_lend_transact(self, order_code): + log.info('骨科仓借出单办理/审批') + self.list_page.open_order(order_code=order_code) + self.button.transact() + self.em.check_message() + self.list_page.edit_iframe_is_show() diff --git a/component/GuKeYiTiHua/SurgeryFollow/SurgeryLend/out_ledger.py b/component/GuKeYiTiHua/SurgeryFollow/SurgeryLend/out_ledger.py new file mode 100644 index 0000000000000000000000000000000000000000..14310c33bbe302ae39c1a0da5403722138f28d10 --- /dev/null +++ b/component/GuKeYiTiHua/SurgeryFollow/SurgeryLend/out_ledger.py @@ -0,0 +1,29 @@ +# -*- coding:utf-8 -*- +# 作者:齐振鋆 +# 日期:2023/2/24 +# 描述: 借出单出库台账 +import logging +import allure + +from component.GuKeYiTiHua import iframe, menu, list_page +from component.GuKeYiTiHua.SurgeryFollow import first_menu + +log = logging.getLogger(__name__) + + +class OutLedger(object): + third_menu = '手术跟台借出单出库台账' + + def __init__(self): + self.iframe = iframe + self.menu = menu + self.list_page = list_page + + @allure.step('打开菜单:{}'.format(third_menu)) + def open_menu_out_ledger(self): + self.iframe.out_frame() + self.menu.open_menu(first_menu, self.third_menu) + + @allure.step('查询:{}'.format(third_menu)) + def out_ledger_search(self, tap_name='主单', order_code=None, count=1): + self.list_page.order_search(self.third_menu, tap_name, '借出单号', order_code, count) diff --git a/component/GuKeYiTiHua/SurgeryFollow/SurgeryLend/surgery_distribute.py b/component/GuKeYiTiHua/SurgeryFollow/SurgeryLend/surgery_distribute.py new file mode 100644 index 0000000000000000000000000000000000000000..74bbc41ceba63e46c96286a86d3497a0f2b4ae78 --- /dev/null +++ b/component/GuKeYiTiHua/SurgeryFollow/SurgeryLend/surgery_distribute.py @@ -0,0 +1,62 @@ +# -*- coding:utf-8 -*- +# 作者:齐振鋆 +# 日期:2023/2/14 +# 描述: 手术请领配货单 +import logging +import allure + +from random import randint +from component.GuKeYiTiHua.SurgeryFollow import first_menu +from component.GuKeYiTiHua import iframe, menu, list_page, button, order_detail_main, order_detail_table, \ + modal + +log = logging.getLogger(__name__) + + +class SurgeryDistribute(object): + third_menu = '手术请领配货单' + + def __init__(self): + self.iframe = iframe + self.menu = menu + self.list_page = list_page + self.button = button + self.order_detail_main = order_detail_main + self.order_detail_table = order_detail_table + self.modal = modal + + @allure.step('打开菜单:{}'.format(third_menu)) + def surgery_distribute_menu_open(self): + self.iframe.out_frame() + self.menu.open_menu(first_menu, self.third_menu) + + @allure.step('查询:{}'.format(third_menu)) + def surgery_distribute_search(self, tap_name='待办', order_code=None, count=1): + self.list_page.order_search(self.third_menu, tap_name, '请领单号', order_code, count) + + @allure.step('配货:{}'.format(third_menu)) + def surgery_require_distribute(self, order_code): + test_data_info = self.menu.dd.get_value('test_data_info') + log.info('手术请领单配货') + self.list_page.open_order(order_code=order_code) + + self.order_detail_main.choose_tap('主体信息') + self.order_detail_main.some_click_item('业务员名称 ') + salesman_code = test_data_info['salesman'] + self.modal.search_and_choose_items(title='选择员工信息', text=salesman_code) + + self.order_detail_main.choose_tap('仓库信息') + lend_warehouse_code = test_data_info['warehouse_lend'] + self.order_detail_main.some_click_item('借出仓库名称 ') + self.modal.search_and_choose_items(title='选择借出仓库信息', text=lend_warehouse_code) + borrow_warehouse_code = test_data_info['warehouse_borrow'] + self.order_detail_main.some_click_item('借入仓库名称 ') + self.modal.search_and_choose_items(title='选择借入仓库信息', text=borrow_warehouse_code) + + goods = test_data_info['goods'] + for good in goods: + not_distribute_number = int(self.order_detail_table.get_cell_text('未分配数量', good)) + distribute_number = randint(self.menu.dd.get_value('minNum'), not_distribute_number) + self.order_detail_table.input_text('分配数量', good, distribute_number) + self.button.submit() + self.list_page.edit_iframe_is_show() diff --git a/component/GuKeYiTiHua/SurgeryFollow/SurgeryLend/surgery_require.py b/component/GuKeYiTiHua/SurgeryFollow/SurgeryLend/surgery_require.py new file mode 100644 index 0000000000000000000000000000000000000000..9829cee8bf6acabfcdc04907b9bdb9f1ca847f4b --- /dev/null +++ b/component/GuKeYiTiHua/SurgeryFollow/SurgeryLend/surgery_require.py @@ -0,0 +1,95 @@ +# -*- coding:utf-8 -*- +# 作者:齐振鋆 +# 日期:2023/2/14 +# 描述: 手术请领单 +import logging +from random import randint +from time import sleep + +import allure + +from component.GuKeYiTiHua import iframe, menu, list_page, button, order_detail_main, order_detail_table, \ + modal, dbq +from component.GuKeYiTiHua.SurgeryFollow import first_menu +from unit.public.YamlUtil import UtilYaml + +log = logging.getLogger(__name__) + + +class SurgeryRequire(object): + third_menu = '手术请领单' + + def __init__(self): + self.dbq = dbq + self.iframe = iframe + self.menu = menu + self.list_page = list_page + self.button = button + self.order_detail_main = order_detail_main + self.order_detail_table = order_detail_table + self.modal = modal + + @allure.step('打开菜单:{}'.format(third_menu)) + def surgery_require_menu_open(self): + self.iframe.out_frame() + self.menu.open_menu(first_menu, self.third_menu) + + @allure.step('查询:{}'.format(third_menu)) + def surgery_require_search(self, tap_name='待办', order_code=None, count=1): + self.list_page.order_search(self.third_menu, tap_name, '请领单号', order_code, count) + + @allure.step('新建:{}'.format(third_menu)) + def surgery_require_create(self, order_code=None): + test_data_info = self.menu.dd.get_value('test_data_info') + log.info('新建手术请领单') + self.iframe.to_main_iframe() + if order_code is None: + self.button.new() + else: + self.surgery_require_search(order_code=order_code) + self.list_page.open_order(order_code=order_code) + + self.order_detail_main.choose_tap('主体信息') + # 公司 + self.order_detail_main.some_click_item('公司名称 ') + company_code = test_data_info['company'] + self.modal.search_and_choose_items(placeholder='模糊检索:公司名称,公司编码', text=company_code) + self.order_detail_main.drop_choose_item('手术类型 ', '翻修手术') + # 手术日期 + date_str = self.menu.tu.get_date_str(1) + self.order_detail_main.date_input_item('手术日期 ', date_str) + + self.order_detail_main.choose_tap('客户信息') + self.order_detail_main.some_click_item('客户名称 ') + customer_code = test_data_info['customer'] + self.modal.search_and_choose_items(title='选择客户', text=customer_code) + self.order_detail_main.some_click_item('配销客户名称 ') + self.modal.search_and_choose_items(title='选择配销客户', text=customer_code) + + # self.order_detail_main.choose_tap('其他信息') + # self.order_detail_main.some_click_item(name='是否启用开单校验 ', end_str="div[@class='awsui-component']") + # 保存获得请领单号 + self.order_detail_main.choose_tap('主体信息') + self.button.save() + log.info('获取请领单号&存储') + ql_code = '' + while ql_code.startswith('QL') is False: + sleep(1) + ql_code = self.order_detail_main.get_element_text('请领单号 ') + log.info('请领单号:【{}】'.format(ql_code)) + self.menu.dd.set_value('ql_code', ql_code) + UtilYaml(self.menu.dd.get_value('extract_path')).write_yaml({'ql_code': ql_code}) + + log.info('添加商品') + self.button.click_button(button_name='商品信息') + goods = test_data_info['goods'] + self.modal.search_and_choose_items(placeholder='模糊检索:商品编码,商品名称,规格型号,厂家物料编码,存储条件', text=goods) + sleep(3 * len(goods)) + self.order_detail_table.get_cell_text('商品名称', goods[0]) + min_num = self.menu.dd.get_value('minNum') + for good in goods: + good_number = randint(min_num, 8) if self.dbq.get_serial_flag(test_data_info['warehouse_lend'], + good) != 'Y' else randint(min_num, 2) + self.order_detail_table.input_text('数量', good, good_number) + self.button.submit() + self.list_page.edit_iframe_is_show() diff --git a/component/GuKeYiTiHua/SurgeryFollow/__init__.py b/component/GuKeYiTiHua/SurgeryFollow/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..b8ad8bf7bed71317383e473372309304776b90f1 --- /dev/null +++ b/component/GuKeYiTiHua/SurgeryFollow/__init__.py @@ -0,0 +1,6 @@ +# -*- coding:utf-8 -*- +# 作者:齐振鋆 +# 日期:2023/2/14 +# 描述: 手术跟台 + +first_menu = '手术跟台' diff --git a/component/GuKeYiTiHua/Transfer/__init__.py b/component/GuKeYiTiHua/Transfer/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..4c216d629e1885557d8b9bc9445ddf0cd849a91a --- /dev/null +++ b/component/GuKeYiTiHua/Transfer/__init__.py @@ -0,0 +1,6 @@ +# -*- coding:utf-8 -*- +# 作者:齐振鋆 +# 日期:2023/3/12 +# 描述: + +first_menu = '调拨管理' diff --git a/component/GuKeYiTiHua/Transfer/transfer_in.py b/component/GuKeYiTiHua/Transfer/transfer_in.py new file mode 100644 index 0000000000000000000000000000000000000000..2784db7dba3a284a7356de50cd8268af90935283 --- /dev/null +++ b/component/GuKeYiTiHua/Transfer/transfer_in.py @@ -0,0 +1,65 @@ +''' +@Project :test_guke +@File :transfer_in.py +@IDE :PyCharm +@Author :何凯 +@Date :2023/3/17 16:00 +@desc :调拨入库单 +''' + +import logging +from random import randint +import allure +from time import sleep +from component.GuKeYiTiHua import iframe, menu, list_page, button, order_detail_main, order_detail_table, \ + modal +from component.GuKeYiTiHua.Transfer import first_menu +from unit.public.YamlUtil import UtilYaml + +log = logging.getLogger(__name__) + + +class TransferIn(object): + third_menu = '调拨入库单' + def __init__(self): + self.iframe = iframe + self.menu = menu + self.list_page = list_page + self.button = button + self.order_detail_main = order_detail_main + # self.order_detail_table = order_detail_table + # self.modal = modal + + @allure.step('打开菜单:{}'.format(third_menu)) + def open_menu_transfer_in(self): + self.iframe.out_frame() + self.menu.open_menu(first_menu, self.third_menu) + + @allure.step('查询:{}'.format(third_menu)) + def transfer_in_search(self, tap_name='待办视图', order_code=None, count=1): + self.list_page.order_search(self.third_menu, tap_name, '调拨出库单号', order_code, count) + + @allure.step('提交:{}'.format(third_menu)) + def transfer_in_code_create(self, order_code=None): + log.info('调拨入库单提交') + self.iframe.to_main_iframe() + self.transfer_in_search(order_code=order_code) + self.list_page.open_order('订单号') + self.order_detail_main.choose_tap('主体信息') + log.info('获取调拨入库单号') + transfer_in_code = '' + while transfer_in_code.startswith('OT') is False: + sleep(1) + transfer_in_code = self.order_detail_main.get_element_text('调拨入库单号 ') + self.menu.dd.set_value('transfer_in_code', transfer_in_code) + UtilYaml(self.menu.dd.get_value('extract_path')).write_yaml({'transfer_in_code': transfer_in_code}) + self.button.submit() + self.list_page.edit_iframe_is_show() + + def transfer_in_code_cancel(self, order_code=None): + log.info('调拨入库单整单取消') + self.transfer_in_search(tap_name='已办视图',order_code=order_code,count=1) + self.list_page.checked_order(0) + self.button.click_button(button_name='整单取消') + self.button.click_button(root_str="//div[contains(@class,'is-message-box')]", button_name="是") + diff --git a/component/GuKeYiTiHua/Transfer/transfer_out.py b/component/GuKeYiTiHua/Transfer/transfer_out.py new file mode 100644 index 0000000000000000000000000000000000000000..50c45e61111405a9245c605b47740140fdf33342 --- /dev/null +++ b/component/GuKeYiTiHua/Transfer/transfer_out.py @@ -0,0 +1,109 @@ +''' +@Project :gukeyitihua +@File :1.py +@IDE :PyCharm +@Author :何凯 +@Date :2023/3/12 10:35 +@desc :调拨出库单 +''' + +import logging +from random import randint + +import allure +from time import sleep + +from SeleniumLibrary.errors import ElementNotFound + +from component.GuKeYiTiHua import iframe, menu, list_page, button, order_detail_main, order_detail_table, \ + modal +from component.GuKeYiTiHua.Transfer import first_menu + +from unit.public.YamlUtil import UtilYaml + +log = logging.getLogger(__name__) + + +class TransferOut(object): + third_menu = '调拨出库单' + def __init__(self): + self.iframe = iframe + self.menu = menu + self.list_page = list_page + self.button = button + self.order_detail_main = order_detail_main + self.order_detail_table = order_detail_table + self.modal = modal + + @allure.step('打开菜单:{}'.format(third_menu)) + def open_menu_transfer_out(self): + self.iframe.out_frame() + self.menu.open_menu(first_menu, self.third_menu) + + @allure.step('查询:{}'.format(third_menu)) + def transfer_out_search(self, tap_name='待办', order_code=None, count=1): + self.list_page.order_search(self.third_menu, tap_name, '调拨出库单号', order_code, count) + + + + @allure.step('新建:{}'.format(third_menu)) + def transfer_out_code_create(self,order_code=None): + test_data_info = self.menu.dd.get_value('test_data_info') + log.info('创建调拨出库单') + self.iframe.to_main_iframe() + if order_code is None: + self.button.new() + else: + self.transfer_out_search(order_code=order_code) + self.list_page.open_order('调拨出库订单号') + + self.order_detail_main.choose_tap('主体信息') + self.order_detail_main.some_click_item('公司名称 ') + company_code = test_data_info['company'] + self.modal.search_and_choose_items(placeholder='模糊检索:公司名称,公司编码', text=company_code) + try: + self.button.click_button(root_str="//div[contains(@class, 'is-message-box')]", button_name='确定') + except Exception: + pass + + self.order_detail_main.some_click_item('业务员 ') + customer_code = test_data_info['counterman'] + self.modal.search_and_choose_items(title='选择业务员(关联部门)(调拨)', text=customer_code) + + self.order_detail_main.choose_tap('仓库信息') + lend_warehouse_code =test_data_info['warehouse_lend'] + self.order_detail_main.some_click_item('调拨出库仓库名称 ') + self.modal.search_and_choose_items(title='选择调拨出库仓库', text=lend_warehouse_code) + borrow_warehouse_code = test_data_info['warehouse_borrow'] + self.order_detail_main.some_click_item('调拨入库仓库名称 ') + self.modal.search_and_choose_items(title='选择调拨入库仓库', text=borrow_warehouse_code) + + self.order_detail_main.choose_tap('主体信息') + self.button.save() + log.info('获取调拨出库单号') + transfer_out_code = '' + while transfer_out_code.startswith('ST') is False: + sleep(1) + transfer_out_code = self.order_detail_main.get_element_text('调拨出库订单号 ') + self.menu.dd.set_value('transfer_out_code', transfer_out_code) + UtilYaml(self.menu.dd.get_value('extract_path')).write_yaml({'transfer_out_code': transfer_out_code}) + + log.info('添加商品') + self.button.click_button(button_name='商品信息') + goods = test_data_info['goods'] + self.modal.search_and_choose_items(placeholder='模糊检索:商品编码,商品全称,规格型号,厂家物料编码,生产厂家编码,行类型,产品描述,是否免备案', + text=goods) + sleep(5 * len(goods)) + self.order_detail_table.get_cell_text('商品名称', goods[0]) + for good in goods: + self.order_detail_table.input_text('调拨数量', good, randint(2, 5)) + self.button.submit() + self.list_page.edit_iframe_is_show() + + @allure.step('办理:{}'.format(third_menu)) + def transfer_out_code_transact(self, order_code): + log.info('调拨出库单办理/审批') + self.transfer_out_search(order_code=order_code, count=1) + self.list_page.open_order('调拨出库订单号') + self.button.transact() + self.list_page.edit_iframe_is_show() \ No newline at end of file diff --git a/component/GuKeYiTiHua/Transfer/transfer_out_red.py b/component/GuKeYiTiHua/Transfer/transfer_out_red.py new file mode 100644 index 0000000000000000000000000000000000000000..b40cf5ea3691973babb9c1dd450aca488738026b --- /dev/null +++ b/component/GuKeYiTiHua/Transfer/transfer_out_red.py @@ -0,0 +1,52 @@ +''' +@Project :test_guke +@File :transfer_out_red.py +@IDE :PyCharm +@Author :何凯 +@Date :2023/3/25 14:38 +@desc :调拨出库红冲单 +''' + +import logging +import time +from random import randint +import allure +from time import sleep +from component.GuKeYiTiHua import iframe, menu, list_page, button, order_detail_main, order_detail_table, \ + modal +from component.GuKeYiTiHua.Transfer import first_menu +from unit.public.YamlUtil import UtilYaml +log = logging.getLogger(__name__) + + +class TransferOutRed(object): + third_menu = '调拨出库红冲单' + def __init__(self): + self.iframe = iframe + self.menu = menu + self.list_page = list_page + self.button = button + self.order_detail_main = order_detail_main + self.order_detail_table = order_detail_table + self.modal = modal + + @allure.step('打开菜单:{}'.format(third_menu)) + def open_menu_transfer_out_red(self): + self.iframe.out_frame() + self.menu.open_menu(first_menu, self.third_menu) + + # @allure.step('查询:{}'.format(third_menu)) + # def transfer_in_search(self, tap_name='待办视图', order_code=None, count=1): + # self.list_page.order_search(self.third_menu, tap_name, '调拨出库单号', order_code, count) + + @allure.step('新建:{}'.format(third_menu)) + def transfer_out_red_code_create(self, order_code=None): + log.info('创建调拨出库红冲单') + self.iframe.to_main_iframe() + self.button.red_flush() + self.list_page.checked_order(0) + self.button.click_button(button_name='整单红冲') + + + + diff --git a/component/GuKeYiTiHua/__init__.py b/component/GuKeYiTiHua/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..79c18e9782795afa661fc30566362109c7955012 --- /dev/null +++ b/component/GuKeYiTiHua/__init__.py @@ -0,0 +1,24 @@ +# -*- coding:utf-8 -*- +# 作者:齐振鋆 +# 日期:2023/2/14 +# 描述: 骨科一体化项目 +from page.GuKeYiTiHua.DBQuery.db_query import DBQuery +from page.GuKeYiTiHua.Public.OrderListPage import OrderList +from page.GuKeYiTiHua.Public.errorMsg import ErrorMessage +from page.GuKeYiTiHua.Public.iFrame import IframeElement +from page.GuKeYiTiHua.Public.menu import MenuElement +from page.GuKeYiTiHua.Public.modalBox import ModalBoxElement +from page.GuKeYiTiHua.Public.button import ButtonElement +from page.GuKeYiTiHua.Public.orderDetailPage import OrderDetailMain, OrderDetailTable +from page.GuKeYiTiHua.Public.table import Table + +iframe = IframeElement() +menu = MenuElement() +list_page = OrderList() +button = ButtonElement() +order_detail_main = OrderDetailMain() +order_detail_table = OrderDetailTable() +modal = ModalBoxElement() +em = ErrorMessage() +dbq = DBQuery() +table = Table() diff --git a/component/GuKeYiTiHua/purchaseManage/__init__.py b/component/GuKeYiTiHua/purchaseManage/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..3edf23350a30ccf9c93ff58d1f168fbe9dffd36a --- /dev/null +++ b/component/GuKeYiTiHua/purchaseManage/__init__.py @@ -0,0 +1,6 @@ +# -*- coding:utf-8 -*- +# 作者:齐振鋆 +# 日期:2023/2/27 +# 描述: + +first_menu = '采购管理' diff --git a/component/GuKeYiTiHua/purchaseManage/purchaseBack/__init__.py b/component/GuKeYiTiHua/purchaseManage/purchaseBack/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e1f8544e188accfa14413510e7ec0ce481998f84 --- /dev/null +++ b/component/GuKeYiTiHua/purchaseManage/purchaseBack/__init__.py @@ -0,0 +1,4 @@ +# -*- coding:utf-8 -*- +# 作者:齐振鋆 +# 日期:2023/2/27 +# 描述: diff --git a/component/GuKeYiTiHua/purchaseManage/purchaseIn/__init__.py b/component/GuKeYiTiHua/purchaseManage/purchaseIn/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e1f8544e188accfa14413510e7ec0ce481998f84 --- /dev/null +++ b/component/GuKeYiTiHua/purchaseManage/purchaseIn/__init__.py @@ -0,0 +1,4 @@ +# -*- coding:utf-8 -*- +# 作者:齐振鋆 +# 日期:2023/2/27 +# 描述: diff --git a/component/GuKeYiTiHua/purchaseManage/purchaseIn/purchase_op.py b/component/GuKeYiTiHua/purchaseManage/purchaseIn/purchase_op.py new file mode 100644 index 0000000000000000000000000000000000000000..6604ba54c756ca46321df8bf61086bd855bbffbe --- /dev/null +++ b/component/GuKeYiTiHua/purchaseManage/purchaseIn/purchase_op.py @@ -0,0 +1,109 @@ +# -*- coding:utf-8 -*- +# 作者:齐振鋆 +# 日期:2023/2/27 +# 描述: +import logging +import allure + +from time import sleep + +from selenium.common.exceptions import TimeoutException + +from component.GuKeYiTiHua import iframe, menu, list_page, button, order_detail_main, order_detail_table, \ + modal +from component.GuKeYiTiHua.purchaseManage import first_menu +from unit.public.YamlUtil import UtilYaml + +log = logging.getLogger(__name__) + + +class PurchaseOP(object): + third_menu = '普通采购订单' + + def __init__(self): + self.iframe = iframe + self.menu = menu + self.list_page = list_page + self.button = button + self.order_detail_main = order_detail_main + self.order_detail_table = order_detail_table + self.modal = modal + + @allure.step('打开菜单:{}'.format(third_menu)) + def open_menu_purchase_op(self): + self.iframe.out_frame() + self.menu.open_menu(first_menu, self.third_menu) + + @allure.step('查询:{}'.format(third_menu)) + def purchase_op_search(self, tap_name='待办', order_code=None, count=1): + self.list_page.order_search(self.third_menu, tap_name, '订单号', order_code, count) + + @allure.step('新建:{}'.format(third_menu)) + def purchase_op_create(self, order_code=None): + log.info('新建采购订单(OP)') + self.iframe.out_frame() + self.iframe.to_main_iframe() + if order_code is None: + self.button.new() + else: + self.purchase_op_search(order_code=order_code) + self.list_page.open_order('订单号') + self.order_detail_main.choose_tap('主体信息') + # self.order_detail_main.some_click_item('公司名称 ') + # company_code = self.menu.dd.get_value('test_data_info')['company'] + # self.modal.search_and_choose_items(placeholder='模糊检索:公司名称,公司编码', text=company_code) + # try: + # self.button.click_button(root_str="//div[contains(@class, 'is-message-box')]", button_name='确定') + # except TimeoutException: + # pass + # self.order_detail_main.choose_tap('仓库信息') + self.order_detail_main.some_click_item('仓库名称 ') + warehouse_code = self.menu.dd.get_value('test_data_info')['warehouse'] + self.modal.search_and_choose_items(title='选择仓库', text=warehouse_code) + # ------ + self.order_detail_main.choose_tap('合同信息') + self.order_detail_main.some_click_item('采购合同/协议号 ') + agreement_code = self.menu.dd.get_value('test_data_info')['agreement'] + self.modal.search_and_choose_items(title='选择合同', text=agreement_code) + self.order_detail_main.some_click_item('供应商名称 ') + supplier_code = self.menu.dd.get_value('test_data_info')['supplier'] + self.modal.search_and_choose_items(title='选择供应商', text=supplier_code) + # ------ + self.order_detail_main.some_click_item('业务员名称 ') + salesman_code = self.menu.dd.get_value('test_data_info')['salesman'] + self.modal.search_and_choose_items(title='选择业务员及部门', text=salesman_code) + + # ------ + log.info('获取采购单号&存储') + self.order_detail_main.choose_tap('主体信息') + self.button.save() + purchase_op_code = '' + while purchase_op_code.startswith('OP') is False: + sleep(1) + purchase_op_code = self.order_detail_main.get_element_text('订单号 ') + self.menu.dd.set_value('purchase_op_code', purchase_op_code) + UtilYaml(self.menu.dd.get_value('extract_path')).write_yaml({'purchase_op_code': purchase_op_code}) + self.order_detail_main.some_click_item(name='是否启用开单校验(测试用) ', end_str="div[@class='awsui-component']") + log.info('添加商品') + self.button.click_button(button_name='商品录入') + goods_obj = self.menu.dd.get_value('test_data_info')['goods'] + goods_code_list = [] + for good in goods_obj: + goods_code_list.append(good[0]) + self.modal.search_and_choose_items(placeholder='模糊检索:商品编码,商品名称,规格型号,厂家物料编码', text=goods_code_list) + sleep(5 * len(goods_code_list)) + self.order_detail_table.get_cell_text('商品名称', goods_code_list[0]) + for good in goods_obj: + good_code = good[0] + good_number = good[1] + self.order_detail_table.input_text('订购数量', good_code, good_number) + self.button.submit() + self.list_page.edit_iframe_is_show() + + @allure.step('办理:{}'.format(third_menu)) + def purchase_op_transact(self, order_code): + log.info('采购订单办理/审批') + self.purchase_op_search(order_code=order_code, count=1) + self.list_page.open_order('订单号') + self.button.transact() + self.list_page.edit_iframe_is_show() diff --git a/component/__init__.py b/component/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..9c62bcea0c850f74615d0bfd837707a558a73248 --- /dev/null +++ b/component/__init__.py @@ -0,0 +1,4 @@ +# -*- coding:utf-8 -*- +# 作者:齐振鋆 +# 日期:2023/2/14 +# 描述: 组件,我来组成场景用例 diff --git a/conf.yaml b/conf.yaml new file mode 100644 index 0000000000000000000000000000000000000000..1eb78b9192609862034a5974f6c4718b543a24e0 --- /dev/null +++ b/conf.yaml @@ -0,0 +1,2 @@ +rate: 1.25 # 桌面分辨率,设置错误会导致验证码识别失败 +element_wait_time: 15 # 元素最大等待时间 diff --git a/conftest.py b/conftest.py new file mode 100644 index 0000000000000000000000000000000000000000..6b718f1be54db06978386853613c5669aef637fb --- /dev/null +++ b/conftest.py @@ -0,0 +1,77 @@ +# -*- coding:utf-8 -*- +# 作者:齐振鋆 +# 日期:2022/9/27 +import logging +import os +import shutil +import pytest + +from typing import Dict, Tuple +# from unit.public.WindowsUnit import WindowsCommon +from unit.public.DataDic import DataDic +from unit.public.TimeUnit import TimeUnit +from unit.public.YamlUtil import UtilYaml + +_test_failed_incremental: Dict[str, Dict[Tuple[int, ...], str]] = {} +root_path = os.getcwd() +dd = DataDic() +tu = TimeUnit() +log = logging.getLogger(__name__) + + +def pytest_runtest_makereport(item, call): + # 判断用例执行失败后是否需要跳过 + if "incremental" in item.keywords: + # 如果用例失败,添加到全局变量中 + if call.excinfo is not None: + cls_name = str(item.cls) + parametrize_index = ( + tuple(item.callspec.indices.values()) + if hasattr(item, "callspec") + else () + ) + test_name = item.originalname or item.name + _test_failed_incremental.setdefault(cls_name, {}).setdefault( + parametrize_index, test_name + ) + + +def pytest_runtest_setup(item): + # 判断用例执行失败后是否需要跳过 + if "incremental" in item.keywords: + cls_name = str(item.cls) + # 判断当前用例的类是否在全局变量中 + if cls_name in _test_failed_incremental: + parametrize_index = ( + tuple(item.callspec.indices.values()) + if hasattr(item, "callspec") + else () + ) + test_name = _test_failed_incremental[cls_name].get(parametrize_index, None) + # 如果当前类中的用例存在失败用例,就跳过 + if test_name is not None: + pytest.xfail("前置用例失败 ({})".format(test_name)) + + +@pytest.fixture(scope="session", autouse=True) +def init_test(): + """初始化测试""" + log.info('清空校验文件......') + UtilYaml('data/extract.yaml').clean_yaml() + log.info('清空旧截图......') + for item in os.listdir(os.path.join(root_path, 'file', 'screenshot')): + obj = os.path.join(root_path, 'file', 'screenshot', item) + if os.path.isdir(obj) is True and tu.get_date_str() != item: + shutil.rmtree(obj) + + +@pytest.fixture(scope="session", autouse=True) +def init_params(pytestconfig): + log.info('初始化参数......') + dd.set_value('root_path', root_path) + dd.set_value('screenshot_path', os.path.join(root_path, 'file', 'screenshot', tu.get_date_str())) + dd.set_value('extract_path', os.path.join(root_path, 'data', 'extract.yaml')) + dd.set_value('element_wait_time', UtilYaml('conf.yaml').load_yaml()['element_wait_time']) + # 桌面缩放比例 + # rate = WindowsCommon().get_screen_scale_rate() + dd.set_value('rate', UtilYaml('conf.yaml').load_yaml()['rate']) diff --git a/data/__init__.py b/data/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..9cce890cc1bc06cb6df91f2388d03e1fe063e15e --- /dev/null +++ b/data/__init__.py @@ -0,0 +1,3 @@ +# -*- coding:utf-8 -*- +# 作者:齐振鋆 +# 日期:2022/8/11 diff --git a/data/dataTemplate.yaml b/data/dataTemplate.yaml new file mode 100644 index 0000000000000000000000000000000000000000..44ee23ca5fc2d097a34ab45df51969931a998933 --- /dev/null +++ b/data/dataTemplate.yaml @@ -0,0 +1,8 @@ +- user: + name: test1 + pwd: + val: 1 +- user: + name: test2 + pwd: + val: 2 \ No newline at end of file diff --git a/data/goods_sn_data.yaml b/data/goods_sn_data.yaml new file mode 100644 index 0000000000000000000000000000000000000000..a39f10eaa5f274155d30e572cb58c18490832a44 --- /dev/null +++ b/data/goods_sn_data.yaml @@ -0,0 +1,6 @@ +"10171873": "0106902284147362 112302281723033110YC230302" +"10184703": "0110603295009902 112204071723092210PU180948" +"10154042": "0110603295012726 112204071732033110PU180948" +"10157849": "0110603295009996 112204071732033110PU180948" +"10157852": "0110603295009995 112204071732033110PU180948" +"10155177": "0106902284157369 112303011732033110AU180948" \ No newline at end of file diff --git a/data/purchaseTestData.yaml b/data/purchaseTestData.yaml new file mode 100644 index 0000000000000000000000000000000000000000..cc7a6b342e45083efd9e667798982fdd98212543 --- /dev/null +++ b/data/purchaseTestData.yaml @@ -0,0 +1,13 @@ + - + company: '00103' + warehouse: '103356' + supplier: '1003207' # 供应商 + salesman: '11353403' # 业务员 + agreement: '37373' # 合同 + goods: # [商品编码,采购数量, 条码] +# - ['10174665', 22] +# - ['10045736', 23] # 灭菌 +# - ['10145318', 99] # 冷链 + - ['10184703', 20] # 序列号 +# - ['10157852', 3] # 灭菌+序列号 +# - ['10155177', 20] # 冷链+灭菌+序列号 diff --git a/data/surgeryTestData.yaml b/data/surgeryTestData.yaml new file mode 100644 index 0000000000000000000000000000000000000000..87a831d8ab935b3b95797d2d109ffc1691d0f012 --- /dev/null +++ b/data/surgeryTestData.yaml @@ -0,0 +1,19 @@ + - + description: 'normal sense' # 场景说明 + process_type: 2 # 1:请领单开始,2:借出单开始 + company: '00122' # 公司 + warehouse_lend: '122302' # 借出仓 + warehouse_borrow: '122310' # 借入仓 + warehouse_return: '122302' # 还回仓 + salesman: '12345678' # 业务员 + customer: '1219166' # 客户 + agreement: '38618' # 合同 + follow: 'N' # 是否连台 + goods: # 借出商品 +# - 非序列号商品:10174665、10154871、10153570、10155572、10156326、10156327、10156331、10157133 +# - 序列号商品:10171873、10184703、10154042、10157849、10157852、10155177 +# - '10157133' +# - '10045736' +# - '10184703' +# - '10157852' + - '10155177' diff --git a/data/transferTestData.yaml b/data/transferTestData.yaml new file mode 100644 index 0000000000000000000000000000000000000000..0ad2e0f8e9c76fd43b939233824708396d3ad51b --- /dev/null +++ b/data/transferTestData.yaml @@ -0,0 +1,7 @@ + - + company: '00122' + counterman: '888999' + warehouse_lend: '122301' + warehouse_borrow: '122302' + goods: + - '10005528' \ No newline at end of file diff --git a/driver/__init__.py b/driver/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..9f6ec263e5c7bcd6ac74358b478b076120067c1c --- /dev/null +++ b/driver/__init__.py @@ -0,0 +1,4 @@ +# -*- coding:utf-8 -*- +# 作者:齐振鋆 +# 日期:2022/11/8 +# 描述: diff --git a/driver/client.bat b/driver/client.bat new file mode 100644 index 0000000000000000000000000000000000000000..50a5c96f343cec75a20fce7382bcface6c6d07b5 --- /dev/null +++ b/driver/client.bat @@ -0,0 +1,2 @@ +cd c:\ +java -Dwebdriver.chrome.driver="C:\chromedriver.exe" -jar selenium-server-standalone-3.141.0.jar -role node -port 5555 -hub http://10.17.73.97:4444/grid/register/ \ No newline at end of file diff --git "a/driver/driver\344\270\213\350\275\275\345\234\260\345\235\200" "b/driver/driver\344\270\213\350\275\275\345\234\260\345\235\200" new file mode 100644 index 0000000000000000000000000000000000000000..f57169775328dbee36186fc43254c9354c92c81f --- /dev/null +++ "b/driver/driver\344\270\213\350\275\275\345\234\260\345\235\200" @@ -0,0 +1,5 @@ +Edge: +https://developer.microsoft.com/zh-cn/microsoft-edge/tools/webdriver/ + +Chrome: +https://registry.npmmirror.com/binary.html?path=chromedriver/ \ No newline at end of file diff --git a/driver/selenium-server-standalone-3.141.0.jar b/driver/selenium-server-standalone-3.141.0.jar new file mode 100644 index 0000000000000000000000000000000000000000..dc0708be430730882c99c2e1a71d29a9af71964c Binary files /dev/null and b/driver/selenium-server-standalone-3.141.0.jar differ diff --git a/driver/server.bat b/driver/server.bat new file mode 100644 index 0000000000000000000000000000000000000000..7afc2facb363a61c3f9f5a6fc83a397b8858a68c --- /dev/null +++ b/driver/server.bat @@ -0,0 +1 @@ +java -jar selenium-server-standalone-3.141.0.jar -role hub -host 0.0.0.0 \ No newline at end of file diff --git a/file/__init__.py b/file/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..9f6ec263e5c7bcd6ac74358b478b076120067c1c --- /dev/null +++ b/file/__init__.py @@ -0,0 +1,4 @@ +# -*- coding:utf-8 -*- +# 作者:齐振鋆 +# 日期:2022/11/8 +# 描述: diff --git a/file/download/__init__.py b/file/download/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..9f6ec263e5c7bcd6ac74358b478b076120067c1c --- /dev/null +++ b/file/download/__init__.py @@ -0,0 +1,4 @@ +# -*- coding:utf-8 -*- +# 作者:齐振鋆 +# 日期:2022/11/8 +# 描述: diff --git a/file/upload/__init__.py b/file/upload/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..9f6ec263e5c7bcd6ac74358b478b076120067c1c --- /dev/null +++ b/file/upload/__init__.py @@ -0,0 +1,4 @@ +# -*- coding:utf-8 -*- +# 作者:齐振鋆 +# 日期:2022/11/8 +# 描述: diff --git a/main.py b/main.py new file mode 100644 index 0000000000000000000000000000000000000000..515842ae9ee79c6721a7cc28ee08dd53013cff41 --- /dev/null +++ b/main.py @@ -0,0 +1,14 @@ +# -*- coding:utf-8 -*- + +import flet + +from args_command import get_command_args +from args_ui import get_ui_args +from unit.public.DataDic import DataDic + +dd = DataDic() + + +if __name__ == '__main__': + UI = False # 运行模式 + flet.app(target=get_ui_args) if UI is True else get_command_args() diff --git a/page/GuKeYiTiHua/DBQuery/__init__.py b/page/GuKeYiTiHua/DBQuery/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..c11325d446a1272a2be4a7ba344682efd0611405 --- /dev/null +++ b/page/GuKeYiTiHua/DBQuery/__init__.py @@ -0,0 +1,4 @@ +# -*- coding:utf-8 -*- +# 作者:齐振鋆 +# 日期:2023/3/14 +# 描述: diff --git a/page/GuKeYiTiHua/DBQuery/db_query.py b/page/GuKeYiTiHua/DBQuery/db_query.py new file mode 100644 index 0000000000000000000000000000000000000000..f32877a150518a81484bce247efcc1f7e418916c --- /dev/null +++ b/page/GuKeYiTiHua/DBQuery/db_query.py @@ -0,0 +1,168 @@ +# -*- coding:utf-8 -*- +# 作者:齐振鋆 +# 日期:2023/3/14 +# 描述: +import logging + +import allure + +from unit.public.DataDic import DataDic + +log = logging.getLogger(__name__) +dd = DataDic() + + +def get_results(index, col): + def query(func): + def wrapper(self, *args, **kwargs): + db = dd.get_value('db') + sql = func(self, *args, **kwargs) + log.info(sql) + result = db.exec(sql) + return result if index is None else result[index] if col is None else result[index][col] + return wrapper + return query + + +class DBQuery(object): + @get_results(0, 0) + def get_stock_cargo(self, warehouse): + """仓库是否启用货位管理""" + with allure.step('DB:查询仓库是否启用货位管理'): + return """select + SPACE_MANAGEMENT + from + BO_EU_STOCK_CARGO_USING + where + BUSINESS_UNITS='{}';""".format(warehouse) + + @get_results(0, 0) + def get_pro_num(self, warehouse, good): + """获取生产批号""" + with allure.step('DB:获取生产批号'): + return """select + F_PRO_NUM + from + BO_EU_STOCK_CURRENT + where + F_ENTREPOT_CODE = '{warehouse}' + and F_COMMODITY_CODE = '{good}' + and F_CARGO_CODE in ( + select + F_CARGO_CODE + from + BO_EU_STOCK_MGMT_CARGO_SPACE + where + F_ENTREPOT_CODE = '{warehouse}' + and F_COMMODITY_CODE = '{good}');""".format(**locals()) + + @get_results(0, 0) + def get_serial_flag(self, warehouse, good): + """商品序列号标识""" + with allure.step('DB:查询商品序列号标识'): + return """select + F_IS_SERIAL_NO + from + BO_EU_BSI_GOODS_MCU + where + BUSINESS_UNITS='{warehouse}' + and COMMODITY_CODE='{good}';""".format(**locals()) + + @get_results(0, None) + def get_storage_sterilization_flag(self, company, good): + """获取商品存储条件、灭菌管理标识""" + with allure.step('DB:获取商品存储条件、灭菌管理标识'): + return """select + STORAGECON, STERILIZATION_FLAG + from + bo_eu_bsi_commodity + where + COMPANY='{company}' + and COMMODITY_CODE='{good}';""".format(**locals()) + + @get_results(None, None) + def get_enable_serial(self, warehouse, good, batch, num): + """获取可用序列号""" + with allure.step('DB:获取可用序列号'): + return """select + F_SERIAL + from + bo_eu_stock_serial + where + F_ENTREPOT_CODE = '{warehouse}' + and F_COMMODITY_CODE = '{good}' + and F_BATCH_SERIA = '{batch}' + and F_STATUS = '1' + and F_SERIAL not in ( + select + F_SERIAL + from + bo_eu_stock_serial_occupy + where + F_ENTREPOT_CODE = '{warehouse}' and F_COMMODITY_CODE = '{good}' + and F_BATCH_SERIA = '{batch}') + limit 0, + {num};""".format(**locals()) + + @get_results(0, 0) + def get_follow_ql_code(self, hh_code): + """获取连台请领单号""" + with allure.step('DB:获取连台请领单号'): + return """select + F_CST_ENQUIRY_NO + from + bo_eu_surgery_ior_header + where + BINDID in( + select + id + from + wfc_process + where + CREATEUSERDEPTID in( + select + TARGETDEPTID + from + wfc_task + where + TASKTITLE like '%{}%')) + order by + CREATEDATE desc + limit 0,1;""".format(hh_code) + + @get_results(None, None) + def get_back_able_serial(self, order_code): + """获取还回可用序列号""" + with allure.step('DB:获取还回可用序列号'): + return """select + F_SERIAL + from + aws.bo_eu_surgery_serial_detail + where + F_ORDER_NO = '{}' + and F_SERIAL_STATUS = 0;""".format(order_code) + + @get_results(None, None) + def get_jr_info(self, order_code): + """获取借入单信息""" + with allure.step('DB:获取借入单信息'): + return """select + F_COMMODITY_CODE, + F_SERIAL_MANGE_FLAG, + F_BATCH_NO, + F_RECEIVE_NUM + from + bo_eu_surgery_borrow_detail + where + F_REL_SALE_BILL_NO = '{}';""".format(order_code) + + @get_results(None, None) + def get_surgery_serial(self, order_code, good, batch): + """获取手术跟台序列号""" + with allure.step('DB:获取借出单商品序列号'): + return """select F_SERIAL from + bo_eu_surgery_serial_detail + where + F_ORDER_NO = '{order_code}' + and F_COMMODITY_CODE = '{good}' + and F_BATCH_NO = '{batch}';""".format(**locals()) diff --git a/page/GuKeYiTiHua/Public/OrderListPage.py b/page/GuKeYiTiHua/Public/OrderListPage.py new file mode 100644 index 0000000000000000000000000000000000000000..405667baf37d49b556948d540c6a980b4d40d7d2 --- /dev/null +++ b/page/GuKeYiTiHua/Public/OrderListPage.py @@ -0,0 +1,135 @@ +# -*- coding:utf-8 -*- +# 作者:齐振鋆 +# 日期:2023/2/14 +# 描述: +import logging +import re +import allure +import pytest + +from time import sleep +from page.GuKeYiTiHua.Public.errorMsg import ErrorMessage +from page.GuKeYiTiHua.Public.iFrame import IframeElement +from page.GuKeYiTiHua.Public.table import Table +from unit.public.UI.BasePage import BasePage + +log = logging.getLogger(__name__) + + +class OrderList(BasePage): + em = ErrorMessage() + iframe = IframeElement() + table = Table() + + def list_title(self, title): + self.wait_element("//p[@class='title-class' and text()='{}']".format(title)) + + def order_search(self, page_title, tap_name='待办', field_name=None, field_value=None, count=1, max_try=3, + count_check=True): + """ + 查找单据 + parameter page_title: 页面名称,一般为三级菜单 + parameter tap_name: + parameter field_name: 查找字段 [field1, field2, ...] + parameter field_value: 查找值 [value1, value2, ...] + parameter count: 查询结果预期数量 + parameter count_check: 是否启用数量验证,默认启用 + """ + log.info('查询:{}-{}'.format(page_title, tap_name)) + if type(field_name) != type(field_value): + raise Exception('字段名和字段值参数类型不一致') + self.out_frame() + self.iframe.to_main_iframe() + while self.list_title(page_title) is False: + sleep(1) + self.change_list_tap(tap_name) if tap_name is not None else 0 + try_count = 0 + fields = {} + if type(field_name) is not list: + fields.setdefault(field_name, field_value) + else: + for i in range(0, len(fields)): + fields.setdefault(field_name[i], field_value[i]) + while self.get_results_number() != count and try_count < 5: + log.info("查找条件:{}".format(fields)) + for index, key in enumerate(fields.keys()): + field_name, field_value = key, fields[key] + search_input = "//label[text()='{}']/following-sibling::div//input".format(field_name) + self.type(search_input, field_value) + self.enter(search_input) if index == len(fields) - 1 else 0 + sleep(3) + if count_check is False: + break + try_count += 1 + if try_count >= max_try: + self.screenshot() + pytest.fail('{}{}列表未查询到{}相关{}单据.'.format(page_title, tap_name, field_value, page_title)) + + def get_cell_text(self, field_name, row=1): + """获取视图单元格内容""" + log.info('获取第{}行,字段{}的值') + col_id = self.table.get_col_id(field_name) + return self.get_ele_text("//td[@colid='{}' and not(contains(@class, 'fixed--hidden'))][{}]".format(col_id, row)) + + def open_order(self, column=None, row=1, order_code=None): + """ + param tag: link列名 + param index: 行 + """ + if order_code is None: + tag_colid = self.table.get_col_id(column) + text = self.get_cell_text(column, row) + log.info("打开单据【{}】".format(text)) + self.click( + "(//td[@colid='{}' and not(contains(@class, 'fixed--hidden'))])[{}]//span".format(tag_colid, row)) + else: + log.info("打开单据【{}】".format(order_code)) + self.click("(//td[contains(@class, 'dw-click-cell')]//*[text()='{}'])[{}]".format(order_code, row)) + self.iframe.to_edit_iframe() + self.em.check_message() + + def checked_order(self, index=1, tag=None): + """选择单据""" + if index == 0: + log.info("全选单据...") + check_box = "//th[not(contains(@class, 'fixed--hidden'))]//span[@title='全选/取消']" + else: + log.info("勾选单据...") + check_box_colid = self.table.get_col_id(tag) + check_box = "(//td[@colid='{}' and not(contains(@class, 'fixed--hidden'))])[{}]//span[contains(@class, 'vxe-cell--checkbox')]".format( + check_box_colid, index) + self.click(check_box) + + def get_results_number(self): + """获取视图查询统计数量""" + total_str = self.get_ele_text("//span[@class='vxe-pager--total']") + total = int(re.search(r"\d+", total_str).group(0)) + return total + + def change_list_tap(self, tap_name): + """切换列表tap""" + log.info('切换到:【{}】tap页'.format(tap_name)) + self.click("//li[@role='menuitem' and text()='{}']".format(tap_name)) + + def edit_iframe_is_show(self): + """等待编辑窗口关闭""" + self.out_frame() + self.iframe.to_main_iframe() + count = 0 + while self.wait_element("//div[@class='el-drawer__body']/ancestor::div[@class='el-overlay']", + wait_time=3) is True and count < 10: + sleep(1) + count += 1 + + def get_cell_text(self, field_name, row=1): + log.info('获取第{}行,字段{}的值') + col_id = self.table.get_col_id(field_name) + return self.get_ele_text("//div[@id='dw-grid-div']//tbody//td[@colid='{}'][{}]".format(col_id, row)) + + @allure.step('字段校验') + def field_value_check(self, field_name, expected_value, line=1): + """视图单元格内容校验""" + text = self.get_cell_text(field_name, line) + if text != str(expected_value): + self.fail_screenshot() + pytest.fail('{}实际结果:{},与预期结果{} 不符'.format(field_name, text, expected_value)) diff --git a/page/GuKeYiTiHua/Public/__init__.py b/page/GuKeYiTiHua/Public/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..fdaecc50afc68160bd56ea8b34816f7d38a4f9ab --- /dev/null +++ b/page/GuKeYiTiHua/Public/__init__.py @@ -0,0 +1,4 @@ +# -*- coding:utf-8 -*- +# 作者:齐振鋆 +# 日期:2022/11/7 +# 描述: diff --git a/page/GuKeYiTiHua/Public/button.py b/page/GuKeYiTiHua/Public/button.py new file mode 100644 index 0000000000000000000000000000000000000000..07a9d92110eaa550593c97ca36b107e38ef56870 --- /dev/null +++ b/page/GuKeYiTiHua/Public/button.py @@ -0,0 +1,69 @@ +# -*- coding:utf-8 -*- +# 作者:齐振鋆 +# 日期:2023/3/4 +# 描述: + +import logging + +from page.GuKeYiTiHua.Public.errorMsg import ErrorMessage +from page.GuKeYiTiHua.Public.iFrame import IframeElement +from unit.public.UI.BasePage import BasePage + +log = logging.getLogger(__name__) + + +class ButtonElement(BasePage): + em = ErrorMessage() + iframe = IframeElement() + + def click_button(self, root_str='', button_name='保存', end_str="/ancestor::button"): + """点击按钮,默认为保存""" + log.info('点击:【{}】按钮'.format(button_name)) + self.click("{}//*[text()='{}']{}".format(root_str, button_name, end_str)) + self.em.check_message() + + def new(self): + self.click_button(button_name='新建') + self.iframe.to_edit_iframe() + + + def all_delivery(self): + """整单发货""" + self.click_button(button_name='整单发货') + + def save(self): + """保存""" + self.click_button(button_name='保存') + + def submit(self): + """提交""" + self.click_button(button_name='提交') + + def nullify(self): + """作废""" + self.click_button(button_name='作废') + + def send(self): + """发送""" + self.click_button(button_name='发送') + + def transact(self): + """办理""" + self.click_button(button_name='办理') + + def scan_bar(self): + """扫码""" + self.click("//button[text()='扫码']") + + def all_cancel(self): + """整单取消""" + self.click_button(button_name='整单取消') + + def red_flush(self): + """红冲""" + self.click_button(button_name='红冲') + self.iframe.to_transfer_out_iframe() + + def all_red_flush(self): + """整单红冲""" + self.click_button(button_name='整单红冲') \ No newline at end of file diff --git a/page/GuKeYiTiHua/Public/common.py b/page/GuKeYiTiHua/Public/common.py new file mode 100644 index 0000000000000000000000000000000000000000..f52a0f925364be1b6c0a9c93628851d02a771356 --- /dev/null +++ b/page/GuKeYiTiHua/Public/common.py @@ -0,0 +1,25 @@ +# -*- coding:utf-8 -*- +# 作者:齐振鋆 +# 日期:2023/2/14 +# 描述: +import logging + +import allure + +from unit.public.UI.BasePage import BasePage + +log = logging.getLogger(__name__) + + +class CommonElement(BasePage): + @allure.step('关闭当前tap页面') + def close_tap(self, tap_name=None): + """ + 关闭tap页,不传名称则关闭当前tap页 + :param tap_name: tap名称 + """ + log.info("Closing Tap") + self.out_frame() + tap_close_span = "//div[@id='awsui-tabs']//div[contains(@class, 'current')]/span[contains(@class, 'close')]" if tap_name is None else "//div[@id='awsui-tabs']//span[text()='{}']/following-sibling::span".format( + tap_name) + self.click(tap_close_span) diff --git a/page/GuKeYiTiHua/Public/errorMsg.py b/page/GuKeYiTiHua/Public/errorMsg.py new file mode 100644 index 0000000000000000000000000000000000000000..9f2c38e1f2ceb1a0596e9a149381b06b8871b48f --- /dev/null +++ b/page/GuKeYiTiHua/Public/errorMsg.py @@ -0,0 +1,26 @@ +# -*- coding:utf-8 -*- +# 作者:齐振鋆 +# 日期:2023/3/10 +# 描述: +import logging +import pytest + +from unit.public.UI.BasePage import BasePage + +log = logging.getLogger(__name__) + + +class ErrorMessage(BasePage): + def check_message(self): + log.info('校验错误提示') + if self.wait_element("//div[contains(@id, 'message_')]//i[contains(@class, 'el-message-icon--error')]", + wait_time=3) is True: + error_message = self.get_ele_text("//div[contains(@id, 'message_')]//p/span") + self.fail_screenshot() + pytest.fail("监听到页面错误提示:{}".format(error_message)) + + def check_details_message(self): + log.info('校验子表') + if self.wait_element("//div[contains(@class, 'validate-msg-pop-body')]", wait_time=3) is True: + self.fail_screenshot() + pytest.fail("监听到子表错误提示") diff --git a/page/GuKeYiTiHua/Public/iFrame.py b/page/GuKeYiTiHua/Public/iFrame.py new file mode 100644 index 0000000000000000000000000000000000000000..2d4b726a9ac16a9e603803313071124476d8549c --- /dev/null +++ b/page/GuKeYiTiHua/Public/iFrame.py @@ -0,0 +1,31 @@ +# -*- coding:utf-8 -*- +# 作者:齐振鋆 +# 日期:2022/11/10 +# 描述: +import logging + +from unit.public.UI.BasePage import BasePage + +log = logging.getLogger(__name__) + + +class IframeElement(BasePage): + def to_main_iframe(self): + log.info("进入主iframe") + iframe = "//div[@class='awsui-tab-content-item awsui-tab-this']//iframe[@class='metro-main-frame']" + self.to_frame(iframe) + + def to_edit_iframe(self): + log.info("进入编辑iframe") + iframe = "(//iframe[contains(@name, 'awsui-dialog-iframe')])[1]" + self.to_frame(iframe) + + def to_bar_iframe(self, name='扫码'): + log.info("进入扫码iframe") + iframe = "//div[@aria-label='{}']//iframe".format(name) + self.to_frame(iframe) + + def to_transfer_out_iframe(self): + log.info("进入调拨出库整单红冲iframe") + iframe = "//div[@aria-label='调拨出库单台账']//iframe" + self.to_frame(iframe) \ No newline at end of file diff --git a/page/GuKeYiTiHua/Public/loginPage.py b/page/GuKeYiTiHua/Public/loginPage.py new file mode 100644 index 0000000000000000000000000000000000000000..8572b04880d95eed9d549bb5bf841a2e421895c0 --- /dev/null +++ b/page/GuKeYiTiHua/Public/loginPage.py @@ -0,0 +1,95 @@ +# -*- coding:utf-8 -*- +# 作者:齐振鋆 +# 日期:2022/9/23 +import logging +import re + +import allure +import os +import time +import pytesseract + +from PIL import Image +from selenium.common.exceptions import TimeoutException, InvalidArgumentException + +from unit.public.UI.BasePage import BasePage +from unit.public.DataDic import DataDic +from page.GuKeYiTiHua.Public.menu import MenuElement + +log = logging.getLogger(__name__) + + +class LoginPage(BasePage): + mo = MenuElement() + + @allure.step('登录') + def login(self): + log.info('登录') + project_conf = self.dd.get_value('project_conf') + user_info = project_conf['userinfo'] + username_input = ('id', 'input1') + password_input = ('id', 'input2') + self.type(username_input, user_info['username']) + self.type(password_input, user_info['password']) + verificationCode = project_conf['verificationCode'] + while verificationCode == 1: + log.info('输入验证码...') + self.input_vCode() + login_button = ('id', 'loginBtn') + self.click(login_button) + # time.sleep(1) + if self.login_check() is True: + break + self.enter(password_input) if verificationCode != 1 else 0 + + def input_vCode(self, vcode_xpath='//canvas'): + rate = self.dd.get_value('rate') + self.screenshot('vcode.png') + # 定位到图片元素 + captcha_elm = self.get_element(vcode_xpath) + + # 3、取验证码的矩形区域 + point = captcha_elm.location # 字典形式 水平位置和垂直位置,x和y值 + size = captcha_elm.size # 字典形式,宽和高 + x = int(point['x']) + y = int(point['y']) + width = int(x + size['width']) + height = int(y + size['height']) + + screen_path = DataDic().get_value('screenshot_path') + filepath = os.path.join(screen_path, 'vcode.png') + image_code = Image.open(filepath) + + little_img = image_code.crop((int(x * rate), int(y * rate), int(width * rate), int(height * rate))) # 截图 + little_file_name = 'vcode{}.png'.format(int(time.time() * 1000)) + little_path = os.path.join(screen_path, little_file_name) + little_img.save(little_path) # 截图名字 + + result = '8888' + vCode = '//canvas' + try: + result = re.match(r'[\da-zA-Z]{4}', pytesseract.image_to_string(little_path).replace(' ', '')).group() + except AttributeError: + self.click(vCode) + time.sleep(1) + self.input_vCode() + log.info('验证码:{}'.format(result)) + os.remove(little_path) + fil = ['0', '1', 'o', 'i', 'O', 'I'] + fil_res = any(word if word in result else False for word in fil) + if fil_res is True or len(result) > 4: + self.click(vCode) + time.sleep(1) + self.input_vCode() + else: + vCode_input = ('id', 'photoCode') + self.type(vCode_input, result) + + def login_check(self): + try: + self.get_element("//span[text()='退出']", retry=False) + return True + except InvalidArgumentException: + return False + except TimeoutException: + return False diff --git a/page/GuKeYiTiHua/Public/menu.py b/page/GuKeYiTiHua/Public/menu.py new file mode 100644 index 0000000000000000000000000000000000000000..43a6141fd9029001321c2fba38675a1c61835137 --- /dev/null +++ b/page/GuKeYiTiHua/Public/menu.py @@ -0,0 +1,21 @@ +# -*- coding:utf-8 -*- +# 作者:齐振鋆 +# 日期:2022/9/23 +import logging +import allure + +from unit.public.UI.BasePage import BasePage + +log = logging.getLogger(__name__) + + +class MenuElement(BasePage): + def open_menu(self, first_menu_name, last_menu_name): + log.info('打开菜单:{}'.format(last_menu_name)) + first_menu = "//div[contains(@class,'menuNavTop')]//div[text()='{}']".format(first_menu_name) + second_menu = "//div[contains(@class, 'third-menu') and @navname='{}']/ancestor::div[@class='sec-menu']".format( + last_menu_name) + third_menu = "//div[contains(@class, 'third-menu') and @navname='{}']".format(last_menu_name) + self.move_to_element(first_menu) + self.move_to_element(second_menu) + self.click(third_menu) if self.wait_element(third_menu) else self.click(second_menu) diff --git a/page/GuKeYiTiHua/Public/modalBox.py b/page/GuKeYiTiHua/Public/modalBox.py new file mode 100644 index 0000000000000000000000000000000000000000..a6ac1b11e46fda6062931d821aed27f9280b81db --- /dev/null +++ b/page/GuKeYiTiHua/Public/modalBox.py @@ -0,0 +1,54 @@ +# -*- coding:utf-8 -*- +# 作者:齐振鋆 +# 日期:2023/2/14 +# 描述: +import logging +from time import sleep + +from unit.public.UI.BasePage import BasePage + +log = logging.getLogger(__name__) + + +class ModalBoxElement(BasePage): + @staticmethod + def get_search_input(title=None, placeholder=None): + if title is not None: + search_input = "//div[contains(@aria-label, '{}')]//div[@class='dictionary-search']//input".format(title) + elif placeholder is not None: + search_input = "//input[@placeholder='{}']".format(placeholder) + else: + search_input = "//div[@aria-modal='true']/div[@tabindex='-1']//input[@type='text']" + return search_input + + def search_and_choose_items(self, title=None, placeholder=None, text=None, sing_choose=True, all_choose=False): + search_input = self.get_search_input(title, placeholder) + items = [] + if type(text) is str: + items.append(text) + elif type(text) is list: + items = text + else: + log.error('查找参数格式不正确!') + for item in items: + self.type(search_input, item) + self.enter(search_input) + sleep(0.5) + if all_choose is False: + self.click_cell(title, placeholder, item) if sing_choose is True else 0 + sleep(1) + else: + all_checkbox = "//div[@aria-modal='true']/div[@tabindex='-1']//th[@colspan=1]//input[@aria-hidden='false']" + self.click(all_checkbox) + sleep(0.5) + confirm_button = "{}/ancestor::div[@class='el-overlay']//div[@class='pagination-footer']//span[text()='确定']/parent::button[@aria-disabled='false']".format( + search_input) + self.click(confirm_button) if sing_choose is True or all_choose is True else 0 + + def click_cell(self, title=None, placeholder=None, text=None): + search_input = self.get_search_input(title, placeholder) + cell = "{}/ancestor::div[@class='el-overlay']//div[contains(@class, 'tableNoDesign')]//tbody//tr[1]//div[text()='{}']".format(search_input, text) + check_box = "{}/ancestor::tr/td[1]//label".format(cell) + while "is-checked" not in self.get_attribute(check_box, 'class'): + self.click(cell) + sleep(1) diff --git a/page/GuKeYiTiHua/Public/orderDetailPage.py b/page/GuKeYiTiHua/Public/orderDetailPage.py new file mode 100644 index 0000000000000000000000000000000000000000..cd5f3328be44f13e474314653484c3705d7bc4b4 --- /dev/null +++ b/page/GuKeYiTiHua/Public/orderDetailPage.py @@ -0,0 +1,158 @@ +# -*- coding:utf-8 -*- +# 作者:齐振鋆 +# 日期:2023/2/14 +# 描述: +import logging +import pytest + +from time import sleep + +from page.GuKeYiTiHua.Public.errorMsg import ErrorMessage +from page.GuKeYiTiHua.Public.table import Table +from unit.public.UI.BasePage import BasePage + +log = logging.getLogger(__name__) + + +class OrderDetailMain(BasePage): + em = ErrorMessage() + + def choose_tap(self, tap_name): + """ + 主单信息tap页 + parameter: tap_name tap名称 + """ + log.info('切换详情tap页到:{}'.format(tap_name)) + self.click("//*[text()='{}']".format(tap_name)) + + def text_input_item(self, name, text, enter=False, get=False): + log.info('【{}】输入:{}'.format(name, text)) + text_input = "//*[string()='{}']/following-sibling::div//input".format(name) + if get is True: + return text_input + else: + self.type(text_input, text) + self.enter(text_input) if enter is True else 0 + self.em.check_message() + + def text_area_item(self, name, text): + log.info('【{}】输入:{}'.format(name, text)) + area = "//*[string()='{}']/following-sibling::div//textarea".format(name) + self.type(area, text) + + def some_click_item(self, name, end_str="i[@class='awsui-iconfont']", get=False): + log.info('点击:【{}】相关图标'.format(name)) + element = "//*[text()='{}']/following-sibling::div//{}".format(name, end_str) + return element if get is True else self.click(element) + + def drop_choose_item(self, name, item): + log.info('【{}】下拉选择:{}'.format(name, item)) + self.click("//*[string()='{}']/following-sibling::div//input".format(name)) + drop_item = "//div[@data-popper-placement='bottom-start' and @aria-hidden='false']//*[text()='{}']".format(item) + self.click(drop_item) + + def date_input_item(self, name, date_str=None): + date_input = "//*[string()='{}']/following-sibling::div//input".format(name) + date_str = self.tu.get_date_str(1) if date_str is None else date_str + log.info('【{}】输入:{}'.format(name, date_str)) + self.type(date_input, date_str) + + def get_element_text(self, name, get=False): + log.info('获取:【{}】'.format(name)) + element = "//div[text()='{}']/following-sibling::div/span".format(name) + if get is True: + return element + else: + text = self.get_ele_text(element) + log.info('{}:【{}】'.format(name, text)) + return text + + def choose_transactor(self, transactor='管理员'): + log.info('选择办理人&提交') + self.click("//div[text()='办理人']/following-sibling::div//i[contains(@class, 'awsui-iconfont-add-ico')]") + self.double_click("//span[text()='{} ']".format(transactor)) + + +class OrderDetailTable(BasePage): + table = Table() + + def position_cell(self, column_name, row_tag): + colid = self.table.get_col_id(column_name) + # 定位表格 + th_xpath = "//span[text()='{}']/ancestor::th".format(column_name) + table_div = "{}/ancestor::div[@class='form-row']".format(th_xpath) + # 定位行 + tr_xpath = "{}//span[text()='{}']/ancestor::tr[contains(@class,'vxe-body--row')]".format(table_div, row_tag) + # 定位列 + return "{}/td[@colid='{}']/div".format(tr_xpath, colid) + + def get_cell_text(self, column_name, row_tag): + log.info('获取{}的{}'.format(row_tag, column_name)) + # 获取列id + cell = self.position_cell(column_name, row_tag) + self.scroll_element(cell) + return self.get_ele_text(cell) + + def input_text(self, column_name, row_tag, text): + log.info('【{}】的【{}】输入:【{}】'.format(row_tag, column_name, text)) + # 定位单元格 + td_xpath = self.position_cell(column_name, row_tag) + self.scroll_element(td_xpath) + # 点击单元格以加载输入框 + self.click(td_xpath) + # 定位输入框 + input_xpath = "{}//input".format(td_xpath) + # 输入内容 + self.type(input_xpath, text) + # 移出光标 + th_xpath = "//span[text()='{}']/ancestor::th".format(column_name) + self.click(th_xpath) + sleep(0.5) + + def choose_item(self, column_name, row_tag, item): + log.info('【{}】的【{}】选择:【{}】'.format(row_tag, column_name, item)) + # 定位单元格 + td_xpath = self.position_cell(column_name, row_tag) + self.scroll_element(td_xpath) + # 点击单元格以加载输入框 + self.click(td_xpath) + self.click("//div[@data-popper-placement='bottom-start' and @aria-hidden='false']//*[text()='{}']".format(item)) + # 移出光标 + th_xpath = "//span[text()='{}']/ancestor::th".format(column_name) + self.click(th_xpath) + sleep(0.5) + + # 移出光标 + th_xpath = "//span[text()='{}']/ancestor::th".format(column_name) + self.click(th_xpath) + sleep(0.5) + + def get_details(self, columns): + columns = [columns] if type(columns) == str else columns if type(columns) == list else pytest.fail( + "获取单据明细详情参数类型错误") + detail_list = [] + col_list = [] + for column in columns: + colid = self.table.get_col_id(column) + col_list.append(colid) + lines = len(self.get_elements("//tr[@class='vxe-body--row']")) + log.info('当前单据有:{}行商品明细'.format(lines)) + for index in range(lines): + item = [] + for col_id in col_list: + ele = "(//td[@colid='{}' and contains(@class, 'col--left')])[{}]//*[contains(@class, 'label')]".format(col_id, index + 1) + log.info('{}:{}'.format('元素:', ele)) + txt = self.get_ele_text(ele) + log.info('{}:{}'.format('文本:', txt)) + item.append(txt) + detail_list.append(item) + return detail_list + + +class ScanTable(BasePage): + """扫码明细""" + + def check_enter_result(self, text): + """检查扫码结果""" + td = "//*[text()='扫码明细']/following-sibling::div//*[text()='{}']".format(text) + self.wait_element(td, wait_time=3) diff --git a/page/GuKeYiTiHua/Public/table.py b/page/GuKeYiTiHua/Public/table.py new file mode 100644 index 0000000000000000000000000000000000000000..51e10ce4c75a8c61631620679f4845af6e8c126c --- /dev/null +++ b/page/GuKeYiTiHua/Public/table.py @@ -0,0 +1,12 @@ +# -*- coding:utf-8 -*- +# 作者:齐振鋆 +# 日期:2023/2/17 +# 描述: +from unit.public.UI.BasePage import BasePage + + +class Table(BasePage): + def get_col_id(self, field_name): + # 获取列id + th_xpath = "//span[text()='{}']/ancestor::th[not(contains(@class, 'hidden'))]".format(field_name) + return self.get_attribute(th_xpath, 'colid') diff --git a/page/GuKeYiTiHua/__init__.py b/page/GuKeYiTiHua/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..c89a23bc087fa1d2729ac2ec04f7b947ddcf8d7e --- /dev/null +++ b/page/GuKeYiTiHua/__init__.py @@ -0,0 +1,4 @@ +# -*- coding:utf-8 -*- +# 作者:齐振鋆 +# 日期:2022/11/14 +# 描述: 骨科一体化项目 diff --git a/page/__init__.py b/page/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..9cce890cc1bc06cb6df91f2388d03e1fe063e15e --- /dev/null +++ b/page/__init__.py @@ -0,0 +1,3 @@ +# -*- coding:utf-8 -*- +# 作者:齐振鋆 +# 日期:2022/8/11 diff --git a/pytest.ini b/pytest.ini new file mode 100644 index 0000000000000000000000000000000000000000..ee312de93ca09947e4eee14c4ccd3c9d55e4eafa --- /dev/null +++ b/pytest.ini @@ -0,0 +1,22 @@ +[pytest] +python_files = test_*.py +python_classes = Test* +python_functions = test + +log_cli = 1 +log_cli_level = INFO +log_cli_format = %(asctime)s [%(levelname)s] %(message)s (%(filename)s:%(lineno)s) +log_cli_date_format=%Y-%m-%d %H:%M:%S + +markers = + incremental: "mast have" + run: "ordering" + debug: "debug" + smoke: "smoke test" + surgery: "gkyth_ssgt" + purchase: "gkyth_cg_op" + transfer: "gkyth_db" + verify: "warehouse verify" + transferin: 'test' + transferoutred:'test' +addopts = -vs --strict-markers --disable-warnings --alluredir allure-results --clean-alluredir diff --git a/pytest_run.py b/pytest_run.py new file mode 100644 index 0000000000000000000000000000000000000000..9d7487b8d605f86b590269ea9281577a87ec2b02 --- /dev/null +++ b/pytest_run.py @@ -0,0 +1,22 @@ +# -*- coding:utf-8 -*- +# 作者:齐振鋆 +# 日期:2023/3/27 +# 描述: +import os + +import pytest + +from unit.public.DataDic import DataDic + +dd = DataDic() + + +def py_run(): + tab_code = dd.get_value('tab') + if tab_code is None: + pytest.main(['cases/UI/{}/{}'.format(dd.get_value('project'), dd.get_value('module'))]) + else: + pytest.main( + ['cases/UI/{}/{}'.format(dd.get_value('project'), dd.get_value('module')), '-m', tab_code]) + # allure generate allure-results -o allure-report --clean + os.system("allure generate allure-results -o allure-report --clean") \ No newline at end of file diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000000000000000000000000000000000000..3a0e3f3cd8c6b225b48918c461445205bd4f464e Binary files /dev/null and b/requirements.txt differ diff --git a/unit/__init__.py b/unit/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..9cce890cc1bc06cb6df91f2388d03e1fe063e15e --- /dev/null +++ b/unit/__init__.py @@ -0,0 +1,3 @@ +# -*- coding:utf-8 -*- +# 作者:齐振鋆 +# 日期:2022/8/11 diff --git a/unit/project/VerifyUnit.py b/unit/project/VerifyUnit.py new file mode 100644 index 0000000000000000000000000000000000000000..41693d1bdaf6cf781dc6603e7baacdb5e38aa4b7 --- /dev/null +++ b/unit/project/VerifyUnit.py @@ -0,0 +1,50 @@ +# -*- coding:utf-8 -*- +# 作者:齐振鋆 +# 日期:2022/11/10 +# 描述: +import logging +import re + +import pytest + +from unit.public.UI.BasePage import BasePage + +log = logging.getLogger('gyxc') + + +class VerifyTool(BasePage): + verify_object = { + 're': '正则匹配', + 'in': '包含', + 'large': '大于', + 'less': '小于', + 'eq': '等于' + } + + def verify_text(self, actual_result, expect_result, verify_type, fail_msg): + """ + param: actual_result 实际结果 + param: expect_result 预期结果 + param: verify_type 校验类型[re:正则,in:包含,large:大于,less:小于,eq:等于] + param: fail_msg 失败信息 + """ + res_flag = False + if verify_type == 're': + res = re.search(expect_result, actual_result) + if res: + res_flag = True + if verify_type == 'in': + res_flag = expect_result in actual_result + if verify_type == 'large': + res_flag = actual_result > expect_result + if verify_type == 'less': + res_flag = actual_result < expect_result + if verify_type == 'eq': + res_flag = actual_result == expect_result + log.info('{} {} {},结果为:{}'.format(actual_result, self.verify_object[verify_type], expect_result, res_flag)) + if res_flag is False: + self.screenshot() + pytest.fail(fail_msg) + + def verify_attribute(self): + pass diff --git a/unit/project/__init__.py b/unit/project/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..4414c0230e8b86b5d991f8e380870565a22e835f --- /dev/null +++ b/unit/project/__init__.py @@ -0,0 +1,4 @@ +# -*- coding:utf-8 -*- +# 作者:齐振鋆 +# 日期:2023/1/9 +# 描述: diff --git a/unit/public/API/__init__.py b/unit/public/API/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..4414c0230e8b86b5d991f8e380870565a22e835f --- /dev/null +++ b/unit/public/API/__init__.py @@ -0,0 +1,4 @@ +# -*- coding:utf-8 -*- +# 作者:齐振鋆 +# 日期:2023/1/9 +# 描述: diff --git a/unit/public/BaseUnit.py b/unit/public/BaseUnit.py new file mode 100644 index 0000000000000000000000000000000000000000..7c043d7c57a17651bc1923af2c550f5c8781092a --- /dev/null +++ b/unit/public/BaseUnit.py @@ -0,0 +1,14 @@ +# -*- coding:utf-8 -*- +# 作者:齐振鋆 +# 日期:2023/1/10 +# 描述: +from random import sample + + +class BaseUnit(object): + def __init__(self): + pass + + @staticmethod + def random_string(str_len=32): + return ''.join(sample('abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890', str_len)) diff --git a/unit/public/DBUnit.py b/unit/public/DBUnit.py new file mode 100644 index 0000000000000000000000000000000000000000..cfb505271e9ebff71f0240ac96a59fd198ef0c84 --- /dev/null +++ b/unit/public/DBUnit.py @@ -0,0 +1,37 @@ +# -*- coding:utf-8 -*- +# 作者:齐振鋆 +# 日期:2023/1/10 +# 描述: +import pymysql + +from unit.public.YamlUtil import UtilYaml + + +class MysqlDataBase(object): + __init_flag = False + __instance = None + + def __new__(cls, connect_info): + cls.__instance = object.__new__(cls) if cls.__instance is None else cls.__instance + return cls.__instance + + def __init__(self, connect_info): + if not MysqlDataBase.__init_flag: + MysqlDataBase.__init_flag = True + self.__db = pymysql.connect(host=connect_info['DB_HOST'], + port=connect_info['DB_PORT'], + user=connect_info['DB_USER'], + passwd=connect_info['DB_PASSWD'], + db=connect_info['DB_NAME'], charset='utf8') + self.cursor = self.__db.cursor() + + def exec(self, sql): + self.cursor.execute(sql) + return self.cursor.fetchall() + + def commit(self): + self.__db.commit() + + def final(self): + self.cursor.close() + self.__db.close() diff --git a/unit/public/DataDic.py b/unit/public/DataDic.py new file mode 100644 index 0000000000000000000000000000000000000000..582318222219d17ac48d0b023810469430bef70f --- /dev/null +++ b/unit/public/DataDic.py @@ -0,0 +1,25 @@ +# -*- coding:utf-8 -*- +# 作者:齐振鋆 +# 日期:2022/11/9 +# 描述: + + +class DataDic(object): + __init_flag = False + __instance = None + + def __new__(cls): + if cls.__instance is None: + cls.__instance = object.__new__(cls) + return cls.__instance + + def __init__(self): + if not DataDic.__init_flag: + DataDic.__init_flag = True + self.global_data = {} + + def set_value(self, key, value): + self.global_data.setdefault(key, value) + + def get_value(self, key): + return self.global_data.get(key) diff --git a/unit/public/ExcelUnit.py b/unit/public/ExcelUnit.py new file mode 100644 index 0000000000000000000000000000000000000000..2f8c10ba0c0f332eeced68791318b0ba58b60391 --- /dev/null +++ b/unit/public/ExcelUnit.py @@ -0,0 +1,58 @@ +# -*- coding:utf-8 -*- +# 作者:齐振鋆 +# 日期:2023/1/10 +# 描述: +import warnings + +from openpyxl import load_workbook + + +class Excel(object): + __init_flag = False + __instance = None + + def __new__(cls, file, sheet_name): + cls.__instance = object.__new__(cls) if cls.__instance is None else cls.__instance + return cls.__instance + + def __init__(self, file, sheet_name): + if not Excel.__init_flag: + Excel.__init_flag = True + self.__file = file + with warnings.catch_warnings(record=True): + self.__wb = load_workbook(file) + self.__sheet = self.__wb[sheet_name] + + def excel_save(self): + self.__wb.save(self.__file) + + def excel_close(self): + self.__wb.close() + + def excel_write(self, i, j, value): + """ + excel写 + :param i: 行 + :param j: 列 + :param value: 值 + :return: + """ + item = self.__sheet.cell(row=i, column=j) + item.value = value + + def excel_get_max_line(self): + """ + 获取sheet最大行 + :return: + """ + return self.__sheet.max_row + + def excel_read(self, i, j): + """ + excel读取单元格 + :param i: 行 + :param j: 列 + :return: + """ + item = self.__sheet.cell(row=i, column=j) + return item.value diff --git a/unit/public/TimeUnit.py b/unit/public/TimeUnit.py new file mode 100644 index 0000000000000000000000000000000000000000..e9729286a3a45fa197df252163872aa0ee12e17d --- /dev/null +++ b/unit/public/TimeUnit.py @@ -0,0 +1,45 @@ +# -*- coding:utf-8 -*- +# 作者:齐振鋆 +# 日期:2022/11/12 +# 描述: +import time +from datetime import datetime, timedelta + + +class TimeUnit(object): + @staticmethod + def get_date_str(time_diff=0): + """ + param: time_diff - 时间差 + """ + now = datetime.now() + dt = now + timedelta(days=time_diff) + return dt.strftime('%Y-%m-%d') + + @staticmethod + def get_time_str(time_diff=0): + """ + param: time_diff - 时间差 + """ + now = datetime.now() + dt = now + timedelta(hours=time_diff) + return dt.strftime('%H-%M-%S') + + @staticmethod + def get_timezone(): + return int(time.time() * 1000) + + @staticmethod + def get_datetime(format_type='X'): + now = datetime.now() + dt = time.strftime('%Y-%m-%d %X') if format_type == 'X' else time.strftime( + '%Y-%m-%d') if format_type == 'D' else '{}{:0>2}{:0>2}{:0>2}{:0>2}{:0>2}{:0>3}'.format(now.year, now.month, + now.day, now.hour, + now.minute, + now.second, + int(now.microsecond / 1000)) + return dt + + @staticmethod + def str_to_datetime(date_str): + return datetime.strptime(date_str, '%Y-%m-%d %H:%M:%S') diff --git a/unit/public/UI/BasePage.py b/unit/public/UI/BasePage.py new file mode 100644 index 0000000000000000000000000000000000000000..1d175fd762478b244d20770f52e58a352382429b --- /dev/null +++ b/unit/public/UI/BasePage.py @@ -0,0 +1,433 @@ +# -*- coding:utf-8 -*- +# 作者:齐振鋆 +# 日期:2022/9/23 +import logging +import os +import time + +import allure +import pyautogui +import pytest +from selenium.common.exceptions import TimeoutException +from selenium.webdriver.common.action_chains import ActionChains +from selenium.webdriver.common.by import By +from selenium.webdriver.common.keys import Keys +from selenium.webdriver.support import expected_conditions as ec +from selenium.webdriver.support.ui import WebDriverWait + +from unit.public.DataDic import DataDic +from unit.public.TimeUnit import TimeUnit + +log = logging.getLogger(__name__) + + +class BasePage(object): + def __init__(self): + self.locator_dict = { + 'id': By.ID, + 'name': By.NAME, + 'class': By.CLASS_NAME, + 'tag': By.TAG_NAME, + 'link': By.LINK_TEXT, + 'plink': By.PARTIAL_LINK_TEXT, + 'xpath': By.XPATH, + 'css': By.CSS_SELECTOR, + } + self.dd = DataDic() + self.tu = TimeUnit() + self.try_count = 0 + + def split_locator(self, locator): + """ + 分解定位表达式,如'(xpath,//div[@class="username"])',拆分后返回'By.XPATH'和定位表达式'//div[@class="username"]' + :param locator: 定位方法+定位表达式组合字符串,如'css,.username' + :return: locator_dict[by], value:返回定位方式和定位表达式 + """ + + if type(locator) is tuple: + by = locator[0] + value = locator[1] + if by not in self.locator_dict.keys(): + raise NameError( + "wrong locator!'id','name','class','tag','link','plink','xpath','css',exp:'id,username'") + element_obj = (self.locator_dict[by], value) + else: + element_obj = (self.locator_dict['xpath'], locator) + # log.debug('操作元素:{}'.format(element_obj)) + return element_obj + + def wait_element(self, locator, wait_time=None): + """ + 等待元素出现 + :param locator: 定位方法+定位表达式组合字符串,用逗号分隔,如'(xpath,//div[@class="username"])' + :param wait_time: 等待时间 + """ + element_obj = self.split_locator(locator) + try: + wait = self.dd.get_value('element_wait_time') if wait_time is None else wait_time + WebDriverWait(self.dd.get_value('driver'), wait, 1).until(ec.visibility_of_element_located(element_obj)) + log.debug('等待元素:{}'.format(locator)) + return True + except TimeoutException: + return False + except Exception as e: + log.info(e) + self.dd.get_value('driver').quit() + + def retry_get_element(self, locator): + if self.try_count < 2: + log.debug("等待1秒后,第{}次未找到元素,继续尝试。".format(self.try_count + 1)) + time.sleep(1) + self.try_count += 1 + self.get_element(locator) + else: + log.debug("第{}次未找到元素,测试失败。".format(self.try_count + 1)) + self.fail_screenshot() + pytest.fail('元素获取失败...') + self.dd.get_value('driver').quit() + + def fail_screenshot(self): + log.debug("失败截图") + allure.attach(self.dd.get_value('driver').get_screenshot_as_png(), '{}'.format(self.tu.get_timezone()), + allure.attachment_type.PNG) + + def get_element(self, locator, retry=False): + """ + 获取一个元素 + :param locator: 定位方法+定位表达式组合字符串,用逗号分隔,如'(xpath,//div[@class="username"])' + :param retry: 重试标识 + :return: 元素可找到返回element对象,否则再次查找 + """ + # if self.wait_element(locator, sec) is True: + # log.debug('获取元素:{}'.format(locator)) + # with allure.step('获取元素:{}'.format(locator)): + element_obj = self.split_locator(locator) + try: + element = WebDriverWait(self.dd.get_value('driver'), self.dd.get_value('element_wait_time'), 1).until( + ec.visibility_of_element_located(element_obj)) + self.try_count = 0 + return element + except Exception as e: + if retry is True: + self.retry_get_element(locator) + else: + self.fail_screenshot() + raise e + + def get_element_coordinate(self, locator): + """获取元素坐标""" + return self.get_element(locator).location + + def get_elements(self, locator): + """ + 获取一组元素 + :param locator: 定位方法+定位表达式组合字符串,用逗号分隔,如'(xpath,//div[@class="username"])' + :return: elements + """ + element_objs = self.split_locator(locator) + try: + elements = WebDriverWait(self.dd.get_value('driver'), self.dd.get_value('element_wait_time'), 1).until( + ec.visibility_of_all_elements_located(element_objs)) + # log.debug('获取元素列表:{}'.format(locator)) + return elements + except Exception as e: + self.fail_screenshot() + raise e + + def open(self, url): + """ + 打开网址 + :param url: 网址连接 + """ + log.debug('打开网址:{}'.format(url)) + self.dd.get_value('driver').get(url) + + def clear(self, locator): + """ + 清除元素中的内容 + :param locator: 定位方法+定位表达式组合字符串,用逗号分隔,如'css,.username' + """ + log.debug('清空内容:{}'.format(locator)) + self.get_element(locator).clear() + + def type(self, locator, text): + """ + 在元素中输入内容 + :param locator: 定位方法+定位表达式组合字符串,用逗号分隔,如'css,.username' + :param text: 输入的内容 + """ + self.clear(locator) + log.debug('向元素 {} 输入文字:{}'.format(locator, text)) + self.get_element(locator).send_keys(text) + + def enter(self, locator): + """ + 在元素上按回车键 + :param locator: 定位方法+定位表达式组合字符串,用逗号分隔,如'css,.username' + """ + log.debug('在元素 {} 上按回车'.format(locator)) + self.get_element(locator).send_keys(Keys.ENTER) + + def click(self, locator): + """ + 在元素上单击 + :param locator: 定位方法+定位表达式组合字符串,用逗号分隔,如'css,.username' + """ + log.debug('点击元素:{}'.format(locator)) + self.get_element(locator).click() + time.sleep(1) + + def right_click(self, locator): + """ + 鼠标右击元素 + :param locator: 定位方法+定位表达式组合字符串,用逗号分隔,如'css,.username' + """ + log.debug('在元素上右击:{}'.format(locator)) + element = self.get_element(locator) + ActionChains(self.dd.get_value('driver')).context_click(element).perform() + + def double_click(self, locator): + """ + 双击元素 + :param locator: 定位方法+定位表达式组合字符串,用逗号分隔,如'css,.username' + """ + log.debug('在元素上双击:{}'.format(locator)) + element = self.get_element(locator) + ActionChains(self.dd.get_value('driver')).double_click(element).perform() + + def move_to_element(self, locator): + """ + 鼠标指向元素 + :param locator: 定位方法+定位表达式组合字符串,用逗号分隔,如'css,.username' + """ + log.debug('指向元素 {}'.format(locator)) + element = self.get_element(locator) + ActionChains(self.dd.get_value('driver')).move_to_element(element).perform() + time.sleep(2) + + def drag_and_drop(self, locator, target_locator): + """ + 拖动一个元素到另一个元素位置 + :param locator: 要拖动元素的定位 + :param target_locator: 目标位置元素的定位 + """ + log.debug('把元素 {} 拖至元素 {}'.format(locator, target_locator)) + element = self.get_element(locator) + target_element = self.get_element(target_locator) + ActionChains(self.dd.get_value('driver')).drag_and_drop(element, target_element).perform() + + def drag_and_drop_by_offset(self, locator, xoffset, yoffset): + """ + 拖动一个元素向右下移动x,y个偏移量 + :param locator: 定位方法+定位表达式组合字符串,用逗号分隔,如'css,.username' + :param xoffset: X offset to move to + :param yoffset: Y offset to move to + """ + log.debug('把元素 {} 拖至坐标:{}, {}'.format(locator, xoffset, yoffset)) + element = self.get_element(locator) + ActionChains(self.dd.get_value('driver')).drag_and_drop_by_offset(element, xoffset, yoffset).perform() + + def click_link(self, text): + """ + 按部分链接文字查找并点击链接 + :param text: 链接的部分文字 + """ + log.debug('点击连接:{}'.format(text)) + self.get_element('plink,' + text).click() + + def alert_text(self): + """ + 返回alert文本 + :return: alert文本 + """ + log.debug('获取弹框文本:{}'.format(self.dd.get_value('driver').switch_to.alert.text)) + return self.dd.get_value('driver').switch_to.alert.text + + def alert_accept(self): + """ + alert点确认 + """ + log.debug('点击弹框确认') + self.dd.get_value('driver').switch_to.alert.accept() + + def alert_dismiss(self): + """ + alert点取消 + """ + log.debug('点击弹框取消') + self.dd.get_value('driver').switch_to.alert.dismiss() + + def get_attribute(self, locator, attribute): + """ + 返回元素某属性的值 + :param locator: 定位方法+定位表达式组合字符串,用逗号分隔,如'css,.username' + :param attribute: 属性名称 + :return: 属性值 + """ + value = self.get_element(locator).get_attribute(attribute) + log.debug('获取元素 {} 的属性值 {} 为:{}'.format(locator, attribute, value)) + return value + + def get_ele_text(self, locator): + """ + 返回元素的文本 + :param locator: 定位方法+定位表达式组合字符串,用逗号分隔,如'css,.username' + :return: 元素的文本 + """ + text = self.get_element(locator).text + log.debug('获取元素 {} 的文本为:{}'.format(locator, text)) + return self.get_element(locator).text + + def is_display(self, locator): + """判断元素是否显示""" + return self.get_element(locator).is_displayed() + + def to_frame(self, locator): + """ + 进入frame + :param locator: 定位方法+定位表达式组合字符串,如'css,.username' + """ + log.debug('进入frame:{}'.format(locator)) + e = self.get_element(locator) + WebDriverWait(self.dd.get_value('driver'), DataDic().get_value('element_wait_time'), 1).until( + ec.frame_to_be_available_and_switch_to_it(e)) + + def to_parent_frame(self): + """ + 进入父frame + """ + log.info('进入父frame') + self.dd.get_value('driver').switch_to.parent_frame() + + def out_frame(self): + """ + 返回主文档 + """ + log.info('退出frame返回默认文档') + self.dd.get_value('driver').switch_to.default_content() + + def open_new_window_by_locator(self, locator): + """ + 点击元素打开新窗口,并将句柄切换到新窗口 + :param locator: 定位方法+定位表达式组合字符串,如'css,.username' + """ + log.debug('点击元素 {} 打开新窗口'.format(locator)) + self.get_element(locator).click() + self.dd.get_value('driver').switch_to.window(self.dd.get_value('driver').window_handles[-1]) + + # old_handle = self.dd.get_value('driver').current_window_handle + # self.get_element(locator).click() + # all_handles = self.dd.get_value('driver').window_handles + # for handle in all_handles: + # if handle != old_handle: + # self.dd.get_value('driver').switch_to.window(handle) + + def open_new_window_by_element(self, element): + """ + 点击元素打开新窗口,并将句柄切换到新窗口 + :param element: 元素对象 + """ + log.debug('点击元素打开新窗口') + element.click() + self.dd.get_value('driver').switch_to.window(self.dd.get_value('driver').window_handles[-1]) + + def js(self, script): + """ + 执行JavaScript + :param script:js语句 + """ + log.debug('执行JS语句:{}'.format(script)) + self.dd.get_value('driver').execute_script(script) + + @staticmethod + def zoom(z_type, times): + """放大缩小""" + for i in range(times): + pyautogui.hotkey('ctrl', z_type) + time.sleep(1) + time.sleep(3) + + def set_attribute(self, locator, attr, val): + self.dd.get_value('driver').execute_script("arguments[0].setAttribute('{}', '{}')".format(attr, val), + self.get_element(locator)) + + def scroll_element(self, locator): + """ + 拖动滚动条至目标元素 + :param locator: 定位方法+定位表达式组合字符串,如'css,.username' + """ + log.debug('滚动至元素:{}'.format(locator)) + script = "arguments[0].scrollIntoView()" + element = self.get_element(locator) + self.dd.get_value('driver').execute_script(script, element) + + def scroll_top(self): + """ + 滚动至顶部 + """ + log.debug('滚动至顶部') + self.js("window.scrollTo(document.body.scrollHeight,0)") + + def scroll_bottom(self): + """ + 滚动至底部 + """ + log.debug('滚动至底部') + self.js("window.scrollTo(0,document.body.scrollHeight)") + + def back(self): + """ + 页面后退 + """ + log.debug('页面后退') + self.dd.get_value('driver').back() + + def forward(self): + """ + 页面向前 + """ + log.debug('页面向前') + self.dd.get_value('driver').forward() + + def is_text_on_page(self, text): + """ + 返回页面源代码 + :return: 页面源代码 + """ + + if text in self.dd.get_value('driver').page_source: + log.debug('判断页面上有文本:{}'.format(text)) + return True + else: + log.debug('判断页面上没有文本:{}'.format(text)) + return False + + def refresh(self): + """ + 刷新页面 + """ + log.debug('刷新页面') + self.dd.get_value('driver').refresh() + + def screenshot(self, file_name='err@{}.png'.format(int(time.time() * 1000))): + """ + 截图,起名为:文件名-方法名-注释 + :param file_name: 文件名 + """ + log.debug(u'截图') + screen_path = DataDic().get_value('screenshot_path') # 从全局变量取截图文件夹位置 + if not os.path.exists(screen_path): + os.makedirs(screen_path) + filepath = os.path.join(screen_path, file_name) + self.dd.get_value('driver').save_screenshot(filepath) + with open(filepath, 'rb') as f: + file = f.read() + allure.attach(file, '异常截图{}'.format(self.tu.get_timezone()), attachment_type=allure.attachment_type.PNG) + + def close(self): + """ + 关闭当前页 + """ + log.debug('关闭当前Tab') + self.dd.get_value('driver').close() + self.dd.get_value('driver').switch_to.window(self.dd.get_value('driver').window_handles[0]) diff --git a/unit/public/UI/__init__.py b/unit/public/UI/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..4414c0230e8b86b5d991f8e380870565a22e835f --- /dev/null +++ b/unit/public/UI/__init__.py @@ -0,0 +1,4 @@ +# -*- coding:utf-8 -*- +# 作者:齐振鋆 +# 日期:2023/1/9 +# 描述: diff --git a/unit/public/WindowsUnit.py b/unit/public/WindowsUnit.py new file mode 100644 index 0000000000000000000000000000000000000000..19b13ca123bfc7c8ddba511fef99e5548d74cfc7 --- /dev/null +++ b/unit/public/WindowsUnit.py @@ -0,0 +1,51 @@ +# -*- coding:utf-8 -*- +# 作者:齐振鋆 +# 日期:2023/1/9 +# 描述: +import win32api +import win32con +import win32gui +import win32print + + +class WindowsCommon: + """ + windows的一些函数 + """ + + def __init__(self): + self.hdc = win32gui.GetDC(0) + + def get_screen_resolution(self): + """ + 得到屏幕的真实分辨率 + :return: + """ + sx = win32print.GetDeviceCaps(self.hdc, win32con.DESKTOPHORZRES) + sy = win32print.GetDeviceCaps(self.hdc, win32con.DESKTOPVERTRES) + return sx, sy + + @staticmethod + def get_screen_current(): + """ + 得到屏幕缩放后的分辨率 + :return: + """ + sx = win32api.GetSystemMetrics(win32con.SM_CXSCREEN) + sy = win32api.GetSystemMetrics(win32con.SM_CYSCREEN) + return sx, sy + + def get_screen_scale_rate(self): + """ + 得到当前屏幕的缩放比例 + :return: + """ + screen_x, screen_y = self.get_screen_resolution() + current_x, current_y = self.get_screen_current() + rate = round(screen_x / current_x, 2) + return rate + + +if __name__ == '__main__': + windows_common = WindowsCommon() + print(windows_common.get_screen_scale_rate()) diff --git a/unit/public/YamlUtil.py b/unit/public/YamlUtil.py new file mode 100644 index 0000000000000000000000000000000000000000..9e13ea0a8ea38691695071a91d2ef0afd0383b8e --- /dev/null +++ b/unit/public/YamlUtil.py @@ -0,0 +1,45 @@ +# -*- coding:utf-8 -*- +# 作者:齐振鋆 +# 日期:2022/11/1 +import logging + +import yaml + +log = logging.getLogger(__name__) + + +class UtilYaml(object): + def __init__(self, file_path): + self.yaml_file = file_path + + def load_yaml(self): + with open(self.yaml_file, 'r', encoding='utf-8') as f: + text = yaml.load(f, Loader=yaml.FullLoader) + return text + + def get_yaml_value(self, key_lev): + value = self.load_yaml() + for key in key_lev: + try: + value = value[key] + except KeyError: + log.info('没有key:{}'.format(key)) + value = None + except TypeError: + log.info('{}不是json字符串'.format(value)) + value = None + return value + + def write_yaml(self, data): + with open(self.yaml_file, 'a', encoding='utf-8') as f: + text = yaml.dump(data, f, allow_unicode=True) + + def clean_yaml(self): + with open(self.yaml_file, 'w', encoding='utf-8') as f: + f.truncate() + + +if __name__ == '__main__': + yaml_file = '../../data/surgeryTestData.yaml' + res = UtilYaml(yaml_file).get_yaml_value(['goods', 'val']) + print(res) diff --git a/unit/public/__init__.py b/unit/public/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..4414c0230e8b86b5d991f8e380870565a22e835f --- /dev/null +++ b/unit/public/__init__.py @@ -0,0 +1,4 @@ +# -*- coding:utf-8 -*- +# 作者:齐振鋆 +# 日期:2023/1/9 +# 描述: