예제 #1
0
    def get_prod_data(self):
        startkey = [
            self.domain,
            self.active_location._id if self.active_location else None
        ]
        product_cases = CommCareCase.view('commtrack/product_cases',
                                          startkey=startkey,
                                          endkey=startkey + [{}],
                                          include_docs=True)

        cases_by_product = map_reduce(lambda c: [(c.product, )],
                                      data=product_cases,
                                      include_docs=True)
        products = Product.view('_all_docs',
                                keys=cases_by_product.keys(),
                                include_docs=True)

        def _sum(vals):
            return sum(vals) if vals else None

        def aggregate_product(cases):
            data = [(current_stock(c), monthly_consumption(c)) for c in cases
                    if is_timely(c, 1000)]
            total_stock = _sum([d[0] for d in data if d[0] is not None])
            total_consumption = _sum([d[1] for d in data if d[1] is not None])
            # exclude stock values w/o corresponding consumption figure from total months left calculation
            consumable_stock = _sum(
                [d[0] for d in data if d[0] is not None and d[1] is not None])
            try:
                months_left = consumable_stock / total_consumption
            except (TypeError, ZeroDivisionError):
                months_left = None

            return {
                'total_stock': total_stock,
                'total_consumption': total_consumption,
                'months_left': months_left,
            }

        status_by_product = dict((p, aggregate_product(cases))
                                 for p, cases in cases_by_product.iteritems())
        for p in sorted(products, key=lambda p: p.name):
            stats = status_by_product[p._id]
            yield [
                p.name,
                stats['total_stock'],
                stats['total_consumption'],
                stats['months_left'],
                stock_category(stats['total_stock'],
                               stats['total_consumption'],
                               stats['months_left']),
            ]
예제 #2
0
    def get_prod_data(self):
        startkey = [self.domain, self.active_location._id if self.active_location else None]
        product_cases = SPPCase.view('commtrack/product_cases', startkey=startkey, endkey=startkey + [{}], include_docs=True)

        cases_by_product = map_reduce(lambda c: [(c.product,)], data=product_cases, include_docs=True)
        products = Product.view('_all_docs', keys=cases_by_product.keys(), include_docs=True)

        def status(case):
            return case.current_stock_category if is_timely(case, 1000) else 'nonreporting'

        status_by_product = dict((p, map_reduce(lambda c: [(status(c),)], len, data=cases)) for p, cases in cases_by_product.iteritems())

        cols = ['stockout', 'understock', 'adequate', 'overstock', 'nodata'] #'nonreporting', 'nodata']
        for p in sorted(products, key=lambda p: p.name):
            cases = cases_by_product.get(p._id, [])
            results = status_by_product.get(p._id, {})
            def val(key):
                return results.get(key, 0) / float(len(cases))
            yield [p.name, len(cases)] + [100. * val(key) for key in cols]
예제 #3
0
    def aggregate_cases(self, product_cases, slugs):
        cases_by_product = map_reduce(lambda c: [(c.product,)], data=product_cases, include_docs=True)
        products = Product.view('_all_docs', keys=cases_by_product.keys(), include_docs=True)

        def _sum(vals):
            return sum(vals) if vals else None

        def aggregate_product(cases):
            data = [(c.current_stock_level, c.monthly_consumption) for c in cases if is_timely(c, 1000)]
            total_stock = _sum([d[0] for d in data if d[0] is not None])
            total_consumption = _sum([d[1] for d in data if d[1] is not None])
            # exclude stock values w/o corresponding consumption figure from total months left calculation
            consumable_stock = _sum([d[0] for d in data if d[0] is not None and d[1] is not None])

            return {
                'total_stock': total_stock,
                'total_consumption': total_consumption,
                'consumable_stock': consumable_stock,
            }

        status_by_product = dict((p, aggregate_product(cases)) for p, cases in cases_by_product.iteritems())
        for p in sorted(products, key=lambda p: p.name):
            stats = status_by_product[p._id]

            months_left = SPPCase.months_of_stock_remaining(stats['consumable_stock'], stats['total_consumption'])
            category = SPPCase.stock_category(stats['total_stock'], stats['total_consumption'], stats['consumable_stock'])

            full_output = {
                self.SLUG_PRODUCT_NAME: p.name,
                self.SLUG_PRODUCT_ID: p._id,
                self.SLUG_LOCATION_ID: self.active_location._id if self.active_location else None,
                self.SLUG_LOCATION_LINEAGE: self.active_location.lineage if self.active_location else None,
                self.SLUG_CURRENT_STOCK: stats['total_stock'],
                self.SLUG_CONSUMPTION: stats['total_consumption'],
                self.SLUG_MONTHS_REMAINING: months_left,
                self.SLUG_CATEGORY: category,
            }

            yield dict((slug, full_output['slug']) for slug in slugs) if slugs else full_output
