· 6 years ago · Mar 11, 2020, 08:20 AM
1# Страница настройки BillingRule
2# page object слой
3import time
4from ReconTests.common.page_objects.PageObject import PageObject, WebElementObject
5from ReconTests.page_objects.page_commons.ui_repo import SearchForm as ui
6
7
8class BillingRulePage(PageObject):
9 URL = 'Modules/Admin/BillingRulePage.aspx?QueueType=InvoiceFees'
10
11 # PAGE_LOCATOR = "//span[contains(text(), 'All facilities')]"
12 PAGE_LOCATOR = "//span[text()='ALL']"
13 SAVE_BUTTON = ".//*[@id='btnSave']"
14 ROW_NUMBER = ".//div[@class='ww-number']"
15 CLASSIFICATION = ".//div[contains(@class,'ww-drag')]"
16 ADD_ROW_BUTTON = "//button[contains(text(), 'Add Row')]"
17 LOADING_DATA_LOCATOR = "//*[contains(@class, 'loading_data')]"
18 REMOVE_ALL_ROWS_BUTTON = ".//*[@class='b-row b-row--padding-medium']/div[2]/div[1]"
19
20 LISTED_VENUE = ".//*[contains(@id, 'ListedOn')]/ul"
21 LISTED_VENUE_DROPDOWN = ".//*[contains(@id, 'ListedOn')]/ul/li/div"
22 DEFAULT_PRICE = ".//input[contains(@name, 'DefaultPrice')][1]"
23 PRICE_TYPE = ".//input[contains(@name, 'PriceType')]/../div/div/div/span"
24 PRICE_TYPE_DROPDOWN = ".//input[contains(@name, 'PriceType')]/../div/div/ul/li"
25 BASE_PRICE = ".//input[contains(@name, 'BasePrice')]/../div/div/div/span"
26 BASE_PRICE_DROPDOWN = ".//input[contains(@name, 'BasePrice')]/../div/div/ul/li/span"
27 BILLING_TYPE = ".//input[contains(@name, 'BillingType')]/../div/div/div/span"
28 BILLING_TYPE_DROPDOWN = ".//input[contains(@name, 'BillingType')]/../div/div/ul/li"
29 LABEL_INACTIVE = "//*[contains(@class, 'trg-checkbox__label')]"
30
31 SETTING_NAME_ID = "txtName"
32 USE_SECOND_CATEGORIES_ID = "UseSecondCategory"
33 CHECKBOX_INACTIVE = "Inactive---SearchForm"
34
35 def __init__(self, should_try_url_open=False):
36 super(BillingRulePage, self).__init__(self.URL, should_try_url_open)
37
38 def wait_page_open(self):
39 self.wait_element_appear(self.PAGE_LOCATOR)
40
41 def wait_loading_data(self):
42 self.wait_element_disappear(self.LOADING_DATA_LOCATOR, timeout=5)
43
44 def enter_setting_name(self, value):
45 self.input(self.locator.id_(self.SETTING_NAME_ID), value)
46
47 def select_billing_type(self, value):
48 self._set_select_value_react(
49 self.BILLING_TYPE,
50 self.BILLING_TYPE_DROPDOWN,
51 value
52 )
53 time.sleep(2.0)
54
55 def select_base_price(self, value):
56 self._set_select_value_react(
57 self.BASE_PRICE,
58 self.BASE_PRICE_DROPDOWN,
59 value
60 )
61
62 def set_default_price(self, value):
63 value = str(value)
64 self.input(self.DEFAULT_PRICE, value)
65
66 def select_price_type(self, value):
67 self._set_select_value_react(
68 self.PRICE_TYPE,
69 self.PRICE_TYPE_DROPDOWN,
70 value
71 )
72
73 def select_category2(self, category2_tree, clear_all=False):
74 if clear_all:
75 categories_elements = self.find_elements(
76 ".//*[contains(@id, '%s')]/ul/li" % ui.ids['categories2'], del_table_info=True
77 )
78 for category in categories_elements[:-1]:
79 category.find_element('./a').click()
80 self.wait_loading_data()
81 field_xpath = ".//*[contains(@id, '%s')]/ul/li/input" % ui.ids['categories2']
82 input = self.find_element(field_xpath)
83 input.click()
84 root_collapsed = ".//*[contains(@id, 'Categories2')]/div/ul/li/div[contains(@class, '%s')]/span[position()>1]" % 'b-switch_collapsed'
85 root_expanded = ".//*[contains(@id, 'Categories2')]/div/ul/li/div[contains(@class, '%s')]/span[position()>1]" % 'b-switch_expanded'
86 if not self.check_element_is_displayed(root_expanded, timeout=1):
87 self.find_element(root_collapsed).click() # expand section ALL
88
89 if len(category2_tree) == 1:
90 self._check_category2(category2_tree[0])
91 else:
92 for parent_category2 in category2_tree:
93 self._expand_category2(parent_category2, category2_tree)
94 self.click(".//div[@class='page-name']") # for closing dropdown
95
96 def _expand_category2(self, category2_name, category2_tree):
97 xpath_expanded = f"//div[@class='b-switch__row b-switch__colapsable b-switch_expanded']//span[@class='b-switch'][text() = '{category2_name}']"
98 xpath_collapsed = f"//div[@class='b-switch__row b-switch__colapsable b-switch_collapsed']//span[@class='b-switch'][text() = '{category2_name}']"
99 xpath_last_category = f"//div[@class='b-switch__row b-switch__colapsable']//span[@class='b-switch'][text() = '{category2_name}']"
100 xpath_category_select = f"//li[@class='b-search-options__list_item']//div[@class='b-switch__row b-switch__colapsable b-switch_expanded']//span[@class='b-switch'][text() = '{category2_name}']/preceding-sibling::span[contains(@class, 'b-switch_type_2')]"
101 if not self.check_element_is_displayed(xpath_expanded, timeout=1) and not self.check_element_is_displayed(xpath_collapsed, timeout=1):
102 self.find_element(xpath_last_category).click()
103 elif not self.check_element_is_displayed(xpath_expanded, timeout=1):
104 self.find_element(xpath_collapsed).click()
105 if category2_name == category2_tree[-1]:
106 self.find_element(xpath_category_select).click()
107
108 def _check_category2(self, category2_name):
109 xpath = ".//div[contains(., '%s')]/span[1]" % category2_name
110 self.find_element(xpath).click()
111
112 def select_listed_venue(self, value):
113 self._set_select_value_react(
114 self.LISTED_VENUE,
115 self.LISTED_VENUE_DROPDOWN,
116 value
117 )
118
119 def click_save(self):
120 self.click("//*[@id='btnSave']")
121 message = self.popup.get_popup_error_message()
122 assert not message, 'Error occured: %s' % message
123
124 def add_classification(self, type, value, price, price_type):
125 time.sleep(5.0)
126 self.add_row()
127 adding_classification = self.get_classifications()[-1]
128 adding_classification.add_classification(type)
129 self.click(self.ROW_NUMBER)
130 # self.close_classification_dropdown() # can fix problem with unclose dropdown
131 adding_classification.set_classification(type, value)
132 adding_classification.set_price(price, price_type)
133
134 def add_row(self):
135 self.click(self.ADD_ROW_BUTTON)
136 time.sleep(1)
137
138 def remove_all_rows(self):
139 self.click(self.REMOVE_ALL_ROWS_BUTTON)
140
141 def set_inactive(self, value):
142 if self.get_checkbox_status_script(self.CHECKBOX_INACTIVE) == value:
143 return
144 self.click(self.LABEL_INACTIVE)
145
146 def get_classifications(self):
147 classifications = []
148 index = 0
149 assert self.is_clickable(self.CLASSIFICATION), "Can't find element %s" % self.CLASSIFICATION
150 rows = self.find_elements(self.CLASSIFICATION)
151 if rows:
152 for row in rows:
153 index = index + 1
154 classifications.append(Classification(row, index))
155 return classifications
156
157 def set_use_second_categories(self):
158 self.set_checkbox(True, self.USE_SECOND_CATEGORIES_ID)
159
160 def close_classification_dropdown(self):
161 self.press_escape("//body")
162
163
164class Classification(WebElementObject):
165 PRICE = ".//*[@class='b-price__input']"
166 CLASSIFICATION_DROPDOWN = "./div/ul/li"
167 PRICE_TYPE = ".//div[text()='Price type']/following-sibling::div"
168 PRICE_TYPE_DROPDOWN = ".//div[text()='Price type']/following-sibling::div/ul/li"
169 CLASSIFICATION_TYPE_XPATH = ".//div[@class='b-label'][contains(text(), '%s')]//following-sibling::div"
170 SEARCH_OPTIONS = ".//div[text()='Search options']/following-sibling::div"
171 SEARCH_OPTIONS_DROPDOWN = ".//*[@class='b-search-options__list_item']"
172
173 REMOVE_BUTTON = ".//*[@class='ww-delete-row']"
174 CLASSIFICATIONS_LIST = ".//*[@class='b-switch__row']"
175 CLASSIFICATION_VALUE = WebElementObject.locator.class_("b-shown-option__name")
176 CLASSIFICATIONS_BUTTON = ".//*[@class='b-button b-menu__placeholder b-button--type-dropdown']"
177 SEARCH_OPTIONS_FIELDS = ".//div[@class='b-label'][contains(text(),'Search options')]/following-sibling::div[@class='b-search-options b-search-options--size-small b-shown-option__input--size-small']"
178
179 def __init__(self, web_element, index):
180 super(Classification, self).__init__(web_element)
181 self.index = index
182
183 def remove(self):
184 self.find_element(self.REMOVE_BUTTON).click()
185
186 def add_classification(self, classification):
187 self.find_element(self.CLASSIFICATIONS_BUTTON).click()
188 options = self.find_elements(self.CLASSIFICATIONS_LIST)
189 for option in options:
190 if option.text == classification:
191 option.click()
192 break
193 else:
194 self.check_for_stacktrace()
195 raise Exception("Could not add classification %s" % classification)
196
197 def set_classification(self, classification, value):
198 class_field = self.find_element(self.CLASSIFICATION_TYPE_XPATH % classification)
199 class_field.click()
200 options = class_field.find_elements(self.CLASSIFICATION_DROPDOWN)
201 for option in options:
202 if option.text == value:
203 option.click()
204 break
205 else:
206 self.check_for_stacktrace()
207 raise Exception('Could not set classification %s value %s' % (classification, value))
208
209 def set_price(self, value, type):
210 self.find_element(self.PRICE).send_keys(str(value))
211 self.find_element(self.PRICE_TYPE).click()
212 drop_down_options = self.find_elements(self.PRICE_TYPE_DROPDOWN)
213 for drop_down_option in drop_down_options:
214 if drop_down_option.text == type:
215 drop_down_option.click()
216 break
217 else:
218 self.check_for_stacktrace()
219 raise Exception("Could not set price")
220
221 def check_search_options(self):
222 result = self.get_search_options()
223 return result
224
225 def get_search_options(self):
226 POSITIVE = 'b-shown-option__name b-shown-options_state_positive'
227 NEGATIVE = 'b-shown-option__name b-shown-options_state_negative'
228
229 options = self.find_elements(".//ul/li[@class='b-shown-option b-shown-option_type_item']/span[contains(@class, 'b-shown-option__name b-shown-options_state_')]")
230 get_search_options_dict = {}
231 for option in options: # all options locators
232 option_state = option.get_attribute('class') # "b-shown-option__name b-shown-options_state_negative"
233 assert option_state in (NEGATIVE, POSITIVE), "Get search options error"
234 option_name = option.text
235 if option_state == NEGATIVE:
236 option_state = False
237 elif option_state == POSITIVE:
238 option_state = True
239 get_search_options_dict[option_name] = option_state
240 return get_search_options_dict
241
242 def set_search_options(self, search_options_dict, clear_all=False):
243 if clear_all:
244 search_options_elements = self.find_elements(
245 ".//*[contains(@id, 'Search options')]/ul/li", del_table_info=True
246 )
247 for search_option in search_options_elements[:-1]:
248 search_option.find_element('./a').click()
249 self.find_element(self.SEARCH_OPTIONS).click()
250 for key, value in search_options_dict.items():
251 assert value in (True, False), f'Unknown position of value for key {key}: {value}'
252 xpath = self.SEARCH_OPTIONS_DROPDOWN + f'//*[text()="{key}"]'
253 drop_down_option = self.find_element(xpath)
254 drop_down_option.click()
255 if value == False:
256 drop_down_option.click()
257
258 def get_classification_values(self, classification):
259 options = self.find_element(self.CLASSIFICATION_TYPE_XPATH % classification)
260 values = []
261 for option in options.find_elements_by_class_name(self.CLASSIFICATION_VALUE):
262 values.append(option.text)
263 return values
264
265
266
267# Actions слой
268
269from libs.Reporter import reporter
270from ReconTests.actions.common import Search
271from ReconTests.consts.ServiceCodes import ServiceCodes
272from ReconTests.page_objects.BillingRulePage import BillingRulePage
273from ReconTests.page_objects.BillingRules import BillingRules
274from ReconTests.api_actions import BillingCalculator_v3
275
276
277@reporter.step('Creating new billing rule')
278def fill_billing_rule(
279 billing_rule_name,
280 billing_type,
281 warehouse,
282 categories2,
283 base_price=None,
284 listed_venue=None,
285 remove_classifications=True,
286 is_inactive=False
287):
288 billing_rule = BillingRulePage(should_try_url_open=False)
289 with reporter.step('Set billing rule name "%s"' % billing_rule_name):
290 billing_rule.enter_setting_name(billing_rule_name)
291 with reporter.step('Select warehouse "%s"' % warehouse):
292 Search.fill_facilities(warehouse)
293 with reporter.step('Select category2 "%s"' % categories2):
294 billing_rule.select_category2(categories2, clear_all=True)
295 with reporter.step('Select billing type "%s"' % billing_type):
296 billing_rule.select_billing_type(billing_type)
297 if listed_venue:
298 with reporter.step('Select Listed Venue "%s"' % listed_venue):
299 billing_rule.select_listed_venue(listed_venue)
300 if base_price:
301 with reporter.step('Select base price type "%s"' % base_price):
302 billing_rule.select_base_price(base_price)
303 if remove_classifications:
304 with reporter.step('Removing classifications'):
305 classifications = billing_rule.get_classifications()
306 classifications.reverse()
307 for classification in classifications:
308 classification.remove()
309 if is_inactive:
310 with reporter.step('Make rule "%s" inactive' % billing_rule_name):
311 billing_rule.set_inactive(is_inactive)
312
313
314@reporter.step('Save billing rule')
315def save_billing_rule():
316 billing_rule = BillingRulePage()
317 billing_rule.click_save()
318 BillingRules().wait_page_open()
319
320
321@reporter.step('Delete the all rows')
322def remove_all_rows():
323 billing_rule = BillingRulePage()
324 billing_rule.remove_all_rows()
325
326
327@reporter.step('Add classifications')
328def add_multi_classification(classification_dict, price, price_type, search_options_dict=None):
329 page = BillingRulePage(False)
330 page.add_row()
331 row = page.get_classifications()[-1]
332 for class_type, class_value in classification_dict.items():
333 with reporter.step('Add classification %s, value %s' % (class_type, class_value)):
334 row.add_classification(class_type)
335 page.close_classification_dropdown() # for closing classification dropdown
336 row.set_classification(class_type, class_value)
337
338 row.set_price(price, price_type)
339 if search_options_dict:
340 row.set_search_options(search_options_dict)
341
342
343@reporter.step('Add search options')
344def add_search_options(search_options_dict=None, add_row=False):
345 page = BillingRulePage(False)
346 if add_row:
347 page.add_row()
348 row = page.get_classifications()[-1]
349 row.set_search_options(search_options_dict, clear_all=False)
350 check_search_options(search_options_dict)
351
352
353@reporter.step('Check search options')
354def check_search_options(search_options_dict):
355 page = BillingRulePage(False)
356 row = page.get_classifications()[-1]
357 found_options = row.check_search_options()
358 assert search_options_dict == found_options, "Input search_options differs from expected"
359
360
361@reporter.step('Click on button Add Row')
362def click_add_row():
363 billing_rule = BillingRulePage(should_try_url_open=False)
364 billing_rule.add_row()
365
366
367@reporter.step("Creating billing rule with API")
368def create_billing_rule_by_service(rule_name, is_inactive, feeTypeId, settings):
369 service = BillingCalculator_v3.get_service_billing_rules()
370 status_code, rule_id = service.CreateBillingRule(
371 feeTypeId=feeTypeId, inactive=is_inactive, name=rule_name, settings=settings)
372 assert status_code == ServiceCodes.OK, "Can't create billing rule"
373 return rule_id
374
375
376@reporter.step("Deleting billing rule with API")
377def delete_billing_rule_by_service(rule_id):
378 service = BillingCalculator_v3.get_service_billing_rules()
379 status_code, rule_id = service.DeleteBillingRule(id=rule_id)
380 assert status_code == ServiceCodes.OK, "Can't delete billing rule"
381 return rule_id