class HeroAvailabilityKpi(UnifiedCalculationsScript): def __init__(self, data_provider, config_params=None, **kwargs): super(HeroAvailabilityKpi, self).__init__(data_provider, config_params=config_params, **kwargs) self.util = PepsicoUtil(None, data_provider) def calculate(self): lvl3_ass_res_df = self.dependencies_data distribution_kpi_fk = self.util.common.get_kpi_fk_by_kpi_type( self.util.HERO_SKU_AVAILABILITY) if not lvl3_ass_res_df.empty: location_type_fk = self.util.scif[self.util.scif[ScifConsts.LOCATION_TYPE] == 'Primary Shelf'] \ [ScifConsts.LOCATION_TYPE_FK].values[0] total_skus_in_ass = len(lvl3_ass_res_df) in_store_skus = len( self.util.get_available_hero_sku_list(self.dependencies_data)) res = np.divide(float(in_store_skus), float(total_skus_in_ass)) * 100 score = 100 if res >= 100 else 0 self.write_to_db_result(fk=distribution_kpi_fk, numerator_id=self.util.own_manuf_fk, numerator_result=in_store_skus, result=res, denominator_id=self.util.store_id, denominator_result=total_skus_in_ass, score=score, context_id=location_type_fk) self.util.add_kpi_result_to_kpi_results_df([ distribution_kpi_fk, self.util.own_manuf_fk, self.util.store_id, res, score, None ]) def kpi_type(self): pass
class SosVsTargetHeroSkuKpi(UnifiedCalculationsScript): def __init__(self, data_provider, config_params=None, **kwargs): super(SosVsTargetHeroSkuKpi, self).__init__(data_provider, config_params=config_params, **kwargs) self.util = PepsicoUtil(None, data_provider) def kpi_type(self): pass def calculate(self): self.util.filtered_scif, self.util.filtered_matches = \ self.util.commontools.set_filtered_scif_and_matches_for_specific_kpi(self.util.filtered_scif, self.util.filtered_matches, self.util.HERO_SKU_SOS) self.calculate_hero_sku_sos() self.util.reset_filtered_scif_and_matches_to_exclusion_all_state() def calculate_hero_sku_sos(self): kpi_fk = self.util.common.get_kpi_fk_by_kpi_type(self.util.HERO_SKU_SOS) filtered_scif = self.util.filtered_scif location_type_fk = self.util.all_templates[self.util.all_templates[ScifConsts.LOCATION_TYPE] == 'Primary Shelf'] \ [ScifConsts.LOCATION_TYPE_FK].values[0] if (not filtered_scif.empty) and (not self.dependencies_data.empty): category_df = filtered_scif.groupby([ScifConsts.CATEGORY_FK], as_index=False).agg({'updated_gross_length': np.sum}) category_df.rename(columns={'updated_gross_length': 'cat_len'}, inplace=True) av_hero_list = self.util.get_available_hero_sku_list(self.dependencies_data) filtered_scif = filtered_scif[filtered_scif[ScifConsts.PRODUCT_FK].isin(av_hero_list)] unav_hero_list = self.util.get_unavailable_hero_sku_list(self.dependencies_data) unav_hero_df = self.util.all_products[self.util.all_products[ScifConsts.PRODUCT_FK].isin(unav_hero_list)] \ [[ScifConsts.PRODUCT_FK, ScifConsts.CATEGORY_FK]] unav_hero_df['updated_gross_length'] = 0 filtered_scif = filtered_scif.append(unav_hero_df) hero_cat_df = filtered_scif.groupby([ScifConsts.PRODUCT_FK, ScifConsts.CATEGORY_FK], as_index=False).agg({'updated_gross_length': np.sum}) hero_cat_df = hero_cat_df.merge(category_df, on=ScifConsts.CATEGORY_FK, how='left') hero_cat_df['cat_len'] = hero_cat_df['cat_len'].fillna(0) hero_cat_df['sos'] = hero_cat_df.apply(self.calculate_sos, axis=1) for i, row in hero_cat_df.iterrows(): self.write_to_db_result(fk=kpi_fk, numerator_id=row[ScifConsts.PRODUCT_FK], numerator_result=row['updated_gross_length'], denominator_id=row[ScifConsts.CATEGORY_FK], denominator_result=row['cat_len'], result=row['sos'], context_id=location_type_fk) self.util.add_kpi_result_to_kpi_results_df( [kpi_fk, row[ScifConsts.PRODUCT_FK], row[ScifConsts.CATEGORY_FK], row['sos'], None, None]) @staticmethod def calculate_sos(row): sos = 0 if row['cat_len'] != 0: sos = float(row['updated_gross_length']) / row['cat_len'] * 100 return sos
class ShareOfAssortmentByHeroTypeKpi(UnifiedCalculationsScript): def __init__(self, data_provider, config_params=None, **kwargs): super(ShareOfAssortmentByHeroTypeKpi, self).__init__(data_provider, config_params=config_params, **kwargs) self.util = PepsicoUtil(None, data_provider) def calculate(self): lvl3_ass_res_df = self.dependencies_data if not lvl3_ass_res_df.empty: kpi_fk = self.util.common.get_kpi_fk_by_kpi_type( self.util.SHARE_OF_ASSORTMENT_BY_HERO_TYPE) in_store_skus = len( self.util.get_available_hero_sku_list( self.dependencies_data)) # total recognized location_type_fk = self.util.all_templates[self.util.all_templates[ScifConsts.LOCATION_TYPE] == 'Primary Shelf']\ [ScifConsts.LOCATION_TYPE_FK].values[0] product_hero_df = self.util.all_products[[ ScifConsts.PRODUCT_FK, self.util.HERO_SKU_LABEL ]] lvl3_ass_res_df = lvl3_ass_res_df.merge( product_hero_df, left_on='numerator_id', right_on=ScifConsts.PRODUCT_FK, how='left') lvl3_ass_res_df = lvl3_ass_res_df.merge( self.util.hero_type_custom_entity_df, left_on=self.util.HERO_SKU_LABEL, right_on='name', how='left') kpi_res_df = lvl3_ass_res_df.groupby( [self.util.HERO_SKU_LABEL, 'entity_fk'], as_index=False).agg({'numerator_result': np.sum}) kpi_res_df['in_store_total'] = in_store_skus kpi_res_df['result'] = kpi_res_df.apply(self.get_result, axis=1) kpi_res_df['score'] = kpi_res_df['result'].apply( lambda x: 100 if x >= 100 else 0) for i, res in kpi_res_df.iterrows(): self.write_to_db_result( fk=kpi_fk, numerator_id=res['entity_fk'], numerator_result=res['numerator_result'], result=res['result'], denominator_id=self.util.store_id, denominator_result=res['in_store_total'], score=res['score'], context_id=location_type_fk) self.util.add_kpi_result_to_kpi_results_df([ kpi_fk, res['entity_fk'], res['entity_fk'], res['result'], res['score'], location_type_fk ]) def kpi_type(self): pass @staticmethod def get_result(row): rv = float( row['numerator_result'] ) / row['in_store_total'] * 100 if row['in_store_total'] else 0 return rv