예제 #4
0
    def get_prod_data(self):
        startkey = [
            self.domain,
            self.active_location._id if self.active_location else None
        ]
        product_cases = CommCareCase.view('commtrack/product_cases',
                                          startkey=startkey,
                                          endkey=startkey + [{}],
                                          include_docs=True)

        cases_by_product = map_reduce(lambda c: [(c.product, )],
                                      data=product_cases,
                                      include_docs=True)
        products = Product.view('_all_docs',
                                keys=cases_by_product.keys(),
                                include_docs=True)

        def case_stock_category(case):
            return stock_category(current_stock(case),
                                  monthly_consumption(case))

        def status(case):
            return case_stock_category(case) if is_timely(
                case, 1000) else 'nonreporting'

        status_by_product = dict(
            (p, map_reduce(lambda c: [(status(c), )], len, data=cases))
            for p, cases in cases_by_product.iteritems())

        cols = ['stockout', 'understock', 'adequate', 'overstock',
                'nodata']  #'nonreporting', 'nodata']
        for p in sorted(products, key=lambda p: p.name):
            cases = cases_by_product.get(p._id, [])
            results = status_by_product.get(p._id, {})

            def val(key):
                return results.get(key, 0) / float(len(cases))

            yield [p.name, len(cases)] + [100. * val(key) for key in cols]
예제 #5
0
    def get_prod_data(self):
        startkey = [self.domain, self.active_location._id if self.active_location else None]
        product_cases = CommCareCase.view('commtrack/product_cases', startkey=startkey, endkey=startkey + [{}], include_docs=True)

        cases_by_product = map_reduce(lambda c: [(c.product,)], data=product_cases, include_docs=True)
        products = Product.view('_all_docs', keys=cases_by_product.keys(), include_docs=True)

        def _sum(vals):
            return sum(vals) if vals else None

        def aggregate_product(cases):
            data = [(current_stock(c), monthly_consumption(c)) for c in cases if is_timely(c, 1000)]
            total_stock = _sum([d[0] for d in data if d[0] is not None])
            total_consumption = _sum([d[1] for d in data if d[1] is not None])
            # exclude stock values w/o corresponding consumption figure from total months left calculation
            consumable_stock = _sum([d[0] for d in data if d[0] is not None and d[1] is not None])
            try:
                months_left = consumable_stock / total_consumption
            except (TypeError, ZeroDivisionError):
                months_left = None

            return {
                'total_stock': total_stock,
                'total_consumption': total_consumption,
                'months_left': months_left,
            }

        status_by_product = dict((p, aggregate_product(cases)) for p, cases in cases_by_product.iteritems())
        for p in sorted(products, key=lambda p: p.name):
            stats = status_by_product[p._id]
            yield [
                p.name,
                stats['total_stock'],
                stats['total_consumption'],
                stats['months_left'],
                stock_category(stats['total_stock'], stats['total_consumption'], stats['months_left']),
            ]
예제 #6
0
    def display_config(self):
        conf = {
            'name_column': 'name',
            'detail_columns': ['type'],
            'table_columns': ['type'],
            'column_titles': {
                'type': 'Supply Point Type',
            },
            'enum_captions': {},
            'numeric_format': {},
            'metrics': [
                {
                    'color': {
                        'column': 'type',
                    },
                },
            ],
        }

        titles = {
            'current_stock': 'Stock on Hand',
            'consumption': 'Monthly Consumption',
            'months_remaining': 'Months of Stock Remaining',
            'category': 'Current Stock Status',
        }

        products = sorted(Product.view('commtrack/products',
                                       startkey=[self.domain],
                                       endkey=[self.domain, {}],
                                       include_docs=True),
                          key=lambda p: p.name)
        if self.program_id:
            products = filter(lambda c: c.program_id == self.program_id,
                              products)
        for p in products:
            col_id = lambda c: '%s-%s' % (p._id, c)

            product_cols = []
            for c in ('category', 'current_stock', 'months_remaining',
                      'consumption'):
                conf['column_titles'][col_id(c)] = titles[c]
                product_cols.append(col_id(c))
            conf['detail_columns'].extend(product_cols)

            product_metrics = [{
                'icon': {
                    'column': col_id('category'),
                    'categories': {
                        'stockout': '/static/commtrack/img/stockout.png',
                        'understock': '/static/commtrack/img/warning.png',
                        'adequate': '/static/commtrack/img/goodstock.png',
                        'overstock': '/static/commtrack/img/overstock.png',
                        #'nodata': '/static/commtrack/img/no_data.png',
                        '_null': '/static/commtrack/img/no_data.png',
                    },
                }
            }]
            conf['enum_captions'][col_id('category')] = {
                'stockout': 'Stocked out',
                'understock': 'Under-stock',
                'adequate': 'Adequate Stock',
                'overstock': 'Over-stock',
                '_null': 'No Data',
            }

            for c in ('current_stock', 'months_remaining', 'consumption'):
                metric = {
                    'title': conf['column_titles'][col_id(c)],
                    'size': {
                        'column': col_id(c),
                    },
                }
                if c not in ('consumption', ):
                    metric['color'] = {
                        'column': col_id('category'),
                        'categories': {
                            'stockout': 'rgba(255, 0, 0, .8)',
                            'understock': 'rgba(255, 120, 0, .8)',
                            'adequate': 'rgba(50, 200, 50, .8)',
                            'overstock': 'rgba(120, 0, 255, .8)',
                            '_null': 'rgba(128, 128, 128, .8)',
                        },
                    }
                else:
                    metric['color'] = 'rgba(120, 120, 255, .8)'
                product_metrics.append(metric)

                conf['numeric_format'][col_id(c)] = {
                    'current_stock':
                    "return x + ' %s'" % (p.unit or 'unit'),
                    'months_remaining':
                    "return (Math.round(10 * x) / 10) + (x == 1 ? ' month' : ' months')",
                    'consumption':
                    "return (Math.round(10 * x) / 10) + ' %s / month'" %
                    (p.unit or 'unit'),
                }[c]

            conf['metrics'].append({
                'title': p.name,
                'group': True,
                'children': product_metrics,
            })
            conf['table_columns'].append({
                'title': p.name,
                'subcolumns': product_cols,
            })

        conf['detail_template'] = render_to_string(
            'reports/partials/commtrack/stockstatus_mapdetail.html', {
                'products':
                products,
                'columns': [{
                    'id': c,
                    'title': titles[c]
                } for c in ('category', 'current_stock', 'consumption',
                            'months_remaining')],
            })
        #print conf['detail_template']

        return conf
