157 lines
7.3 KiB
Python
157 lines
7.3 KiB
Python
# pages/calculation_page.py
|
|
from selenium.webdriver.common.by import By
|
|
from pages.base_page import BasePage
|
|
import logging
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
class CalculationPage(BasePage):
|
|
"""Page Object für die Berechnungsformulare"""
|
|
|
|
# WICHTIG: Verwende data-v-* Attribute NUR wenn sie WIRKLICH stabil sind
|
|
# Besser: Positionsbasierte Selektoren mit aussagekräftigen Parent-Elementen
|
|
|
|
FIELD_MAPPING = {
|
|
# Material-Sektion (erste Box)
|
|
"HS_CODE": (
|
|
By.XPATH,
|
|
"//div[contains(@class, 'master-data-item')][1]//div[contains(@class, 'caption-column')][text()='HS code']"
|
|
"/following-sibling::div//input[@class='input-field']"
|
|
),
|
|
"TARIFF_RATE": (
|
|
By.XPATH,
|
|
"//div[contains(@class, 'master-data-item')][1]//div[contains(@class, 'caption-column')][contains(text(), 'Tariff rate')]"
|
|
"/following-sibling::div//input[@class='input-field']"
|
|
),
|
|
|
|
# Price-Sektion (zweite Box)
|
|
"PRICE": (
|
|
By.XPATH,
|
|
"//div[contains(@class, 'master-data-item')][2]//div[contains(@class, 'caption-column')][text()='MEK_A [EUR]']"
|
|
"/following-sibling::div//input[@class='input-field']"
|
|
),
|
|
"OVERSEA_SHARE": (
|
|
By.XPATH,
|
|
"//div[contains(@class, 'master-data-item')][2]//div[contains(@class, 'caption-column')][contains(text(), 'Oversea share')]"
|
|
"/following-sibling::div//input[@class='input-field']"
|
|
),
|
|
# Handling Unit-Sektion (dritte Box)
|
|
"LENGTH": (
|
|
By.XPATH,
|
|
"//div[contains(@class, 'master-data-item')][3]//div[contains(@class, 'caption-column')][text()='HU length']"
|
|
"/following-sibling::div//input[@class='input-field']"
|
|
),
|
|
"WIDTH": (
|
|
By.XPATH,
|
|
"//div[contains(@class, 'master-data-item')][3]//div[contains(@class, 'caption-column')][text()='HU width']"
|
|
"/following-sibling::div//input[@class='input-field']"
|
|
),
|
|
"HEIGHT": (
|
|
By.XPATH,
|
|
"//div[contains(@class, 'master-data-item')][3]//div[contains(@class, 'caption-column')][text()='HU height']"
|
|
"/following-sibling::div//input[@class='input-field']"
|
|
),
|
|
"WEIGHT": (
|
|
By.XPATH,
|
|
"//div[contains(@class, 'master-data-item')][3]//div[contains(@class, 'caption-column')][text()='HU weight']"
|
|
"/following-sibling::div//input[@class='input-field']"
|
|
),
|
|
"PIECES_UNIT": (
|
|
By.XPATH,
|
|
"//div[contains(@class, 'master-data-item')][3]//div[contains(@class, 'caption-column')][text()='Pieces per HU']"
|
|
"/following-sibling::div//input[@class='input-field']"
|
|
),
|
|
|
|
# Dropdowns
|
|
"DIMENSION_UNIT": (
|
|
By.XPATH,
|
|
"//div[contains(@class, 'master-data-item')][3]//div[contains(@class, 'caption-column')][text()='Dimension unit']"
|
|
"/following-sibling::div//button[contains(@class, 'dropdown-trigger')]"
|
|
),
|
|
"WEIGHT_UNIT": (
|
|
By.XPATH,
|
|
"//div[contains(@class, 'master-data-item')][3]//div[contains(@class, 'caption-column')][text()='Weight unit']"
|
|
"/following-sibling::div//button[contains(@class, 'dropdown-trigger')]"
|
|
),
|
|
|
|
# Checkboxen
|
|
"FBA_FEE": (
|
|
By.XPATH,
|
|
"//div[contains(@class, 'master-data-item')][2]"
|
|
"//label[contains(@class, 'checkbox-item')]"
|
|
"[.//span[contains(@class, 'checkbox-label')][normalize-space(text())='']]"
|
|
),
|
|
"MIXED": (
|
|
By.XPATH,
|
|
"//label[contains(@class, 'checkbox-item')]"
|
|
"[.//span[contains(@class, 'checkbox-label')][text()='Mixable']]"
|
|
),
|
|
"STACKED": (
|
|
By.XPATH,
|
|
"//label[contains(@class, 'checkbox-item')]"
|
|
"[.//span[contains(@class, 'checkbox-label')][text()='Stackable']]"
|
|
),
|
|
}
|
|
|
|
DEST_FIELD_MAPPING = {
|
|
"NAME": (By.XPATH, "//input[@placeholder='Add new Destination ...']"),
|
|
"QUANTITY": (By.XPATH,
|
|
"//div[contains(@class, 'destination-edit-column-caption') and contains(text(), 'Annual quantity')]/following-sibling::div[1]//input[@class='input-field']")
|
|
"ROUTING": (By.XPATH,
|
|
"//input[@type='radio' and @name='model' and @value='routing']"),
|
|
"D2D": (By.XPATH,
|
|
"//input[@type='radio' and @name='model' and @value='d2d']"),
|
|
"ROUTE": (By.XPATH,
|
|
"//div[@class='destination-route-container']//div[contains(@class, 'destination-route-inner-container')][.//span[contains(text(), 'Ireland Su')] and .//span[contains(text(), 'WH ULHA')] and .//span[contains(text(), 'AB')]]")
|
|
"HANDLING_TAB": (By.XPATH, "//button[@class='tab-header' and text()='Handling & Repackaging']"),
|
|
"CUSTOM_HANDLING": (By.XPATH,
|
|
"//div[@class='destination-edit-handling-cost']//label[@class='checkbox-item']/input[@type='checkbox']"),
|
|
"REPACKING": (By.XPATH,
|
|
"//div[@class='destination-edit-column-caption' and contains(text(), 'Repackaging cost')]/following-sibling::div[@class='destination-edit-column-data'][1]//input[@class='input-field']"),
|
|
"HANDLING": (By.XPATH,
|
|
"//div[@class='destination-edit-column-caption' and contains(text(), 'Handling cost')]/following-sibling::div[@class='destination-edit-column-data'][1]//input[@class='input-field']"),
|
|
"DISPOSAL": (By.XPATH,
|
|
"//div[@class='destination-edit-column-caption' and contains(text(), 'Disposal cost')]/following-sibling::div[@class='destination-edit-column-data'][1]//input[@class='input-field']"),
|
|
}
|
|
|
|
# Buttons
|
|
CALCULATE_CLOSE_BUTTON = (By.XPATH, "//button[contains(., 'Calculate & close')]")
|
|
CLOSE_BUTTON = (By.XPATH, "//button[contains(., 'Close') and not(contains(., 'Calculate'))]")
|
|
|
|
def fill_form(self, data_dict):
|
|
"""Füllt das Formular mit Daten aus dem Excel"""
|
|
for field_name, locator in self.FIELD_MAPPING.items():
|
|
|
|
value = data_dict[field_name]
|
|
logger.info(f"Filling field: {field_name} = {value}")
|
|
|
|
try:
|
|
if field_name in ["FBA_FEE", "STACKED", "MIXED"]:
|
|
self.set_checkbox(*locator, str(value) == 'True')
|
|
|
|
elif field_name in ["DIMENSION_UNIT", "WEIGHT_UNIT"]:
|
|
self.select_dropdown_option(*locator, str(value))
|
|
|
|
else:
|
|
self.fill_input(*locator, str(value), check_existence=field_name in ["HS_CODE", "TARIFF_RATE"])
|
|
|
|
except Exception as e:
|
|
logger.error(f"Failed to fill field {field_name}: {e}")
|
|
self.driver.save_screenshot(f"failed_field_{field_name}.png")
|
|
raise Exception(f"Could not fill field '{field_name}': {e}") from e
|
|
|
|
def add_destination(self, data_dict):
|
|
self.search_and_select_autosuggest(*self.DEST_FIELD_MAPPING["NAME"], data_dict["NAME"])
|
|
|
|
def fill_destination(self, data_dict):
|
|
self.wait_for_element(*self.DEST_FIELD_MAPPING["QUANTITY"])
|
|
pass
|
|
|
|
def click_calculate_and_close(self):
|
|
"""Klickt auf 'Calculate & close' Button"""
|
|
self.click_button(*self.CALCULATE_CLOSE_BUTTON)
|
|
|
|
def click_close(self):
|
|
"""Klickt auf 'Close' Button"""
|
|
self.click_button(*self.CLOSE_BUTTON)
|