diff --git a/销售订单自动导入.py b/销售订单自动导入.py index f26e02b..9e84dcf 100644 --- a/销售订单自动导入.py +++ b/销售订单自动导入.py @@ -15,15 +15,15 @@ from selenium.webdriver.support import expected_conditions as EC from selenium.webdriver.support.wait import WebDriverWait from selenium.webdriver.remote.webelement import WebElement -parser = argparse.ArgumentParser(description="销售订单自动导入脚本") +parser = argparse.ArgumentParser(description="销售订单自动导入") parser.add_argument('invoices', nargs='?', default='') parser.add_argument('--xm-username', type=str, nargs='?', default='') parser.add_argument('--xm-password', type=str, nargs='?', default='') parser.add_argument('--vf-token', type=str, nargs='?', default='') 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='') parser.add_argument('-C', '--currency', type=str, nargs='?', default='USD') -parser.add_argument('-D', '--department', type=str, nargs='?', default='ULT事业部') +parser.add_argument('-D', '--department', type=str, nargs='?', default='') parser.add_argument('-T', '--duration', type=int, 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') @@ -122,29 +122,9 @@ def main(workbook=None): # 导出发票数据 invoices = root.findall('invoice') limit = len(invoices) - + data = FieldArray() print(f'[信息] 已读取发票数据 {limit} 条') - # 订单导入字段 - # 详情见 - data = FieldArray( - '订单号', - '商机号', - '订单日期', - '当前处理人', - '业绩归属部门', - '客户编号', - '币种', - '产品名称', - '产品编号', - '产品型号', - '原价', - '折扣率', - '单价', - '数量', - '产品描述', - ) - for index, invoice in enumerate(invoices): rate = index / limit number = text(invoice, 'number') @@ -164,21 +144,23 @@ def main(workbook=None): discount = float(text(position, 'discount-percent') or '0') quantity = float(text(position, 'quantity') or '0') + # 订单导入字段 + # 详情见 + data.append('订单号', number) data.append('商机号', relation) data.append('订单日期', issue_date) data.append('当前处理人', category) data.append('业绩归属部门', args.department) data.append('客户编号', client) data.append('币种', args.currency) - data.append('订单号', number) data.append('产品名称', product) data.append('产品编号', None) data.append('产品型号', code) data.append('原价', '%.2f' % price) data.append('折扣率', '%g%%' % discount) - data.append('产品描述', description) data.append('单价', '%.2f' % (price * (1 - discount / 100))) data.append('数量', '%g' % quantity) + data.append('产品描述', description) data.newrow() # 新建导入数据表 @@ -242,11 +224,11 @@ def main(workbook=None): def click(selector, parent=driver, condition=EC.element_to_be_clickable): element = locate(selector, True, parent, condition) if isinstance(selector, str) else selector - counter = lambda: int(element.get_attribute('chronometer') or 0) + counter = lambda: int(element.get_attribute('taximeter') or 0) error = False value = counter() - driver.execute_script("arguments[0].addEventListener('click', () => arguments[0].setAttribute('chronometer', arguments[1] + 1));", element, value) + driver.execute_script("arguments[0].addEventListener('click', () => arguments[0].setAttribute('taximeter', arguments[1] + 1));", element, value) for attempt in range(args.retry): try: @@ -258,17 +240,18 @@ def main(workbook=None): error = True continue # 检测点击事件 - try: WebDriverWait(driver, args.interval).until(lambda _: counter() > value) + try: + WebDriverWait(driver, args.interval).until(lambda _: counter() > value) + break except TimeoutException: continue - except: pass - break + except: break def ready(driver): try: condition = lambda x: 'nprogress-busy' in x.find_element(By.TAG_NAME, 'html').get_attribute('class') wait = WebDriverWait(driver, timeout=args.interval) wait.until(condition) - except TimeoutException: + except (TimeoutException, StaleElementReferenceException): pass wait = WebDriverWait(driver, timeout=args.timeout) wait.until_not(condition) @@ -360,53 +343,60 @@ def main(workbook=None): except: break + # 编辑订单 try: - driver.execute_script("arguments[0].click();", link) + click(link) driver.switch_to.window(driver.window_handles[3]) - # 编辑订单 click(".component-detail-frame-header .okki-space-item:nth-child(1) button") warn = False + associative = False header = locate(".order-edit-header .edit-order-no span span:nth-child(1)") number = header.text if number not in modified: # 选择商机 - try: - selected = False - relation = lookup(number, '商机号', workbook).map(lambda x: x[0]).unwrap() + for attempt in range(args.retry): + try: + relation = lookup(number, '商机号', workbook).map(lambda x: x[0]).unwrap() + match = re.match(r'O\d+', str(relation)) - if re.match(r'O\d+', str(relation)) is not None: - try: - href = locate(".layout-sidebar ul li.list-none.opportunity a").get_attribute('href') - driver.switch_to.new_window('tab') - driver.get(href) + if match is not None: + try: + href = locate(".layout-sidebar ul li.list-none.opportunity a").get_attribute('href') + driver.switch_to.new_window('tab') + driver.get(href) - # 检索商机 - locate(".new-header input").send_keys(relation) - click(".new-header .search-btn span") - ready(driver) + # 检索商机 + locate(".new-header input").send_keys(relation) + click(".new-header .search-btn span") + ready(driver) - name = locate("#business-board-drag-wrapper .business-card-wrapper > div .name-wrapper a", wait=False) - relation = name.text - finally: - driver.close() - driver.switch_to.window(driver.window_handles[3]) + name = locate("#business-board-drag-wrapper .business-card-wrapper > div .name-wrapper a", wait=False) + relation = name.text + finally: + driver.close() + driver.switch_to.window(driver.window_handles[3]) - click(".component-business-select .mm-selector-rendered") - wait = WebDriverWait(driver, timeout=args.timeout) - menu = wait.until(lambda x: x.find_element(By.CSS_SELECTOR, ".mm-outside.mm-select-dropdown")) + click(".component-business-select .mm-selector-rendered") + wait = WebDriverWait(driver, timeout=args.timeout) + menu = wait.until(lambda x: x.find_element(By.CSS_SELECTOR, ".mm-outside.mm-select-dropdown")) - for item in menu.find_elements(By.CSS_SELECTOR, "ul li span"): - driver.execute_script("arguments[0].scrollIntoView({ block: 'center' });", item) - if item.text.startswith(relation): - item.click() - selected = True - break - if not selected: - raise Exception(f'无法找到对应商机 "{relation}"') - except Exception as e: - print(f"[警告] {number}: 关联商机时发生错误:{e}") + for item in menu.find_elements(By.CSS_SELECTOR, "ul li span"): + driver.execute_script("arguments[0].scrollIntoView({ block: 'center' });", item) + if item.text.startswith(relation): + click(item) + associative = True + raise KeyboardInterrupt() + except KeyboardInterrupt: + break + except Exception as e: + print(f"[警告] {number}: 关联商机时发生错误:{e}") + warn = True + break + + if not associative: + print(f'[警告] {number}: 无法找到对应商机 "{relation}"') warn = True # 设定分页选项 10 条/页 @@ -429,11 +419,9 @@ def main(workbook=None): while index < 10: if len(ids) >= len(positions): raise KeyboardInterrupt() - # 获取项 if index >= 5: driver.execute_script("arguments[0].scrollTo(0, arguments[0].scrollHeight);", wrapper) - items = wrapper.find_elements(By.CSS_SELECTOR, ".row-item") - for item in items: + for item in wrapper.find_elements(By.CSS_SELECTOR, ".row-item"): # 订单序号 try: serial = item.find_element(By.CSS_SELECTOR, ".cell[data-cci='2'] .cell-inner div").text except: continue @@ -491,8 +479,8 @@ def main(workbook=None): try: button = locate(".okki-pagination-next button", wait=False) - if bool(button.get_attribute('disabled')): raise Exception() - driver.execute_script("arguments[0].click()", button) + if bool(button.get_attribute('disabled')): raise KeyboardInterrupt() + click(button) except: print('[信息] 已经是最后一页') break @@ -500,13 +488,13 @@ def main(workbook=None): return 0 class FieldArray[K, V]: - def __init__(self, *args: K): - self.map: dict[K, list[V]] = { name: [] for name in args } + def __init__(self): + self.map: dict[K, list[V]] = {} self.index = 0 pass - + def append(self, key: K, value: V): - array = self.map.get(key) + array = self.map.setdefault(key, []) array.insert(self.index, value) def newrow(self, padding=None):