예제 #7
0
    def display_config(self):
        conf = {
            'name_column': 'name',
            'detail_columns': ['type'],
            'table_columns': ['type'],
            'column_titles': {
                'type': 'Supply Point Type',
            },
            'enum_captions': {},
            'numeric_format': {},
            'metrics': [
                {
                    'color': {
                        'column': 'type',
                    },
                },
            ],
        }

        titles = {
            'current_stock': 'Stock on Hand',
            'consumption': 'Monthly Consumption',
            'months_remaining': 'Months of Stock Remaining',
            'category': 'Current Stock Status',
        }

        products = sorted(Product.view('commtrack/products', startkey=[self.domain], endkey=[self.domain, {}], include_docs=True),
                          key=lambda p: p.name)
        if self.program_id:
            products = filter(lambda c: c.program_id == self.program_id, products)
        for p in products:
            col_id = lambda c: '%s-%s' % (p._id, c)

            product_cols = []
            for c in ('category', 'current_stock', 'months_remaining', 'consumption'):
                conf['column_titles'][col_id(c)] = titles[c]
                product_cols.append(col_id(c))
            conf['detail_columns'].extend(product_cols)

            product_metrics = [
                {
                    'icon': {
                        'column': col_id('category'),
                        'categories': {
                            'stockout': '/static/commtrack/img/stockout.png',
                            'understock': '/static/commtrack/img/warning.png',
                            'adequate': '/static/commtrack/img/goodstock.png',
                            'overstock': '/static/commtrack/img/overstock.png',
                            #'nodata': '/static/commtrack/img/no_data.png',
                            '_null': '/static/commtrack/img/no_data.png',
                        },
                    }
                }
            ]
            conf['enum_captions'][col_id('category')] = {
                'stockout': 'Stocked out',
                'understock': 'Under-stock',
                'adequate': 'Adequate Stock',
                'overstock': 'Over-stock',
                '_null': 'No Data',
            }

            for c in ('current_stock', 'months_remaining', 'consumption'):
                metric = {
                    'title': conf['column_titles'][col_id(c)],
                    'size': {
                        'column': col_id(c),
                    },
                }
                if c not in ('consumption',):
                    metric['color'] = {
                        'column': col_id('category'),
                        'categories': {
                            'stockout': 'rgba(255, 0, 0, .8)',
                            'understock': 'rgba(255, 120, 0, .8)',
                            'adequate': 'rgba(50, 200, 50, .8)',
                            'overstock': 'rgba(120, 0, 255, .8)',
                            '_null': 'rgba(128, 128, 128, .8)',
                        },
                    }
                else:
                    metric['color'] = 'rgba(120, 120, 255, .8)'
                product_metrics.append(metric)

                conf['numeric_format'][col_id(c)] = {
                    'current_stock': "return x + ' %s'" % (p.unit or 'unit'),
                    'months_remaining': "return (Math.round(10 * x) / 10) + (x == 1 ? ' month' : ' months')",
                    'consumption': "return (Math.round(10 * x) / 10) + ' %s / month'" % (p.unit or 'unit'),
                }[c]

            conf['metrics'].append({
                    'title': p.name,
                    'group': True,
                    'children': product_metrics,
                })
            conf['table_columns'].append({
                    'title': p.name,
                    'subcolumns': product_cols,
                })

        conf['detail_template'] = render_to_string('reports/partials/commtrack/stockstatus_mapdetail.html', {
                'products': products,
                'columns': [{'id': c, 'title': titles[c]} for c in
                            ('category', 'current_stock', 'consumption', 'months_remaining')],
                })
        #print conf['detail_template']

        return conf