def test_list_inventory(self, mock_get, mock_post): with open("test/data/login_response.json") as f: login_data = json.load(f) with open("test/data/list_inventory_response.json") as f: inventory_data = json.load(f) mock_post_resp = mock_response(login_data) mock_post.return_value = mock_post_resp mock_get_resp = mock_response(inventory_data) mock_get.return_value = mock_get_resp caller = Caller() self.assertEqual(caller.get_inventory_for(), inventory_data["response"]["data"])
def test_list_deposits(self, mock_get, mock_post): with open("test/data/login_response.json") as f: login_data = json.load(f) with open("test/data/list_deposits_response.json") as f: deposits_data = json.load(f) mock_post_resp = mock_response(login_data) mock_post.return_value = mock_post_resp mock_get_resp = mock_response(deposits_data) mock_get.return_value = mock_get_resp caller = Caller() self.assertEqual(caller.get_deposits_stock_for("100000"), deposits_data["response"]["data"])
def test_list_companies(self, mock_get, mock_post): with open("test/data/login_response.json") as f: login_data = json.load(f) with open("test/data/list_companies_response.json") as f: companies_data = json.load(f) mock_post_resp = mock_response(login_data) mock_post.return_value = mock_post_resp mock_get_resp = mock_response(companies_data) mock_get.return_value = mock_get_resp caller = Caller() self.assertEqual(caller.get_companies(), companies_data["response"]["data"])
def test_list_invoices(self, mock_get, mock_post): with open("test/data/login_response.json") as f: login_data = json.load(f) with open("test/data/list_invoices_response.json") as f: invoices_data = json.load(f) mock_post_resp = mock_response(login_data) mock_post.return_value = mock_post_resp mock_get_resp = mock_response(invoices_data) mock_get.return_value = mock_get_resp dates = ("2019-11-01", "2019-11-03") caller = Caller() self.assertEqual(caller.get_invoices_for(dates), invoices_data["response"]["data"])
def test_get_session_key_not_re_logs_before_duration(self, mock_post): with open("test/data/login_response.json") as f: json_data = json.load(f) mock_resp = mock_response(json_data) mock_post.return_value = mock_resp time_delta = datetime.timedelta(minutes=20) second_dt_now = datetime.datetime.now() + time_delta caller = Caller() caller.get_session_key() with patch('datetime.datetime') as mock_datetime: mock_datetime.now = Mock() mock_datetime.now.return_value = second_dt_now caller.get_session_key() self.assertEqual(mock_post.call_count, 1)
def setup_caller(self, colppy_conf): logger.info("Setting up Colppy Caller...") self.caller = Caller(colppy_conf, state=self.state) logger.info("Done.")
class DepositInventoryUpdater(): item_id_col = "idItem" deposit_name_col = "nombre" col_name_dict = { "idItem": "IdItem", "nombre": "Nombre", "codigo": "Código Item", "descripcion": "Descripción Item", "tipoItem": "Producto/Servicio", "unidadMedida": "U. Medida", "precioVenta": "Precio Venta", "costoCalculado": "Costo Calculado", "disponibilidad": "Disponible" } duplicate_cols = ["disponibilidad"] def __init__(self, state=None): if not state: state = "testing" self.state = state def paste_deposit_inventory_to_gsheet(self, deposit_name, spread_name, batch_size=100, colppy_conf=None): self.setup_caller(colppy_conf) self.open_spread(spread_name) self.set_inventory_df() self.check_and_set_deposit_name(deposit_name) self.start_or_resume_inventory_updating(batch_size) self.end_program() def setup_caller(self, colppy_conf): logger.info("Setting up Colppy Caller...") self.caller = Caller(colppy_conf, state=self.state) logger.info("Done.") def open_spread(self, spread_name): try: logger.info("Opening Google spreadsheet %s..." % spread_name) self.spread = GoogleSpread(spread_name) logger.info("Spreadsheet opened.") except: # Test error logger.exception("There was a problem opening the Google \ spreadsheet.") raise ValueError def set_inventory_df(self): self.set_updated_inventory() self.convert_inventory_data_to_df_with_header() def set_updated_inventory(self): logger.info("Setting updated inventory...") self.updated_inventory = self.caller.get_inventory_for() logger.info("Inventory set.") def convert_inventory_data_to_df_with_header(self): header = self.col_name_dict.keys() logger.info("Setting dataframe with headers: %s" % header) df = pd.DataFrame(self.updated_inventory) self.df = df.reindex(columns=header) self.df.set_index(self.item_id_col, inplace=True) logger.info("Dataframe OK.") def check_and_set_deposit_name(self, deposit_name): logger.info("Checking deposit name %s..." % deposit_name) if self.check_deposit_name(deposit_name): self.deposit_name = deposit_name logger.info("Deposit name set to %s." % deposit_name) else: raise ValueError("Wrong deposit name") def check_deposit_name(self, deposit_name): try: self.available_deposits except AttributeError: self.update_available_deposits() if deposit_name not in self.available_deposits: logger.warning("Deposit %s not in available deposits." % deposit_name, " Available deposits:") logger.warning(self.available_deposits) return False else: return True def update_available_deposits(self): logger.info("Updating available deposits...") first_item_id = self.get_first_item_id() deposits = self.get_deposits_stock_for(first_item_id) self.available_deposits = [] for deposit in deposits: self.available_deposits.append(deposit[self.deposit_name_col]) logger.info("Available deposits:") logger.info(self.available_deposits) def get_first_item_id(self): try: first_item_id = list(self.df.index)[0] except AttributeError: self.set_inventory_df() first_item_id = list(self.df.index)[0] return first_item_id def start_or_resume_inventory_updating(self, batch_size): self.setup_temp_worksheet() if self.is_new_worksheet: self.spread.update_cells("A1", "B1", ["Updating sheet...", ""]) self.update_empty_cells_with_deposit_data(batch_size) self.post_final_df() self.erease_temp_worksheet() def setup_temp_worksheet(self): logger.info("Setting up worksheet...") self.open_worksheet() self.set_data_and_worksheet_range() logger.info("Worksheet setup OK.") def open_worksheet(self): try: self.set_temp_worksheet_name() except AttributeError: logger.exception("Please set deposit name first.") raise AttributeError("No deposit name.") self.find_temp_worksheet_or_create_new() def set_temp_worksheet_name(self): now_dt = datetime.datetime.now() now_str = now_dt.strftime("%d-%m-%Y") self.temp_worksheet_name = "_".join(["temp", self.deposit_name, now_str]) def find_temp_worksheet_or_create_new(self): logger.info("Searching for worksheet %s" % self.temp_worksheet_name) temp_worksheet = self.spread.find_sheet(self.temp_worksheet_name) if temp_worksheet: self.is_new_worksheet = False logger.info("Found. Opening worksheet...") else: self.is_new_worksheet = True logger.info("Not found. Creating worksheet...") self.spread.open_sheet(self.temp_worksheet_name, create=True) logger.info("Done.") def set_data_and_worksheet_range(self): logger.info("Configuring cells ranges and setting up data to sheet...") self.start_cell = (3, 1) self.total_rows = len(self.df.index) self.last_row = self.start_cell[0] + self.total_rows if self.is_new_worksheet: self.spread.df_to_sheet(self.df.copy(), start_cell=self.start_cell) logger.info("Done.") def update_empty_cells_with_deposit_data(self, batch_size): logger.info("Updating cells with %s deposit data..." % self.deposit_name) self.pre_update_setup(batch_size) items_to_update = self.get_items_to_update() total_items_to_update = len(items_to_update) count_items = 0 for item_id in items_to_update: count_items += 1 self.try_to_update_cells_for(item_id) if ((count_items % self.batch_size == 0) or (count_items == total_items_to_update)): self.upload_batch_to_sheet() advance = (count_items / total_items_to_update) * 100 logger.info(f"{'{:.2f}'.format(advance)}% done.") logger.info("All cells updated.") def pre_update_setup(self, batch_size): self.batch_size = batch_size self.set_initial_update_range() def set_initial_update_range(self): self.set_cols_to_update() self.update_df_if_not_new() # Always set cols to update first self.set_start_row() self.set_cells_for_initial_range() def set_cols_to_update(self): empty_cols = self.get_empty_cols() self.cols_to_update = empty_cols + self.duplicate_cols logger.info("Columns to update:") logger.info(self.cols_to_update) def get_empty_cols(self): empty_cols = [] for col in self.df.columns: if self.df[col].isnull().all(): empty_cols.append(col) return empty_cols def update_df_if_not_new(self): if not self.is_new_worksheet: logger.info("Updating dataframe with spreadsheet data...") self.df = self.spread.sheet_to_df(start_row=self.start_cell[0]) logger.info("Done.") def set_start_row(self): if self.is_new_worksheet: self.start_row = self.start_cell[0] + 1 self.start_index = 0 else: self.set_first_incomplete_row_index_from_previous_update() self.batch_start_index = self.start_index def set_first_incomplete_row_index_from_previous_update(self): logger.info("Finding first incomplete row from previous update...") first_incomplete_item_id = self.get_first_incomplete_item_id_from_previous_update() self.start_index = list(self.df.index).index(first_incomplete_item_id) self.start_row = self.start_cell[0] + 1 + self.start_index logger.info("Updating from row %d..." % self.start_row) def get_first_incomplete_item_id_from_previous_update(self): first_incomplete_item_id = None for item_id in self.df.index: if self.df.loc[item_id, self.cols_to_update[0]] == "": first_incomplete_item_id = item_id logger.info("Found.") break return first_incomplete_item_id def set_cells_for_initial_range(self): self.start_batch_row = self.start_row self.last_batch_row = self.start_batch_row + self.batch_size - 1 self.update_range_dict = {} for col in self.cols_to_update: col_index = list(self.df.columns).index(col) col_num = self.start_cell[1] + col_index + 1 self.update_range_dict[col] = [[self.start_batch_row, col_num], [self.last_batch_row, col_num]] def get_items_to_update(self): items_to_update = list(self.df.index)[self.start_index:] total_items_to_update = len(items_to_update) logger.info("Total items to update: %d." % total_items_to_update) return items_to_update def try_to_update_cells_for(self, item_id): try: self.update_cells_with_data(item_id) except: # I don't know which error I could find. logger.exception("Some exception occurred for item %d" % item_id) self.update_cells_with_error(item_id) def update_cells_with_data(self, item_id): deposits = self.get_deposits_stock_for(item_id) deposit_name_row = self.get_row_for_deposit(deposits) for col in self.cols_to_update: self.df.loc[item_id, col] = deposit_name_row[col] def update_cells_with_error(self, item_id): for col in self.cols_to_update: self.df.loc[item_id, col] = "Error" def get_deposits_stock_for(self, item_id): if item_id != 0: return self.caller.get_deposits_stock_for(item_id) else: logger.error("Found 0 as item ID.") raise ValueError def get_row_for_deposit(self, deposits): deposit_df = pd.DataFrame(deposits) deposit_df.set_index(self.deposit_name_col, drop=False, inplace=True) return deposit_df.loc[self.deposit_name] def upload_batch_to_sheet(self): logger.info("Uploading batch of new data to worksheet...") self.batch_end_index = self.batch_start_index + self.batch_size for col in self.cols_to_update: batch_values = self.get_batch_values_for(col) self.update_column_with_values(col, batch_values) self.set_new_update_range_for(col) logger.info("Updating index for next batch...") self.batch_start_index += self.batch_size logger.info("Done.") logger.info("Upload ok.") def get_batch_values_for(self, col): batch_series = self.get_batch_series_for(col) logger.info("Preparing batch values...") batch_values = batch_series.fillna("").tolist() logger.info("Batch OK") logger.info("Batch values: %d" % len(batch_values)) return batch_values def get_batch_series_for(self, col): logger.info("Preparing batch for %s..." % col) if self.update_range_dict[col][1][0] > self.last_row: self.update_range_dict[col][1][0] = self.last_row logger.info("Getting batch series...") batch_series = self.df[col].iloc[self.batch_start_index:] else: logger.info("Getting batch series...") batch_series = self.df[col].iloc[self.batch_start_index: self.batch_end_index] return batch_series def update_column_with_values(self, col, batch_values): col_init = tuple(self.update_range_dict[col][0]) col_end = tuple(self.update_range_dict[col][1]) logger.info("Starting cell: %s. Last cell: %s" % (col_init, col_end)) logger.info("Updating column...") self.spread.update_cells(col_init, col_end, batch_values) logger.info("Updated.") def set_new_update_range_for(self, col): logger.info("Configuring %s range for next batch..." % col) self.update_range_dict[col][0][0] += self.batch_size self.update_range_dict[col][1][0] = (self.update_range_dict[col][0][0] + self.batch_size - 1) logger.info("Done.") def post_final_df(self): self.final_worksheet_name = self.temp_worksheet_name[5:] logger.info("Uploading final data to %s..." % self.final_worksheet_name) self.change_header_names() self.spread.df_to_sheet(self.df.copy(), index=False, start_cell=self.start_cell, sheet=self.final_worksheet_name) now_dt = datetime.datetime.now() self.spread.update_cells("A1", "B1", ["Updated on:", str(now_dt)]) logger.info("Data set to %s" % self.spread.spread_url) def change_header_names(self): self.df.rename(columns=self.col_name_dict, inplace=True) def erease_temp_worksheet(self): final_worksheet = self.spread.find_sheet(self.final_worksheet_name) if final_worksheet: self.spread.delete_sheet(self.temp_worksheet_name) def end_program(self): input("Program finished. Press Enter to exit.") sys.exit()