fix: handling invoice pagination
This commit is contained in:
15
index.html
15
index.html
@@ -152,7 +152,7 @@ function main(profiles, args) {
|
|||||||
switch (Status) {
|
switch (Status) {
|
||||||
case 'READY':
|
case 'READY':
|
||||||
let name = $('#name').value;
|
let name = $('#name').value;
|
||||||
let options = new Map();
|
let options = { profile: name };
|
||||||
|
|
||||||
for (let element of $$("input[type='checkbox']:not(.local-only)")) {
|
for (let element of $$("input[type='checkbox']:not(.local-only)")) {
|
||||||
options[element.id] = element.checked;
|
options[element.id] = element.checked;
|
||||||
@@ -166,7 +166,6 @@ function main(profiles, args) {
|
|||||||
args[element.id] = element.valueAsNumber;
|
args[element.id] = element.valueAsNumber;
|
||||||
}
|
}
|
||||||
|
|
||||||
options['profile'] = name;
|
|
||||||
await Rpc2.invoke('begin', options, args);
|
await Rpc2.invoke('begin', options, args);
|
||||||
break;
|
break;
|
||||||
case 'RUNNING':
|
case 'RUNNING':
|
||||||
@@ -225,10 +224,12 @@ function main(profiles, args) {
|
|||||||
$('#dateto').valueAsNumber = date.setHours(24 * 7) + date.getTimezoneOffset() * 60 * 1000;
|
$('#dateto').valueAsNumber = date.setHours(24 * 7) + date.getTimezoneOffset() * 60 * 1000;
|
||||||
$('#all').dispatchEvent(new Event('change'));
|
$('#all').dispatchEvent(new Event('change'));
|
||||||
|
|
||||||
|
if (Object.hasOwn(args, 'account')) {
|
||||||
let account = new String(args['account']);
|
let account = new String(args['account']);
|
||||||
let name = account.split('@', 1).pop() ?? 'unknown';
|
let name = account.split('@', 1).pop();
|
||||||
name = name.charAt(0).toLocaleUpperCase() + name.slice(1);
|
name = name.charAt(0).toLocaleUpperCase() + name.slice(1);
|
||||||
document.title += ` (${name})`;
|
document.title += ` (${name})`;
|
||||||
|
}
|
||||||
|
|
||||||
setInterval(async () => {
|
setInterval(async () => {
|
||||||
let history = await Rpc2.invoke('history');
|
let history = await Rpc2.invoke('history');
|
||||||
@@ -263,11 +264,11 @@ function main(profiles, args) {
|
|||||||
$('#numberLabel').innerText = number ?? '';
|
$('#numberLabel').innerText = number ?? '';
|
||||||
$('#progressLabel').innerText = limit ? `${task}, ${parseFloat((index / limit * 100).toFixed(2))}% (${index}/${limit})` : task;
|
$('#progressLabel').innerText = limit ? `${task}, ${parseFloat((index / limit * 100).toFixed(2))}% (${index}/${limit})` : task;
|
||||||
|
|
||||||
let uptime = await Rpc2.invoke('uptime');
|
let [t1, t2] = await Rpc2.invoke('uptime').catch(() => []);
|
||||||
$('#uptimeLabel').innerText = Temporal.Duration.from({ seconds: uptime }).round({ largestUnit: 'hours' }).toLocaleString('en', { style: 'digital' });
|
$('#uptimeLabel').innerText = Temporal.Duration.from({ seconds: t1 ?? 0 }).round({ largestUnit: 'hours' }).toLocaleString('en', { style: 'digital' });
|
||||||
|
|
||||||
if (index && limit && uptime) {
|
if (index && limit && t2) {
|
||||||
let rate = index / uptime;
|
let rate = index / t2;
|
||||||
let remaining = Math.floor((limit - index) / rate);
|
let remaining = Math.floor((limit - index) / rate);
|
||||||
$('#remainingLabel').innerHTML = Temporal.Duration.from({ seconds: remaining }).round({ largestUnit: 'hours' }).toLocaleString('en');
|
$('#remainingLabel').innerHTML = Temporal.Duration.from({ seconds: remaining }).round({ largestUnit: 'hours' }).toLocaleString('en');
|
||||||
}
|
}
|
||||||
|
|||||||
168
main.py
168
main.py
@@ -60,7 +60,8 @@ def main(driver: WebDriver, logger = logging.getLogger('main')):
|
|||||||
result = ''.join(filter(bool, [self.prefix, number, self.suffix]))
|
result = ''.join(filter(bool, [self.prefix, number, self.suffix]))
|
||||||
return result
|
return result
|
||||||
|
|
||||||
timer = Timer()
|
t1 = Timer()
|
||||||
|
t2 = Timer()
|
||||||
options = dict()
|
options = dict()
|
||||||
profiles: list[Profile] = list()
|
profiles: list[Profile] = list()
|
||||||
status = Status.IDLE
|
status = Status.IDLE
|
||||||
@@ -70,25 +71,27 @@ def main(driver: WebDriver, logger = logging.getLogger('main')):
|
|||||||
options.update(opts)
|
options.update(opts)
|
||||||
status = Status.RUNNING
|
status = Status.RUNNING
|
||||||
parameters.update(args)
|
parameters.update(args)
|
||||||
timer.clear()
|
t1.clear()
|
||||||
timer.start()
|
t1.start()
|
||||||
|
|
||||||
def pause():
|
def pause():
|
||||||
nonlocal status
|
nonlocal status
|
||||||
status = Status.STANDBY
|
status = Status.STANDBY
|
||||||
timer.pause()
|
t1.pause()
|
||||||
|
t2.pause()
|
||||||
|
|
||||||
def resume():
|
def resume():
|
||||||
nonlocal status
|
nonlocal status
|
||||||
status = Status.RUNNING
|
status = Status.RUNNING
|
||||||
driver.switch_to.window(driver.current_window_handle)
|
driver.switch_to.window(driver.current_window_handle)
|
||||||
timer.start()
|
t1.start()
|
||||||
|
t2.start()
|
||||||
|
|
||||||
jsonrpc2.define('begin', begin)
|
jsonrpc2.define('begin', begin)
|
||||||
jsonrpc2.define('pause', pause)
|
jsonrpc2.define('pause', pause)
|
||||||
jsonrpc2.define('resume', resume)
|
jsonrpc2.define('resume', resume)
|
||||||
jsonrpc2.define('status', lambda: status.name)
|
jsonrpc2.define('status', lambda: status.name)
|
||||||
jsonrpc2.define('uptime', lambda: timer.delta())
|
jsonrpc2.define('uptime', lambda: [t1.delta()])
|
||||||
|
|
||||||
try:
|
try:
|
||||||
for source, profile in zip(parameters.get('profile'), repeat(dict())):
|
for source, profile in zip(parameters.get('profile'), repeat(dict())):
|
||||||
@@ -102,7 +105,7 @@ def main(driver: WebDriver, logger = logging.getLogger('main')):
|
|||||||
return 2
|
return 2
|
||||||
|
|
||||||
try:
|
try:
|
||||||
manifest = json.dumps(profiles, default=lambda o: vars(o))
|
manifest = json.dumps(profiles, default=vars)
|
||||||
driver.get(str(Path('index.html').resolve()))
|
driver.get(str(Path('index.html').resolve()))
|
||||||
driver.execute_script(jsonrpc2.prelude(), manifest, parameters)
|
driver.execute_script(jsonrpc2.prelude(), manifest, parameters)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
@@ -196,10 +199,6 @@ def main(driver: WebDriver, logger = logging.getLogger('main')):
|
|||||||
if status == Status.RUNNING:
|
if status == Status.RUNNING:
|
||||||
break
|
break
|
||||||
|
|
||||||
def ready(driver: WebDriver):
|
|
||||||
html = driver.find_element(By.TAG_NAME, 'html')
|
|
||||||
return 'nprogress-busy' in html.get_attribute('class')
|
|
||||||
|
|
||||||
def fetch(url: str, method = 'GET', retry = parameters.get('attempts')):
|
def fetch(url: str, method = 'GET', retry = parameters.get('attempts')):
|
||||||
for attempt in range(1, retry + 1):
|
for attempt in range(1, retry + 1):
|
||||||
try:
|
try:
|
||||||
@@ -207,7 +206,7 @@ def main(driver: WebDriver, logger = logging.getLogger('main')):
|
|||||||
result = response.json()
|
result = response.json()
|
||||||
return result
|
return result
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error('Error while fetching data from %s, retrying... (%d)', url, attempt, exc_info=e)
|
logger.warning('Error while fetching data from %s, retrying... (%d)', url, attempt, exc_info=e)
|
||||||
assert attempt < retry
|
assert attempt < retry
|
||||||
|
|
||||||
flow = ActionFlow()
|
flow = ActionFlow()
|
||||||
@@ -232,15 +231,26 @@ def main(driver: WebDriver, logger = logging.getLogger('main')):
|
|||||||
status = Status.RUNNING
|
status = Status.RUNNING
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def perform(cls):
|
||||||
|
nonlocal status
|
||||||
|
statis = Status.READY
|
||||||
|
driver.switch_to.window(driver.window_handles[0])
|
||||||
|
raise cls
|
||||||
|
|
||||||
class Skip(Action):
|
class Skip(Action):
|
||||||
@classmethod
|
@classmethod
|
||||||
def prepare(cls):
|
def prepare(cls):
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def perform(cls):
|
||||||
|
driver.switch_to.window(driver.current_window_handle)
|
||||||
|
raise cls
|
||||||
|
|
||||||
flow.append(Wait)
|
flow.append(Wait)
|
||||||
flow.allow(Wait)
|
flow.allow(Wait)
|
||||||
flow.do(Wait)
|
flow.do(Wait)
|
||||||
|
|
||||||
flow.append(Cancel)
|
flow.append(Cancel)
|
||||||
flow.append(Skip)
|
flow.append(Skip)
|
||||||
|
|
||||||
@@ -248,23 +258,21 @@ def main(driver: WebDriver, logger = logging.getLogger('main')):
|
|||||||
jsonrpc2.define('cancel', lambda: flow.do(Cancel))
|
jsonrpc2.define('cancel', lambda: flow.do(Cancel))
|
||||||
jsonrpc2.define('skip', lambda: flow.do(Skip))
|
jsonrpc2.define('skip', lambda: flow.do(Skip))
|
||||||
jsonrpc2.define('progress', lambda: progress)
|
jsonrpc2.define('progress', lambda: progress)
|
||||||
|
jsonrpc2.remove('uptime')
|
||||||
|
jsonrpc2.define('uptime', lambda: [t1.delta(), t2.delta()])
|
||||||
|
|
||||||
while not wait(1):
|
while not wait(1):
|
||||||
try:
|
try:
|
||||||
progress.clear()
|
for i in range(len(driver.window_handles), 1, -1):
|
||||||
progress['task'] = 'Task 1 of 4'
|
driver.switch_to.window(driver.window_handles[i-1])
|
||||||
flow.allow(Cancel, False)
|
driver.close()
|
||||||
flow.allow(Skip, False)
|
driver.switch_to.window(driver.window_handles[i-2])
|
||||||
|
|
||||||
if options.get('all'):
|
if options.get('all'):
|
||||||
profile = profiles[selection]
|
profile = profiles[selection]
|
||||||
|
selection += 1
|
||||||
else:
|
else:
|
||||||
name = options.pop('profile')
|
name = options.pop('profile')
|
||||||
profile = next(filter(lambda o: o.name == name, profiles))
|
profile = next(filter(lambda o: o.name == name, profiles))
|
||||||
|
|
||||||
for i in range(len(driver.window_handles), 0):
|
|
||||||
driver.close()
|
|
||||||
driver.switch_to.window(driver.window_handles[i])
|
|
||||||
except (IndexError, KeyError):
|
except (IndexError, KeyError):
|
||||||
logger.info('Done')
|
logger.info('Done')
|
||||||
status = Status.READY
|
status = Status.READY
|
||||||
@@ -273,7 +281,15 @@ def main(driver: WebDriver, logger = logging.getLogger('main')):
|
|||||||
logger.error("Invalid profile '%s'", name)
|
logger.error("Invalid profile '%s'", name)
|
||||||
status = Status.STANDBY
|
status = Status.STANDBY
|
||||||
continue
|
continue
|
||||||
|
except Exception as e:
|
||||||
|
logger.error('Unexpected error', exc_info=e)
|
||||||
|
status = Status.STANDBY
|
||||||
|
continue
|
||||||
|
|
||||||
|
progress.clear()
|
||||||
|
progress['task'] = 'Task 1 of 4'
|
||||||
|
t2.clear()
|
||||||
|
t2.start()
|
||||||
base = APIURL % profile.subdomain
|
base = APIURL % profile.subdomain
|
||||||
data = list()
|
data = list()
|
||||||
df = options.get('datefrom')
|
df = options.get('datefrom')
|
||||||
@@ -284,6 +300,7 @@ def main(driver: WebDriver, logger = logging.getLogger('main')):
|
|||||||
logger.info('Profile selected: %s', profile.name)
|
logger.info('Profile selected: %s', profile.name)
|
||||||
logger.info('Date from %s to %s', df, dt)
|
logger.info('Date from %s to %s', df, dt)
|
||||||
flow.allow(Cancel)
|
flow.allow(Cancel)
|
||||||
|
flow.allow(Skip, False)
|
||||||
|
|
||||||
for page in count(1):
|
for page in count(1):
|
||||||
try:
|
try:
|
||||||
@@ -299,20 +316,20 @@ def main(driver: WebDriver, logger = logging.getLogger('main')):
|
|||||||
except Skip:
|
except Skip:
|
||||||
pass
|
pass
|
||||||
except Cancel:
|
except Cancel:
|
||||||
status = Status.READY
|
|
||||||
break
|
break
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error('Error while fetching data from %s', base, exc_info=e)
|
logger.error('Error while fetching data from %s', base, exc_info=e)
|
||||||
break
|
break
|
||||||
|
|
||||||
if len(data) == 0:
|
if len(data) == 0:
|
||||||
logger.warning('Server returned empty response')
|
logger.warning('Server returned an empty response')
|
||||||
selection += 1
|
|
||||||
continue
|
continue
|
||||||
|
|
||||||
logger.info('Initializing Workbook...')
|
logger.info('Initializing Workbook...')
|
||||||
progress['task'] = 'Task 2 of 4'
|
progress['task'] = 'Task 2 of 4'
|
||||||
progress['limit'] = len(data)
|
progress['limit'] = len(data)
|
||||||
|
t2.clear()
|
||||||
|
t2.start()
|
||||||
workbook = openpyxl.Workbook()
|
workbook = openpyxl.Workbook()
|
||||||
sheet = workbook.active
|
sheet = workbook.active
|
||||||
|
|
||||||
@@ -421,7 +438,6 @@ def main(driver: WebDriver, logger = logging.getLogger('main')):
|
|||||||
except Skip:
|
except Skip:
|
||||||
pass
|
pass
|
||||||
except Cancel:
|
except Cancel:
|
||||||
status = Status.READY
|
|
||||||
continue
|
continue
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error('Error while processing data', exc_info=e)
|
logger.error('Error while processing data', exc_info=e)
|
||||||
@@ -437,7 +453,6 @@ def main(driver: WebDriver, logger = logging.getLogger('main')):
|
|||||||
except Skip:
|
except Skip:
|
||||||
pass
|
pass
|
||||||
except Cancel:
|
except Cancel:
|
||||||
status = Status.READY
|
|
||||||
continue
|
continue
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error('Error while saving excel file', exc_info=e)
|
logger.error('Error while saving excel file', exc_info=e)
|
||||||
@@ -448,6 +463,8 @@ def main(driver: WebDriver, logger = logging.getLogger('main')):
|
|||||||
logger.info('Uploading...')
|
logger.info('Uploading...')
|
||||||
progress.clear()
|
progress.clear()
|
||||||
progress['task'] = 'Task 3 of 4'
|
progress['task'] = 'Task 3 of 4'
|
||||||
|
t2.clear()
|
||||||
|
t2.start()
|
||||||
driver.switch_to.new_window('tab')
|
driver.switch_to.new_window('tab')
|
||||||
driver.get(WEBURL % 'order/importOrder')
|
driver.get(WEBURL % 'order/importOrder')
|
||||||
|
|
||||||
@@ -474,16 +491,14 @@ def main(driver: WebDriver, logger = logging.getLogger('main')):
|
|||||||
if err.get_attribute('disabled') is None:
|
if err.get_attribute('disabled') is None:
|
||||||
logger.warning('Incomplete import detected; downloaded 1 related document')
|
logger.warning('Incomplete import detected; downloaded 1 related document')
|
||||||
err.click()
|
err.click()
|
||||||
sleep(1)
|
wait(1)
|
||||||
|
|
||||||
click(".mm-tbody table tbody tr:nth-child(1) td:nth-child(3) a")
|
click(".mm-tbody table tbody tr:nth-child(1) td:nth-child(3) a")
|
||||||
driver.switch_to.window(driver.window_handles[2])
|
wait(parameters.get('interval'))
|
||||||
until(ready)
|
|
||||||
logger.info('Done')
|
logger.info('Done')
|
||||||
except Skip:
|
except Skip:
|
||||||
pass
|
pass
|
||||||
except Cancel:
|
except Cancel:
|
||||||
status = Status.READY
|
|
||||||
continue
|
continue
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error('Error while uploading excel file', exc_info=e)
|
logger.error('Error while uploading excel file', exc_info=e)
|
||||||
@@ -513,18 +528,28 @@ def main(driver: WebDriver, logger = logging.getLogger('main')):
|
|||||||
|
|
||||||
progress['task'] = 'Task 4 of 4'
|
progress['task'] = 'Task 4 of 4'
|
||||||
progress['limit'] = len(data)
|
progress['limit'] = len(data)
|
||||||
|
t2.clear()
|
||||||
|
t2.start()
|
||||||
index = 0
|
index = 0
|
||||||
attempts = 0
|
attempts = 0
|
||||||
|
|
||||||
while index < len(data):
|
while index < len(data):
|
||||||
try:
|
try:
|
||||||
|
driver.switch_to.window(driver.window_handles[2])
|
||||||
item = data[index]
|
item = data[index]
|
||||||
|
kind = item['kind']
|
||||||
title = re.search(r'O\d+', item['title'])
|
title = re.search(r'O\d+', item['title'])
|
||||||
number = profile.format(item['number'])
|
number = profile.format(item['number'])
|
||||||
positions = item['positions']
|
positions = item['positions']
|
||||||
opportunity = None
|
opportunity = None
|
||||||
attempts += 1
|
attempts += 1
|
||||||
|
|
||||||
|
if kind != 'vat':
|
||||||
|
logger.info('[%d/%d] Skipping %s', index+1, len(data), number)
|
||||||
|
index += 1
|
||||||
|
attempts = 0
|
||||||
|
continue
|
||||||
|
|
||||||
if attempts > parameters.get('attempts'):
|
if attempts > parameters.get('attempts'):
|
||||||
logger.warning('Exhausted all allowed attempts; skipping %s', number)
|
logger.warning('Exhausted all allowed attempts; skipping %s', number)
|
||||||
index += 1
|
index += 1
|
||||||
@@ -572,7 +597,6 @@ def main(driver: WebDriver, logger = logging.getLogger('main')):
|
|||||||
attempts = 0
|
attempts = 0
|
||||||
continue
|
continue
|
||||||
except Cancel:
|
except Cancel:
|
||||||
status = Status.READY
|
|
||||||
break
|
break
|
||||||
except NoSuchElementException:
|
except NoSuchElementException:
|
||||||
logger.warning("Could not find invoice '%s'; skipping", number)
|
logger.warning("Could not find invoice '%s'; skipping", number)
|
||||||
@@ -618,7 +642,6 @@ def main(driver: WebDriver, logger = logging.getLogger('main')):
|
|||||||
attempts = 0
|
attempts = 0
|
||||||
continue
|
continue
|
||||||
except Cancel:
|
except Cancel:
|
||||||
status = Status.READY
|
|
||||||
break
|
break
|
||||||
except NoSuchElementException:
|
except NoSuchElementException:
|
||||||
logger.warning("Could not find opportunity '%s'; skipping", match)
|
logger.warning("Could not find opportunity '%s'; skipping", match)
|
||||||
@@ -648,77 +671,80 @@ def main(driver: WebDriver, logger = logging.getLogger('main')):
|
|||||||
attempts = 0
|
attempts = 0
|
||||||
continue
|
continue
|
||||||
except Cancel:
|
except Cancel:
|
||||||
status = Status.READY
|
|
||||||
break
|
break
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warning('Error while selecting opportunity; skipping', exc_info=e)
|
logger.warning('Could not select opportunity; skipping', exc_info=e)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
pagination = 10
|
||||||
click(".okki-pagination-options-size-changer")
|
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:
|
except:
|
||||||
logger.warning('Unable to setup pagination; this may cause issues')
|
logger.warning('Unable to setup pagination; this may cause issues')
|
||||||
|
|
||||||
pids = list()
|
|
||||||
wrapper = locate(".paas-order-product-list .row-items", condition=None)
|
|
||||||
class Eureka(Exception): pass
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
ids = list()
|
||||||
|
wrapper = locate(".paas-order-product-list .row-items", condition=None)
|
||||||
|
|
||||||
for page in count(1):
|
for page in count(1):
|
||||||
|
hits = 0
|
||||||
|
iteration = 0
|
||||||
flow.react()
|
flow.react()
|
||||||
tail = next(reversed(pids), None)
|
|
||||||
|
while hits < pagination and iteration < parameters.get('attempts'):
|
||||||
|
iteration += 1
|
||||||
|
height = int(wrapper.get_attribute('clientHeight')) if iteration > 1 else 0
|
||||||
driver.execute_script("arguments[0].scrollIntoView({ block: 'center' });", wrapper)
|
driver.execute_script("arguments[0].scrollIntoView({ block: 'center' });", wrapper)
|
||||||
driver.execute_script("arguments[0].scrollTo(arguments[1], arguments[2]);", wrapper, 0, 0)
|
driver.execute_script("arguments[0].scrollTo(0, arguments[1]);", wrapper, height)
|
||||||
|
rows = wrapper.find_elements(By.CSS_SELECTOR, ".row-item")
|
||||||
|
|
||||||
for item in wrapper.find_elements(By.CSS_SELECTOR, ".row-item"):
|
for row in reversed(rows) if iteration > 1 else rows:
|
||||||
if len(pids) >= len(positions): raise Eureka()
|
|
||||||
div = item.find_element(By.CSS_SELECTOR, ".cell[data-cci='2'] .cell-inner div")
|
|
||||||
|
|
||||||
if (serial := int(div.text)) and serial not in pids:
|
|
||||||
flow.react()
|
flow.react()
|
||||||
base = (serial - tail) if tail is not None else index
|
|
||||||
height = int(item.get_attribute('clientHeight'))
|
|
||||||
offset = (base - 1) * height
|
|
||||||
driver.execute_script("arguments[0].scrollTo(arguments[1], arguments[2]);", wrapper, 0, offset)
|
|
||||||
#span = item.find_element(By.CSS_SELECTOR, ".cell[data-cci='3'] .product-info-group-product-info:nth-child(3) span")
|
|
||||||
#code = span.text[6:]
|
|
||||||
|
|
||||||
value = item.find_element(By.CSS_SELECTOR, ".cell[data-cci='4'] input").get_attribute('value')
|
|
||||||
driver.execute_script("arguments[0].scrollIntoView({ block: 'center' });", wrapper)
|
driver.execute_script("arguments[0].scrollIntoView({ block: 'center' });", wrapper)
|
||||||
driver.execute_script("arguments[0].scroll(arguments[1], arguments[2]);", wrapper, 400, offset)
|
driver.execute_script("arguments[0].scrollTo(0, arguments[1]);", wrapper, height)
|
||||||
|
serial = row.text.split('\n', 1)[0].strip()
|
||||||
|
if not serial or serial in ids: continue
|
||||||
|
|
||||||
|
driver.execute_script("arguments[0].scrollIntoView({ block: 'center' });", row)
|
||||||
|
driver.execute_script("arguments[0].scrollIntoView({ block: 'center' });", wrapper)
|
||||||
|
value = row.find_element(By.CSS_SELECTOR, ".cell[data-cci='4'] input").get_attribute('value')
|
||||||
|
driver.execute_script("arguments[0].scroll(400, 0);", wrapper)
|
||||||
|
driver.execute_script("arguments[0].scrollIntoView({ block: 'center' });", row)
|
||||||
|
driver.execute_script("arguments[0].scrollIntoView({ block: 'center' });", wrapper)
|
||||||
wait(parameters.get('interval'))
|
wait(parameters.get('interval'))
|
||||||
target = item.find_element(By.CSS_SELECTOR, ".cell[data-cci='6'] input")
|
target = row.find_element(By.CSS_SELECTOR, ".cell[data-cci='6'] input")
|
||||||
|
|
||||||
if (target.get_attribute('value') == '0'):
|
if (target.get_attribute('value') == '0'):
|
||||||
target.send_keys(Keys.BACKSPACE)
|
target.send_keys(Keys.BACKSPACE)
|
||||||
target.send_keys(value)
|
target.send_keys(value)
|
||||||
|
|
||||||
pids.append(serial)
|
ids.append(serial)
|
||||||
|
hits += 1
|
||||||
|
|
||||||
|
if len(ids) >= len(positions): break
|
||||||
button = locate(".text-right li.okki-pagination-next button", condition=None)
|
button = locate(".text-right li.okki-pagination-next button", condition=None)
|
||||||
if button.get_attribute('disabled') is not None and len(pids) < len(positions):
|
if button.get_attribute('disabled') is not None and len(ids) < len(positions):
|
||||||
raise Exception('Product list imcomplete; expected %d, got %d', len(pids), len(positions))
|
raise Exception('Product list imcomplete; expected %d, got %d' % (len(positions), len(ids)))
|
||||||
flow.react()
|
flow.react()
|
||||||
click(button)
|
click(button)
|
||||||
except Eureka:
|
|
||||||
pass
|
|
||||||
except Skip:
|
except Skip:
|
||||||
index += 1
|
index += 1
|
||||||
attempts = 0
|
attempts = 0
|
||||||
continue
|
continue
|
||||||
except Cancel:
|
except Cancel:
|
||||||
status = Status.READY
|
|
||||||
break
|
break
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error('Error while modifying invoice', exc_info=e)
|
logger.error('Error while modifying invoice', exc_info=e)
|
||||||
status = Status.STANDBY
|
status = Status.STANDBY
|
||||||
continue
|
continue
|
||||||
|
|
||||||
try: click(".ow-box button.okki-btn-round", wait=False)
|
try:
|
||||||
except: pass
|
click(".ow-box button.okki-btn-round", wait=False)
|
||||||
|
wait(parameters.get('interval'))
|
||||||
|
except Exception as e:
|
||||||
|
logger.warning('Unable to unset additional fees; skipping', exc_info=e)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
wait(parameters.get('interval'))
|
|
||||||
flow.react()
|
flow.react()
|
||||||
flow.allow(Cancel, False)
|
flow.allow(Cancel, False)
|
||||||
flow.allow(Skip, False)
|
flow.allow(Skip, False)
|
||||||
@@ -727,7 +753,6 @@ def main(driver: WebDriver, logger = logging.getLogger('main')):
|
|||||||
except Skip:
|
except Skip:
|
||||||
pass
|
pass
|
||||||
except Cancel:
|
except Cancel:
|
||||||
status = Status.READY
|
|
||||||
break
|
break
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error('Error while saving document', exc_info=e)
|
logger.error('Error while saving document', exc_info=e)
|
||||||
@@ -735,7 +760,6 @@ def main(driver: WebDriver, logger = logging.getLogger('main')):
|
|||||||
continue
|
continue
|
||||||
finally:
|
finally:
|
||||||
driver.close()
|
driver.close()
|
||||||
driver.switch_to.window(driver.window_handles[2])
|
|
||||||
|
|
||||||
index += 1
|
index += 1
|
||||||
attempts = 0
|
attempts = 0
|
||||||
@@ -743,16 +767,6 @@ def main(driver: WebDriver, logger = logging.getLogger('main')):
|
|||||||
logger.error('Unexpected error', exc_info=e)
|
logger.error('Unexpected error', exc_info=e)
|
||||||
status = Status.STANDBY
|
status = Status.STANDBY
|
||||||
|
|
||||||
try:
|
|
||||||
driver.close()
|
|
||||||
driver.switch_to.window(driver.window_handles[1])
|
|
||||||
driver.close()
|
|
||||||
driver.switch_to.window(driver.window_handles[0])
|
|
||||||
selection += 1
|
|
||||||
except Exception as e:
|
|
||||||
logger.error('Unexpected error', exc_info=e)
|
|
||||||
status = Status.STANDBY
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
try:
|
try:
|
||||||
logging.basicConfig(level=logging.INFO, format="[%(asctime)s] [%(levelname)s] [%(name)s] %(message)s", datefmt="%Y-%m-%d %H:%M")
|
logging.basicConfig(level=logging.INFO, format="[%(asctime)s] [%(levelname)s] [%(name)s] %(message)s", datefmt="%Y-%m-%d %H:%M")
|
||||||
|
|||||||
Reference in New Issue
Block a user