diff --git a/销售订单自动导入.py b/销售订单自动导入.py index 665e5b4..b33c6dd 100644 --- a/销售订单自动导入.py +++ b/销售订单自动导入.py @@ -25,12 +25,14 @@ 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='') parser.add_argument('-T', '--duration', type=int, nargs='?', default=None) +parser.add_argument('-P', '--prefix', type=str, nargs='?', default='') 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('-d', '--outdir', 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('-i', '--interval', type=int, nargs='?', default=5) +parser.add_argument('-k', '--kinds', type=str, nargs='*', default=['vat', 'correction']) parser.add_argument('-r', '--retry', type=int, nargs='?', default=3) args = parser.parse_args() @@ -78,10 +80,15 @@ def main(workbook=None): datefrom = parse.quote(datefrom.strftime(format)) dateto = parse.quote(dateto.strftime(format)) + kinds = '&'.join([f'kinds%5B%5D={k}' for k in args.kinds]) + + if not args.vf_token or not args.vf_api_url: + print('[!!!!] 缺少参数:vf_token 或 vf_api_url') + return 11 while True: try: - response = requests.get(f'{args.vf_api_url}/invoices.xml?kind=vat&include_positions=true&per_page=25&page={index}&period=more&date_from={datefrom}&date_to={dateto}&search_date_type=issue_date&api_token={args.vf_token}', timeout=args.timeout) + response = requests.get(f'{args.vf_api_url}/invoices.xml?{kinds}&include_positions=true&per_page=25&page={index}&period=more&date_from={datefrom}&date_to={dateto}&search_date_type=issue_date&api_token={args.vf_token}', timeout=args.timeout) string = response.content.decode(args.encoding) data = ET.fromstring(string) except Exception as e: @@ -122,13 +129,35 @@ def main(workbook=None): # 导出发票数据 invoices = root.findall('invoice') limit = len(invoices) - data = FieldArray() print(f'[信息] 已读取发票数据 {limit} 条') + # 订单导入字段 + # 详情见 + data = FieldArray( + '订单号', + '商机号', + '订单日期', + '当前处理人', + '业绩归属部门', + '客户编号', + '币种', + '产品名称', + '产品编号', + '产品型号', + '原价', + '折扣率', + '单价', + '数量', + '产品描述', + 'AVOIR' + ) + for index, invoice in enumerate(invoices): rate = index / limit + kind = text(invoice, 'kind') number = text(invoice, 'number') issue_date = text(invoice, 'issue-date') + total = float(text(invoice, 'price-net') or '0') print(f'[信息] 正在载入 {number} ... {str(round(rate * 100)).rjust(3)} %') @@ -144,23 +173,28 @@ def main(workbook=None): discount = float(text(position, 'discount-percent') or '0') quantity = float(text(position, 'quantity') or '0') - # 订单导入字段 - # 详情见 - data.append('订单号', number) + data.append('订单号', args.prefix + number) data.append('商机号', relation) data.append('订单日期', issue_date) data.append('当前处理人', category) data.append('业绩归属部门', args.department) data.append('客户编号', client) data.append('币种', args.currency) - data.append('产品名称', product) - data.append('产品编号', None) - data.append('产品型号', code) - data.append('原价', '%.2f' % price) - data.append('折扣率', '%g%%' % discount) - data.append('单价', '%.2f' % (price * (1 - discount / 100))) - data.append('数量', '%g' % quantity) - data.append('产品描述', description) + match kind: + case 'vat': + data.append('产品名称', product) + data.append('产品型号', code) + data.append('原价', '%.2f' % price) + data.append('折扣率', '%g%%' % discount) + data.append('单价', '%.2f' % (price * (1 - discount / 100))) + data.append('数量', '%g' % quantity) + data.append('产品描述', description) + case 'correction': + data.append('产品名称', 'REMISE SPECIAL') + data.append('产品编号', '186') + data.append('单价', '0') + data.append('数量', '0') + data.append('AVOIR', '%.2f' % total) data.newrow() # 新建导入数据表 @@ -257,6 +291,10 @@ def main(workbook=None): wait.until_not(condition) return True + def keyin(element: WebElement, value): + try: element.send_keys(value) + except: driver.execute_script("arguments[0].value = arguments[1]", element, value) + if bool(args.xm_username) and bool(args.xm_password): try: locate("input.account").send_keys(args.xm_username) @@ -291,6 +329,8 @@ def main(workbook=None): status = { 'draft': 1, 'final': 6 } try: + # 选择不导入无对应产品的订单 + click(".product-import-img-box .import-img-radio:nth-child(2) .mm-radio-group > label:nth-child(2) .mm-radio-input", condition=None) # 变更状态 click(".product-import-img-box .mm-selector-rendered") click(f".mm-outside.mm-select-dropdown ul li:nth-child({status.get(args.automation)}) span") @@ -341,8 +381,8 @@ def main(workbook=None): # 设置分页选项 10 条/页 try: - click(".okki-pagination-options-size-changer") - click(".okki-select-dropdown .rc-virtual-list-holder-inner div:nth-child(1)") + click(".paas-invoice-list-frame .okki-pagination-options-size-changer") + click(".okki-select-dropdown .rc-virtual-list-holder-inner > div:nth-child(1)") ready(driver) except: print(f'[警告] 分页选项设置失败') @@ -354,19 +394,20 @@ def main(workbook=None): try: click(link) driver.switch_to.window(driver.window_handles[3]) - click(".component-detail-frame-header .okki-space-item:nth-child(1) button") + click(".sticky .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 + number = locate("h1.serial-input-title span").get_attribute('innerText') + total = lookup(number, 'AVOIR', workbook).map(lambda x: x[0]).ornone() - if number not in modified: + if number not in modified and total is None: # 选择商机 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)) + needle = str(relation).strip().lstrip('SAV-') + match = re.match(r'O\d+', needle) if match is not None: try: @@ -375,24 +416,25 @@ def main(workbook=None): driver.get(href) # 检索商机 - locate(".new-header input").send_keys(relation) + locate(".new-header input").send_keys(needle) 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 + needle = name.text.strip() finally: driver.close() driver.switch_to.window(driver.window_handles[3]) - dropdown = locate(".component-business-select .mm-selector-rendered") - click(dropdown) + dropdown = locate("#rc_select_1") + dropdown.clear() + dropdown.send_keys(needle) wait = WebDriverWait(driver, timeout=args.timeout) - menu = wait.until(lambda x: x.find_element(By.CSS_SELECTOR, ".mm-outside.mm-select-dropdown")) + menu = wait.until(lambda x: x.find_element(By.CSS_SELECTOR, ".okki-select-dropdown")) - for item in menu.find_elements(By.CSS_SELECTOR, "ul li span"): - if item.text.startswith(relation): + for item in menu.find_elements(By.CSS_SELECTOR, ".rc-virtual-list-holder-inner > div"): + if item.get_attribute('label').strip().startswith(needle): click(item) associative = True raise KeyboardInterrupt() @@ -412,14 +454,14 @@ def main(workbook=None): # 设定分页选项 10 条/页 try: click(".okki-pagination-options-size-changer") - click(".okki-select-dropdown .rc-virtual-list-holder-inner div:nth-child(1)") + click(".okki-select-dropdown .rc-virtual-list-holder-inner > div:nth-child(1)") except: print(f'[警告] {number}: 分页选项设置失败') pass # 编辑产品 try: - wrapper = locate(".order-edit-product-wrapper .row-items", condition=None) + wrapper = locate(".paas-order-product-list .row-items", condition=None) positions = lookup(number, '产品型号', workbook).unwrap() ids = [] @@ -449,26 +491,32 @@ def main(workbook=None): wait = WebDriverWait(driver, timeout=args.timeout) wait.until_not(lambda x: x.find_element(By.CSS_SELECTOR, ".okki-drawer-body").is_displayed()) - original = locate(".cell[data-cci='4'] input", parent=item, condition=None) + original = locate(".cell[data-cci='5'] input", parent=item, condition=None) if price == '--': price = original.get_attribute('value') # 填入含税成本价 - target = locate(".cell[data-cci='6'] input", parent=item, condition=None) + driver.execute_script("arguments[0].scroll(600, 0);", wrapper) + target = locate(".cell[data-cci='7'] input", parent=item, condition=None) + target.clear() target.send_keys(price) ids.append(serial) index += 1 # 下一页 - click(".summary-pagination-wrapper li.okki-pagination-next button", condition=None) + click(".text-right li.okki-pagination-next button", condition=None) except KeyboardInterrupt: pass except Exception as e: print(f"[警告] {number}: 编辑产品时发生错误:{e}") warn = True + # 删除 Avoir 费用 + try: click(".ow-box button.okki-btn-round") + except: pass + # 保存订单 ready(driver) - click(".order-edit-footer button.okki-btn-primary", condition=None) + click(".sticky.bottom-0 button.okki-btn-primary", condition=None) ready(driver) print(f"[信息] {number}: 修改完成") @@ -488,7 +536,7 @@ def main(workbook=None): return 85 try: - button = locate(".okki-pagination-next button", wait=False) + button = locate(".paas-invoice-list-frame .list-okki-footer-wrap li.okki-pagination-next button", wait=False) if bool(button.get_attribute('disabled')): raise KeyboardInterrupt() click(button) except: @@ -498,13 +546,13 @@ def main(workbook=None): return 0 class FieldArray[K, V]: - def __init__(self): - self.map: dict[K, list[V]] = {} + def __init__(self, *args: K): + self.map: dict[K, list[V]] = { name: [] for name in args } self.index = 0 pass def append(self, key: K, value: V): - array = self.map.setdefault(key, []) + array = self.map.get(key, []) array.insert(self.index, value) def newrow(self, padding=None):