Exemplo n.º 1
0
 def __init__(self, data_provider, output):
     LiveSessionBaseClass.__init__(self, data_provider, output)
     self._data_provider = data_provider
     self.products = self._data_provider.products
     self.common = LiveCommon(data_provider)
     self.store_fk = data_provider.store_fk
     self.current_date = datetime.now()
     self.assortment = LiveAssortmentCalculation(data_provider, False, False)
     self._own_manufacturer = self._get_own_manufacturer()
     self.result_value = self.common.get_result_values()
Exemplo n.º 2
0
 def __init__(self, data_provider, output):
     LiveSessionBaseClass.__init__(self, data_provider, output)
     self._data_provider = data_provider
     self.products = self._data_provider.products
     # self.common = Common(data_provider, is_live=True)
     self.common = LiveCommon(data_provider)
     self.store_fk = data_provider.store_fk
     self.current_date = datetime.now()
     # self.live_ps_provider = PsDataProvider(data_provider, None)
     self.assortment = LiveAssortmentCalculation(data_provider,
                                                 live_assortment=False,
                                                 wish_list=True)
     self._own_manufacturer = self._get_own_manufacturer()
     self.result_value = self.common.get_result_values()
Exemplo n.º 3
0
class CalculateKpi(LiveSessionBaseClass):
    LVL3_SESSION_RESULTS_COL = [
        'kpi_level_2_fk', 'numerator_id', 'numerator_result', 'denominator_id',
        'denominator_result', 'result', 'score'
    ]
    LVL2_SESSION_RESULTS_COL = [
        'kpi_level_2_fk', 'numerator_id', 'numerator_result', 'denominator_id',
        'denominator_result', 'result', 'target', 'score'
    ]
    SKU_LEVEL = 3
    GROUPS_LEVEL = 2

    def __init__(self, data_provider, output):
        LiveSessionBaseClass.__init__(self, data_provider, output)
        self._data_provider = data_provider
        self.products = self._data_provider.products
        self.common = LiveCommon(data_provider)
        self.store_fk = data_provider.store_fk
        self.current_date = datetime.now()
        self.assortment = LiveAssortmentCalculation(data_provider,
                                                    wish_list=False)
        self._own_manufacturer = self._get_own_manufacturer()
        self.result_value = self.common.get_result_values()

    def calculate_session_live_kpi(self):
        """
        Main function of live project
        """
        self.availability_by_assortment_calc()
        self.common.commit_live_queries_session()

    @staticmethod
    def manipulate_result_row(df):
        """
        This function manipulate the result in group level to be in the same structure
        :param df: df with column 'result'
        """
        df.loc[df.result > 1] = 1
        df.loc[:, 'result'] = round(df['result'], 2) * 100

    def availability_by_assortment_calc(self):
        """
        This function calculate availability kpis based assortment.
        Kpis of : distribution and oos .
        In addition its apply "excluded products from Actions" on the assortment store results.
        :return:
        """
        lvl3_result = self.assortment.calculate_lvl3_assortment(False)
        distribution_live = self.get_kpi_fk('Live Distribution')
        lvl3_result = lvl3_result[lvl3_result.kpi_fk_lvl2 == distribution_live]
        if lvl3_result.empty:
            Log.warning('Assortment is Empty for this session')
            return
        # self.assortment_result_base_actions(lvl3_result)  # this function will have the actions affect on lvl3_result
        lvl_2_result = self.assortment.calculate_lvl2_assortment(lvl3_result)
        lvl_2_result.rename(columns={
            'passes': 'numerator_result',
            'total': 'denominator_result',
            'kpi_fk_lvl2': 'kpi_level_2_fk'
        },
                            inplace=True)

        dist_result_lvl1, dist_results_lvl2 = self.distribution_calc(
            lvl3_result, lvl_2_result)
        self.write_results_to_db(dist_result_lvl1)
        self.write_results_to_db(dist_results_lvl2)

        oos_sku_res, oos_group_res = self.oos_calc(dist_result_lvl1,
                                                   lvl_2_result)
        self.write_results_to_db(oos_sku_res)
        self.write_results_to_db(oos_group_res)

    def distribution_calc(self, lvl3_result, lvl2_result):
        """
        This function calculate distribution kpi based on assortment results.
        :param lvl3_result: assortment results on sku level
        :param lvl2_result: assortment results on group
        :return: dist_result_lvl1 -  results on sku level , dist_results_lvl2- results in group level
        """
        dist_result_lvl1 = self.distribution_sku_level(lvl3_result.copy())
        dist_results_lvl2 = self.distribution_group_level(lvl2_result)
        return dist_result_lvl1, dist_results_lvl2

    def oos_calc(self, lvl3_result, lvl2_result):
        """
       This function calculate oos kpi based on assortment results.
       :param lvl3_result: assortment results on sku level
       :param lvl2_result: assortment results on group
       :return: oos_results_lvl1 -  results on sku level , oos_results_lvl2- results in group level
       """
        oos_results_lvl1 = self.oos_sku_level(lvl3_result)
        oos_results_lvl2 = self.oos_group_level(lvl2_result)
        return oos_results_lvl1, oos_results_lvl2

    def distribution_group_level(self, lvl_2_result):
        """
           This function create df sql results, results of distribution on group level based assortment
           :param lvl_2_result: df of assortment results in group level
           :return: df of sql results for oos assortment group level
        """
        lvl_2_result = lvl_2_result.copy()
        lvl_2_result.loc[lvl_2_result['target'] == -1, 'target'] = None
        lvl_2_result.loc[:, 'denominator_result'] = \
            lvl_2_result.apply(lambda row: row['target'] if (row['target'] >= 0 and row['group_target_date'] >
                                                             self.current_date) else row['denominator_result'], axis=1)
        lvl_2_result.loc[:,
                         'result'] = lvl_2_result.numerator_result / lvl_2_result.denominator_result
        self.manipulate_result_row(lvl_2_result)
        self._add_visit_summary_kpi_entities(lvl_2_result)
        lvl_2_result = lvl_2_result[self.LVL2_SESSION_RESULTS_COL]
        Log.info('Distribution group level is done ')
        return lvl_2_result

    def distribution_sku_level(self, lvl_3_result):
        """ This function receive df = lvl_3_result assortment with data regarding the assortment products
            This function turn the sku_assortment_results to be in a shape of db result.
            return distribution_db_results df
        """
        lvl_3_result.rename(columns={
            'product_fk': 'numerator_id',
            'assortment_group_fk': 'denominator_id',
            'in_store': 'result',
            'kpi_fk_lvl3': 'kpi_level_2_fk'
        },
                            inplace=True)
        lvl_3_result.loc[:, 'result'] = lvl_3_result.apply(
            lambda row: self.kpi_result_value(row.result), axis=1)
        lvl_3_result = lvl_3_result.assign(
            numerator_result=lvl_3_result['result'],
            denominator_result=lvl_3_result['result'],
            score=lvl_3_result['result'])
        lvl_3_result = self.filter_df_by_col(lvl_3_result, self.SKU_LEVEL)
        Log.info('Distribution sku level is done ')
        return lvl_3_result

    def oos_sku_level(self, lvl_3_result):
        """
        This function create df sql results, results of oos on sku level based assortment
        :param lvl_3_result:  df of assortment results in sku level
        :return: df of sql results for oos assortment sku level
        """
        # filter distrubution kpis
        # oos_results = lvl_3_result[lvl_3_result['result'] == 0]
        oos_results = lvl_3_result.copy()
        if oos_results.empty:
            return oos_results
        oos_result = self.kpi_result_value(0)
        oos_results = oos_results.loc[oos_results['result'] == oos_result]
        if oos_results.empty:
            return oos_results
        oos_sku_kpi = self.get_kpi_fk('Live OOS - SKU')
        oos_results.loc[:, 'kpi_level_2_fk'] = oos_sku_kpi
        oos_results = self.filter_df_by_col(oos_results, self.SKU_LEVEL)
        Log.info('oos_results_sku level Done')
        return oos_results

    def oos_group_level(self, lvl_2_result):
        """
        This function create df sql results, results of oos on group level based assortment
        :param lvl_2_result: df of assortment results in group level
        :return: df of sql results for oos assortment group level
        """
        lvl_2_result = lvl_2_result.copy()
        lvl_2_result.loc[:, 'numerator_result'] = lvl_2_result[
            'denominator_result'] - lvl_2_result['numerator_result']
        lvl_2_result.loc[:,
                         'result'] = lvl_2_result.numerator_result / lvl_2_result.denominator_result
        self.manipulate_result_row(lvl_2_result)
        oos_group_kpi = self.get_kpi_fk('Live OOS')
        lvl_2_result.loc[:, 'kpi_level_2_fk'] = oos_group_kpi
        lvl_2_result.loc[lvl_2_result['target'] == -1, 'target'] = None
        self._add_visit_summary_kpi_entities(lvl_2_result)
        lvl_2_result = self.filter_df_by_col(lvl_2_result, self.GROUPS_LEVEL)
        Log.info('oos_results group level Done')
        return lvl_2_result

    def assortment_result_base_actions(self, lvl3_res):
        """This Function will handle assortment results in sku level based on the actions made in the mobile
           all products which excluded from oos will be removed from oos list  and will be added to distribution
          :param lvl3_res : assortment results in sku level
        """
        excluded_from_oos = self.common.get_oos_exclude_values()
        if excluded_from_oos.empty:
            return
        products_excluded = excluded_from_oos.product_fk.unique()
        lvl3_res.loc[((lvl3_res['in_store'] == 0) &
                      (lvl3_res['product_fk'].isin(products_excluded))),
                     'in_store'] = 1

    def filter_df_by_col(self, df, level):
        """

        :param df: df results lvl2 / lvl3 assortment results
        :param level: sku /  group level
        :return:filtered df
        """
        if level == self.SKU_LEVEL:
            return df[self.LVL3_SESSION_RESULTS_COL]

        if level == self.GROUPS_LEVEL:
            return df[self.LVL2_SESSION_RESULTS_COL]

    def get_kpi_fk(self, kpi_type):
        """
        :param kpi_type: kpi type
        getting kpi pk from static.kpi_level_2 based on kpi 'type' name
        :return: kpi fk
        """
        kpi_by_name = self.common.get_kpi_fk_by_kpi_type(kpi_type)
        return kpi_by_name

    def _add_visit_summary_kpi_entities(self, df):
        """
        :param df :  kpi results df
        Adding attributes to kpi df for result in visit summary level .
        To db result will be visible in visit summary only when denominator will have the store pk
        and numerator will have own_manufacturer fk
        """
        df.loc[:, 'score'] = df['result']
        df.loc[:, 'denominator_id'] = self.store_fk
        df.loc[:, 'numerator_id'] = self._own_manufacturer

    def write_results_to_db(self, res_df):
        """Function receive dataframe in result structure - meaning df has all desired columns for db result.
          this function turn the df to list of dict and save it in data_provider session_results.
          """
        if res_df.empty:
            return
        # dict_results = res_df.to_dict('records')
        self.common.save_to_new_tables_sessions(res_df)

    def kpi_result_value(self, value):
        """
        :param value:  availability kpi result 0 for oos and 1 for distrbution
         Function retrieve the kpi_result_value needed for Availability KPIS
        (kpi result value match to mobile report signs) , according to the kpi result.
        :return pk of kpi_result_value
         """
        value = 'OOS' if value == 0 else 'DISTRIBUTED'
        value_info = self.result_value[self.result_value['value'] == value]
        if value_info.empty:
            return
        return value_info.pk.iloc[0]

    def _get_own_manufacturer(self):
        """ Gets own_manufacturer fk according to the assortment product list """
        if self._data_provider.own_manufacturer.empty:
            Log.warning('This project doesnt have own manufacturer ')
        return int(self._data_provider.own_manufacturer['param_value'].iloc[0])