fix: element locating failures
This commit is contained in:
3
.gitignore
vendored
3
.gitignore
vendored
@@ -1,4 +1,5 @@
|
|||||||
.venv/
|
.venv/
|
||||||
.vscode/
|
.vscode/
|
||||||
.workbooks/
|
.workbooks/
|
||||||
*.xlsx
|
*.xlsx
|
||||||
|
*.xml
|
||||||
163
销售订单自动导入.py
163
销售订单自动导入.py
@@ -23,11 +23,14 @@ parser.add_argument('--vf-token', type=str, required=True)
|
|||||||
parser.add_argument('--xm-web-url', type=str, nargs='?', default='https://login.xiaoman.cn/login/')
|
parser.add_argument('--xm-web-url', type=str, nargs='?', default='https://login.xiaoman.cn/login/')
|
||||||
parser.add_argument('--vf-api-url', type=str, nargs='?', default='https://ultimatron-france.vosfactures.fr/')
|
parser.add_argument('--vf-api-url', type=str, nargs='?', default='https://ultimatron-france.vosfactures.fr/')
|
||||||
parser.add_argument('--outdir', type=str, nargs='?', default='.')
|
parser.add_argument('--outdir', type=str, nargs='?', default='.')
|
||||||
|
parser.add_argument('--per-page', type=int, nargs='?', default=5)
|
||||||
|
parser.add_argument('--currency', type=str, required=True)
|
||||||
|
parser.add_argument('--department', type=str, required=True)
|
||||||
parser.add_argument('-a', '--automation', type=str, choices=['none', 'draft', 'final'], nargs='?', default='none')
|
parser.add_argument('-a', '--automation', type=str, choices=['none', 'draft', 'final'], nargs='?', default='none')
|
||||||
parser.add_argument('-e', '--encoding', type=str, nargs='?', default='utf-8')
|
parser.add_argument('-e', '--encoding', type=str, nargs='?', default='utf-8')
|
||||||
parser.add_argument('-o', '--output', type=str, nargs='?', default='')
|
parser.add_argument('-o', '--output', type=str, nargs='?', default='')
|
||||||
parser.add_argument('-t', '--timeout', type=int, nargs='?', default=60)
|
parser.add_argument('-t', '--timeout', type=int, nargs='?', default=60)
|
||||||
parser.add_argument('-i', '--interval', type=int, nargs='?', default=3)
|
parser.add_argument('-i', '--interval', type=int, nargs='?', default=5)
|
||||||
|
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
date = datetime.now()
|
date = datetime.now()
|
||||||
@@ -88,12 +91,12 @@ def main():
|
|||||||
rows = products[products.isin([value]).any(axis=1)]
|
rows = products[products.isin([value]).any(axis=1)]
|
||||||
data = rows.to_dict(orient='list')
|
data = rows.to_dict(orient='list')
|
||||||
try: return data.get(fieldname)[0]
|
try: return data.get(fieldname)[0]
|
||||||
except: return ''
|
except: return None
|
||||||
|
|
||||||
def text(element, fieldname) -> str:
|
def text(element, fieldname) -> str:
|
||||||
child = element.find(fieldname)
|
child = element.find(fieldname)
|
||||||
if bool(child.text): return child.text.strip()
|
if bool(child.text): return child.text.strip()
|
||||||
else: return ''
|
else: return None
|
||||||
|
|
||||||
clients = RelationMap(lambda x: text(x, 'client-id'))
|
clients = RelationMap(lambda x: text(x, 'client-id'))
|
||||||
invoices = RelationMap(lambda x: text(x, 'number'))
|
invoices = RelationMap(lambda x: text(x, 'number'))
|
||||||
@@ -175,6 +178,7 @@ def main():
|
|||||||
'订单号',
|
'订单号',
|
||||||
'订单日期',
|
'订单日期',
|
||||||
'当前处理人',
|
'当前处理人',
|
||||||
|
'业绩归属部门',
|
||||||
'客户编号',
|
'客户编号',
|
||||||
'币种',
|
'币种',
|
||||||
'产品名称',
|
'产品名称',
|
||||||
@@ -185,7 +189,6 @@ def main():
|
|||||||
'单价',
|
'单价',
|
||||||
'数量',
|
'数量',
|
||||||
'产品描述',
|
'产品描述',
|
||||||
'订单金额',
|
|
||||||
)
|
)
|
||||||
|
|
||||||
for invoice in invoices.map.values():
|
for invoice in invoices.map.values():
|
||||||
@@ -199,14 +202,15 @@ def main():
|
|||||||
id = lookup(code, '产品编号')
|
id = lookup(code, '产品编号')
|
||||||
product = lookup(code, '产品名称')
|
product = lookup(code, '产品名称')
|
||||||
description = lookup(code, '产品描述')
|
description = lookup(code, '产品描述')
|
||||||
price = float(text(position, 'price-net'))
|
price = float(text(position, 'price-net') or '0')
|
||||||
discount = float(text(position, 'discount-percent') or '0')
|
discount = float(text(position, 'discount-percent') or '0')
|
||||||
quantity = float(text(position, 'quantity'))
|
quantity = float(text(position, 'quantity') or '0')
|
||||||
|
|
||||||
data.append('订单日期', issue_date)
|
data.append('订单日期', issue_date)
|
||||||
data.append('当前处理人', category)
|
data.append('当前处理人', category)
|
||||||
|
data.append('业绩归属部门', args.department)
|
||||||
data.append('客户编号', client)
|
data.append('客户编号', client)
|
||||||
data.append('币种', 'USD')
|
data.append('币种', args.currency)
|
||||||
data.append('订单号', number)
|
data.append('订单号', number)
|
||||||
data.append('产品名称', product)
|
data.append('产品名称', product)
|
||||||
data.append('产品编号', id)
|
data.append('产品编号', id)
|
||||||
@@ -266,9 +270,12 @@ def main():
|
|||||||
|
|
||||||
wait = WebDriverWait(parent, timeout=args.timeout)
|
wait = WebDriverWait(parent, timeout=args.timeout)
|
||||||
element = wait.until(EC.presence_of_element_located(locator))
|
element = wait.until(EC.presence_of_element_located(locator))
|
||||||
|
# 查看元素
|
||||||
driver.execute_script("arguments[0].scrollIntoView({ block: 'center', inline: 'nearest' });", element)
|
driver.execute_script("arguments[0].scrollIntoView({ block: 'center', inline: 'nearest' });", element)
|
||||||
element = wait.until(condition(locator))
|
|
||||||
|
if condition is not None:
|
||||||
|
wait = WebDriverWait(parent, timeout=args.timeout)
|
||||||
|
element = wait.until(condition(locator))
|
||||||
|
|
||||||
return element
|
return element
|
||||||
except StaleElementReferenceException:
|
except StaleElementReferenceException:
|
||||||
@@ -326,7 +333,7 @@ def main():
|
|||||||
wait = WebDriverWait(driver, timeout=(args.timeout * 4))
|
wait = WebDriverWait(driver, timeout=(args.timeout * 4))
|
||||||
wait.until(lambda x: x.find_element(By.CSS_SELECTOR, ".img-box-result-title").get_attribute('innerText') == '导入完成')
|
wait.until(lambda x: x.find_element(By.CSS_SELECTOR, ".img-box-result-title").get_attribute('innerText') == '导入完成')
|
||||||
# 查看导入结果
|
# 查看导入结果
|
||||||
locate(".mm-notification-container .mm-icon-close", wait=False).click()
|
locate(".mm-notification-container .mm-icon-close").click()
|
||||||
locate(".product-import-img-footer button.mm-button__primary").click()
|
locate(".product-import-img-footer button.mm-button__primary").click()
|
||||||
locate(".mm-tbody table tbody tr:nth-child(1) td:nth-child(3) a").click()
|
locate(".mm-tbody table tbody tr:nth-child(1) td:nth-child(3) a").click()
|
||||||
driver.switch_to.window(driver.window_handles[2])
|
driver.switch_to.window(driver.window_handles[2])
|
||||||
@@ -334,82 +341,112 @@ def main():
|
|||||||
print(f'[!!!!] 等待订单录入时发生了错误:{e}')
|
print(f'[!!!!] 等待订单录入时发生了错误:{e}')
|
||||||
return 84
|
return 84
|
||||||
|
|
||||||
|
# 设置每页显示记录数
|
||||||
time.sleep(args.interval) #6
|
time.sleep(args.interval) #6
|
||||||
|
driver.get(driver.current_url.replace('page_size%22%3A20%2C%22', f'page_size%22%3A{args.per_page}%2C%22'))
|
||||||
|
modified = []
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
links = driver.find_elements(By.CSS_SELECTOR, ".list-frame-table .virtual-list-os-target .order-name-wrap a.jump-link")
|
# 等待页面加载
|
||||||
try:
|
wait = WebDriverWait(driver, timeout=args.timeout)
|
||||||
for link in links:
|
wait.until(lambda x: 'nprogress-busy' not in x.find_element(By.TAG_NAME, 'html').get_attribute('class'))
|
||||||
link.click()
|
time.sleep(args.interval) #7
|
||||||
|
|
||||||
|
for idx in range(args.per_page):
|
||||||
|
try:
|
||||||
|
links = driver.find_elements(By.CSS_SELECTOR, ".list-frame-table .virtual-list-os-target .row-items .cell[data-cci='1'] a")
|
||||||
|
element = links[idx]
|
||||||
|
except Exception as e:
|
||||||
|
print(f'[警告] 未找到记录: {e}')
|
||||||
|
break
|
||||||
|
|
||||||
|
try:
|
||||||
|
driver.execute_script("arguments[0].click();", element)
|
||||||
driver.switch_to.window(driver.window_handles[3])
|
driver.switch_to.window(driver.window_handles[3])
|
||||||
# 编辑订单
|
# 编辑订单
|
||||||
locate(".component-detail-frame-header .okki-space-item:nth-child(1) button").click()
|
locate(".component-detail-frame-header .okki-space-item:nth-child(1) button").click()
|
||||||
|
|
||||||
warn = False
|
warn = False
|
||||||
number = locate(".order-edit-header .edit-order-no span span:nth-child(1)").text
|
header = locate(".order-edit-header .edit-order-no span span:nth-child(1)")
|
||||||
|
number = header.text
|
||||||
|
|
||||||
invoice = invoices.map.get(number)
|
invoice = invoices.map.get(number)
|
||||||
|
positions = invoice.find('positions').findall('*')
|
||||||
|
|
||||||
# 选择商机
|
if number not in modified:
|
||||||
try:
|
# 选择商机
|
||||||
dropdown = locate(".component-business-select .mm-selector-rendered")
|
try:
|
||||||
dropdown.click()
|
index = 1
|
||||||
for item in driver.find_elements(By.CSS_SELECTOR, ".mm-outside.mm-select-dropdown ul li span"):
|
dropdown = locate(".component-business-select .mm-selector-rendered")
|
||||||
if item.text.startswith(proformas.getValueOf(invoice)['number']):
|
dropdown.click()
|
||||||
driver.execute_script("arguments[0].scrollIntoView({ block: 'center', inline: 'nearest' });", item)
|
|
||||||
item.click()
|
|
||||||
break
|
|
||||||
except Exception as e:
|
|
||||||
print(f"[警告] 发票 '{number}' 录入商机时发生错误:{e}")
|
|
||||||
warn = True
|
|
||||||
|
|
||||||
# 编辑运费
|
while True:
|
||||||
try:
|
element = locate(f".mm-outside.mm-select-dropdown ul li:nth-child({index}) span")
|
||||||
wrapper = driver.find_element(By.CSS_SELECTOR, ".order-edit-product-wrapper .virtual-list-os-target")
|
index += 1
|
||||||
driver.execute_script("arguments[0].scrollIntoView({ block: 'center', inline: 'end' });", wrapper)
|
if element.text.startswith(proformas.getValueOf(invoice)['number']):
|
||||||
|
driver.execute_script("arguments[0].scrollIntoView({ block: 'center', inline: 'nearest' });", element)
|
||||||
|
element.click()
|
||||||
|
break
|
||||||
|
except Exception as e:
|
||||||
|
print(f"[警告] {number}: 录入商机时发生错误:{e}")
|
||||||
|
warn = True
|
||||||
|
|
||||||
elements = wrapper.find_elements(By.CSS_SELECTOR, ".row-item")
|
# 编辑运费
|
||||||
elements.reverse()
|
try:
|
||||||
|
wrapper = locate(".order-edit-product-wrapper .virtual-list-os-target .row-items", condition=None)
|
||||||
|
limit = len(positions)
|
||||||
|
|
||||||
for item in elements:
|
for idx in range(limit):
|
||||||
if item.find_element(By.CSS_SELECTOR, ".product-info-group-product-name input").get_attribute('value') == 'port':
|
driver.execute_script("arguments[0].scrollTo(0, arguments[0].scrollHeight);", wrapper)
|
||||||
target = locate("input[colindex='6']", parent=item)
|
items = wrapper.find_elements(By.CSS_SELECTOR, "div.vue-recycle-scroller__item-wrapper div.vue-recycle-scroller__item-view")
|
||||||
source = locate("input[colindex='7']", parent=item)
|
driver.execute_script("arguments[0].scrollIntoView({ block: 'start', inline: 'end' });", items[idx])
|
||||||
# 填入含税成本价
|
product = locate(f".product-info-group-product-name input", parent=items[-1], condition=None)
|
||||||
price = source.get_attribute('value')
|
|
||||||
target.send_keys(price)
|
if product.get_attribute('value') == 'port':
|
||||||
break
|
# 定位元素
|
||||||
except Exception as e:
|
driver.execute_script("arguments[0].scrollTo(0, arguments[0].scrollHeight);", wrapper)
|
||||||
print(f"[警告] 发票 '{number}' 编辑运费时发生错误:{e}")
|
locate(".cell[data-cci='4'] input", parent=items[-1], condition=None)
|
||||||
warn = True
|
locate(".cell[data-cci='5'] input", parent=items[-1], condition=None)
|
||||||
|
|
||||||
|
target = locate(".cell[data-cci='6'] input", parent=items[-1], condition=None)
|
||||||
|
source = locate(".cell[data-cci='7'] input", parent=items[-1], condition=None)
|
||||||
|
# 填入含税成本价
|
||||||
|
price = source.get_attribute('value')
|
||||||
|
target.send_keys(price)
|
||||||
|
break
|
||||||
|
except Exception as e:
|
||||||
|
print(f"[警告] {number}: 编辑运费时发生错误:{e}")
|
||||||
|
warn = True
|
||||||
|
|
||||||
|
# 保存订单
|
||||||
|
button = locate(".order-edit-footer button.okki-btn-primary", condition=None)
|
||||||
|
driver.execute_script("arguments[0].click();", button)
|
||||||
|
|
||||||
|
time.sleep(args.interval) #8
|
||||||
|
print(f"[信息] {number}: 修改完成")
|
||||||
|
modified.append(number)
|
||||||
|
|
||||||
|
global success
|
||||||
|
success += 1
|
||||||
|
|
||||||
|
global warning
|
||||||
|
if warn: warning += 1
|
||||||
|
|
||||||
# 保存订单
|
|
||||||
locate(".order-edit-footer button.okki-btn-primary").click()
|
|
||||||
# 关闭标签页
|
# 关闭标签页
|
||||||
driver.close()
|
driver.close()
|
||||||
driver.switch_to.window(driver.window_handles[2])
|
driver.switch_to.window(driver.window_handles[2])
|
||||||
|
except Exception as e:
|
||||||
global success
|
print(f'[!!!!] 编辑订单时发生了错误:{e}')
|
||||||
success += 1
|
return 85
|
||||||
|
|
||||||
global warning
|
|
||||||
if warn: warning += 1
|
|
||||||
except Exception as e:
|
|
||||||
print(f'[!!!!] 编辑订单时发生了错误:{e}')
|
|
||||||
return 85
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
button = locate(".okki-pagination-next button", wait=False)
|
button = locate(".okki-pagination-next button", wait=False)
|
||||||
driver.execute_script("arguments[0].click()", button)
|
|
||||||
time.sleep(args.interval) #7
|
|
||||||
if bool(button.get_attribute('disabled')): raise Exception()
|
if bool(button.get_attribute('disabled')): raise Exception()
|
||||||
|
driver.execute_script("arguments[0].click()", button)
|
||||||
except:
|
except:
|
||||||
print('[信息] 已经是最后一页')
|
print('[信息] 已经是最后一页')
|
||||||
break
|
break
|
||||||
|
|
||||||
# 等待页面加载
|
|
||||||
wait = WebDriverWait(driver, timeout=args.timeout)
|
|
||||||
wait.until(lambda x: 'nprogress-busy' not in x.find_element(By.TAG_NAME, 'html').get_attribute('class'))
|
|
||||||
|
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
class RelationMap:
|
class RelationMap:
|
||||||
@@ -437,7 +474,7 @@ class FieldArray[K, V]:
|
|||||||
array = self.map.get(key)
|
array = self.map.get(key)
|
||||||
array.insert(self.index, value)
|
array.insert(self.index, value)
|
||||||
|
|
||||||
def newrow(self, padding=''):
|
def newrow(self, padding=None):
|
||||||
for array in self.map.values():
|
for array in self.map.values():
|
||||||
if len(array) <= self.index:
|
if len(array) <= self.index:
|
||||||
array.insert(self.index, padding)
|
array.insert(self.index, padding)
|
||||||
@@ -446,5 +483,5 @@ class FieldArray[K, V]:
|
|||||||
try: status = main()
|
try: status = main()
|
||||||
except KeyboardInterrupt: status = 145
|
except KeyboardInterrupt: status = 145
|
||||||
|
|
||||||
print(f'[信息] 已录入 {success} 个订单;收到 {warning} 条警告信息')
|
print(f'[信息] 已修改 {success} 个订单,其中包含 {warning} 条警告信息')
|
||||||
print(f'[信息] 总耗时 {datetime.now() - date}')
|
print(f'[信息] 总耗时 {datetime.now() - date}')
|
||||||
|
|||||||
Reference in New Issue
Block a user