def chart_data(self):
        def calculate_weeks_remaining(stock_state, date):

            if stock_state.last_modified_date < date:
                if not stock_state.daily_consumption:
                    return 0
                consumption = float(stock_state.daily_consumption) * 7.0
                quantity = float(stock_state.stock_on_hand) - int((date - state.last_modified_date).days / 7.0) \
                    * consumption
                if consumption and consumption > 0 and quantity > 0:
                    return quantity / consumption
            return 0

        stock_states = StockState.include_archived.filter(
            case_id__in=get_relevant_supply_point_ids(self.config['domain'], self.sublocations[0]),
            section_id=STOCK_SECTION_TYPE,
            product_id__in=self.get_products(),
            last_modified_date__lte=self.config['enddate'],
        ).order_by('last_modified_date')

        rows = {}
        for state in stock_states:
            product_name = Product.get(state.product_id).name
            rows[product_name] = []
            weeks = ceil((self.config['enddate'] - self.config['startdate']).days / 7.0)
            for i in range(1, int(weeks + 1)):
                rows[product_name].append({'x': i, 'y': calculate_weeks_remaining(state, self.config['startdate'] +
                                                                                  timedelta(weeks=i))})
        return rows
Example #2
0
    def post(self, request, *args, **kwargs):
        InputStockFormSet = formset_factory(InputStockForm)
        formset = InputStockFormSet(request.POST)
        if formset.is_valid():
            try:
                sql_location = SQLLocation.objects.get(site_code=kwargs['site_code'], domain=self.domain)
            except SQLLocation.DoesNotExist:
                raise Http404()
            text = ''
            for form in formset:
                product = Product.get(docid=form.cleaned_data['product_id'])
                if form.cleaned_data['stock_on_hand'] is not None:
                    text += '{} {}.{} '.format(
                        product.code, form.cleaned_data['stock_on_hand'], form.cleaned_data['receipts'] or 0
                    )

                amount = form.cleaned_data['default_consumption']
                if amount is not None:
                    set_default_consumption_for_supply_point(
                        self.domain, product.get_id, sql_location.supply_point_id, amount
                    )
            if text:
                WebSubmissionHandler(self.request.couch_user, self.domain, Msg(text), sql_location).handle()
            url = make_url(
                StockStatus,
                self.domain,
                '?location_id=%s&filter_by_program=%s&startdate='
                '&enddate=&report_type=&filter_by_product=%s',
                (sql_location.location_id, ALL_OPTION, ALL_OPTION)
            )
            return HttpResponseRedirect(url)
        context = self.get_context_data(**kwargs)
        context['formset'] = formset
        return self.render_to_response(context)
    def handle(self, **options):

        self.stdout.write("Processing products...\n")
        products = set()
        total = StockState.objects.count()
        failed = []
        for i, ss in enumerate(StockState.objects.all()):
            if i % 500 == 0:
                self.stdout.write('done {}/{}'.format(i, total))
            if ss.product_id not in products:
                try:
                    product = Product.get(ss.product_id)
                    assert product.doc_type == 'Product'
                    products.add(ss.product_id)
                except (ResourceNotFound, AssertionError):
                    try:
                        case = CommCareCase.get(ss.case_id)
                    except ResourceNotFound:
                        case = CommCareCase()
                    failed.append((ss, case))
        if failed:
            for ss, case in failed:
                self.stdout.write('No product with ID "{}" found! case ID: {}, domain {}'.format(
                    ss.product_id, ss.case_id, case.domain
                ))
            self.stderr.write('{}/{} stock states FAILED check'.format(len(failed), total))
Example #4
0
    def leaf_node_data(self, stock_states):
        for state in stock_states:
            product = Product.get(state.product_id)

            result = {
                'product_id': product._id,
                'product_name': product.name,
                'current_stock': format_decimal(state.stock_on_hand),
            }

            if self._include_advanced_data():
                result.update({
                    'location_id':
                    SupplyPointCase.get(state.case_id).location_id,
                    'location_lineage':
                    None,
                    'category':
                    state.stock_category,
                    'consumption':
                    state.get_monthly_consumption(),
                    'months_remaining':
                    state.months_remaining,
                    'resupply_quantity_needed':
                    state.resupply_quantity_needed
                })

            yield result
Example #5
0
    def post(self, request, *args, **kwargs):
        InputStockFormSet = formset_factory(InputStockForm)
        formset = InputStockFormSet(request.POST)
        if formset.is_valid():
            try:
                sql_location = SQLLocation.objects.get(site_code=kwargs['site_code'], domain=self.domain)
            except SQLLocation.DoesNotExist:
                raise Http404()
            text = ''
            for form in formset:
                product = Product.get(docid=form.cleaned_data['product_id'])
                if form.cleaned_data['stock_on_hand'] is not None:
                    text += '{} {}.{} '.format(
                        product.code, form.cleaned_data['stock_on_hand'], form.cleaned_data['receipts'] or 0
                    )

                amount = form.cleaned_data['default_consumption']
                if amount is not None:
                    set_default_consumption_for_supply_point(
                        self.domain, product.get_id, sql_location.supply_point_id, amount
                    )
            if text:
                WebSubmissionHandler(self.request.couch_user, self.domain, Msg(text), sql_location).handle()
            url = make_url(
                StockStatus,
                self.domain,
                '?location_id=%s&filter_by_program=%s&startdate='
                '&enddate=&report_type=&filter_by_product=%s',
                (sql_location.location_id, ALL_OPTION, ALL_OPTION)
            )
            return HttpResponseRedirect(url)
        context = self.get_context_data(**kwargs)
        context['formset'] = formset
        return self.render_to_response(context)
Example #6
0
def delivery_update(requisition_cases, openlmis_endpoint):
    order_id = requisition_cases[0].get_case_property("order_id")
    products = []
    for rec in requisition_cases:
        product = Product.get(rec.product_id)
        products.append({'productCode': product.code, 'quantityReceived': rec.amount_received})
    delivery_data = {'podLineItems': products}
    return openlmis_endpoint.confirm_delivery(order_id, delivery_data)
Example #7
0
    def test_programs(self):
        self.domain = bootstrap_domain(TEST_DOMAIN)
        self.addCleanup(self.domain.delete)
        bootstrap_products(self.domain.name)
        self.products = sorted(Product.by_domain(self.domain.name), key=lambda p: p._id)
        self.default_program = Program.by_domain(self.domain.name, wrap=True).one()
        self.new_program = make_program(
            self.domain.name,
            'new program',
            'newprogram'
        )
        self.assertTrue(self.default_program.default)
        self.assertFalse(self.new_program.default)

        with self.assertRaises(Exception) as context:
            self.default_program.delete()

        self.assertEqual(six.text_type(context.exception), 'You cannot delete the default program')

        # assign some product to the new program
        self.products[0].program_id = self.new_program._id
        self.products[0].save()

        # make sure start state is okay
        self.assertEqual(
            2,
            len(Program.by_domain(self.domain.name))
        )
        self.assertEqual(2, self.default_program.get_products_count())
        self.assertEqual(1, self.new_program.get_products_count())
        self.assertEqual(
            self.new_program._id,
            self.products[0].program_id
        )
        self.assertEqual(
            self.new_program._id,
            SQLProduct.objects.get(product_id=self.products[0]._id).program_id
        )

        # stash the id before we delete
        new_program_id = self.new_program._id
        self.new_program.delete()

        with self.assertRaises(ResourceNotFound):
            Program.get(new_program_id)

        self.assertEqual(1, len(Program.by_domain(self.domain.name)))
        self.assertEqual(3, self.default_program.get_products_count())
        self.assertEqual(
            self.default_program._id,
            Product.get(self.products[0]._id).program_id
        )
        self.assertEqual(
            self.default_program._id,
            SQLProduct.objects.get(product_id=self.products[0]._id).program_id
        )
Example #8
0
 def expected_notification_message(self, req, amounts):
     summary = sorted(
         ['%s:%d' % (str(Product.get(p).code), amt) for p, amt in amounts]
     )
     return const.notification_template(req.get_next_action().action).format(
         name='Unknown',  # TODO currently not storing requester
         summary=' '.join(summary),
         loc=self.sp.location.site_code,
         keyword=req.get_next_action().keyword
     )
Example #9
0
 def fragment(self):
     """
     A short string representation of this to be used in sms correspondence
     """
     if self.quantity is not None:
         quant = self.quantity
     else:
         quant = ''
     # FIXME product fetch here is inefficient
     return '%s%s' % (Product.get(self.product_id).code.lower(), quant)
Example #10
0
 def fragment(self):
     """
     A short string representation of this to be used in sms correspondence
     """
     if self.quantity is not None:
         quant = int(self.quantity) if self.quantity == int(self.quantity) else self.quantity
     else:
         quant = ''
     # FIXME product fetch here is inefficient
     return '%s%s' % (Product.get(self.product_id).code.lower(), quant)
Example #11
0
 def save(self):
     for field in self.fields:
         val = self.cleaned_data[field]
         product = Product.get(field.split('_')[1])
         assert product.domain == self.domain, 'Product {} attempted to be updated in domain {}'.format(
             product._id, self.domain)
         set_default_consumption_for_product(
             self.domain,
             product._id,
             val,
         )
Example #12
0
def delivery_update(requisition_cases, openlmis_endpoint):
    order_id = requisition_cases[0].get_case_property("order_id")
    products = []
    for rec in requisition_cases:
        product = Product.get(rec.product_id)
        products.append({
            'productCode': product.code,
            'quantityReceived': rec.amount_received
        })
    delivery_data = {'podLineItems': products}
    return openlmis_endpoint.confirm_delivery(order_id, delivery_data)
Example #13
0
    def aggregated_data(self, stock_states):
        def _convert_to_daily(consumption):
            return consumption / 30 if consumption is not None else None

        product_aggregation = {}
        for state in stock_states:
            if state.product_id in product_aggregation:
                product = product_aggregation[state.product_id]
                product['current_stock'] = format_decimal(
                    product['current_stock'] + state.stock_on_hand
                )

                consumption = state.get_monthly_consumption()
                if product['consumption'] is None:
                    product['consumption'] = consumption
                elif consumption is not None:
                    product['consumption'] += consumption

                product['count'] += 1

                product['category'] = stock_category(
                    product['current_stock'],
                    _convert_to_daily(product['consumption']),
                    Domain.get_by_name(self.domain)
                )
                product['months_remaining'] = months_of_stock_remaining(
                    product['current_stock'],
                    _convert_to_daily(product['consumption'])
                )
            else:
                product = Product.get(state.product_id)
                consumption = state.get_monthly_consumption()

                product_aggregation[state.product_id] = {
                    'product_id': product._id,
                    'location_id': None,
                    'product_name': product.name,
                    'location_lineage': None,
                    'resupply_quantity_needed': None,
                    'current_stock': format_decimal(state.stock_on_hand),
                    'count': 1,
                    'consumption': consumption,
                    'category': stock_category(
                        state.stock_on_hand,
                        _convert_to_daily(consumption),
                        Domain.get_by_name(self.domain)
                    ),
                    'months_remaining': months_of_stock_remaining(
                        state.stock_on_hand,
                        _convert_to_daily(consumption)
                    )
                }

        return product_aggregation.values()
Example #14
0
 def save(self):
     for field in self.fields:
         val = self.cleaned_data[field]
         product = Product.get(field.split('_')[1])
         assert product.domain == self.domain, 'Product {} attempted to be updated in domain {}'.format(
             product._id, self.domain
         )
         set_default_consumption_for_product(
             self.domain,
             product._id,
             val,
         )
Example #15
0
    def get_prod_data(self):
        sp_ids = get_relevant_supply_point_ids(self.domain, self.active_location)

        stock_states = StockState.include_archived.filter(
            case_id__in=sp_ids,
            last_modified_date__lte=self.datespan.enddate_utc,
            last_modified_date__gte=self.datespan.startdate_utc,
            section_id=STOCK_SECTION_TYPE
        )
        if not self.archived_products:
            stock_states = stock_states.exclude(
                sql_product__is_archived=True
            )

        stock_states = stock_states.order_by('product_id')

        if self.program_id:
            stock_states = stock_states.filter(
                product_id__in=product_ids_filtered_by_program(
                    self.domain,
                    self.program_id
                )
            )

        product_grouping = {}
        for state in stock_states:
            status = state.stock_category
            if state.product_id in product_grouping:
                product_grouping[state.product_id][status] += 1
                product_grouping[state.product_id]['facility_count'] += 1

            else:
                product_grouping[state.product_id] = {
                    'obj': Product.get(state.product_id),
                    'stockout': 0,
                    'understock': 0,
                    'overstock': 0,
                    'adequate': 0,
                    'nodata': 0,
                    'facility_count': 1
                }
                product_grouping[state.product_id][status] = 1

        for product in product_grouping.values():
            yield [
                product['obj'].name,
                product['facility_count'],
                100.0 * product['stockout'] / product['facility_count'],
                100.0 * product['understock'] / product['facility_count'],
                100.0 * product['adequate'] / product['facility_count'],
                100.0 * product['overstock'] / product['facility_count'],
                100.0 * product['nodata'] / product['facility_count'],
            ]
Example #16
0
 def post(self, request, *args, **kwargs):
     InputStockFormSet = formset_factory(InputStockForm)
     formset = InputStockFormSet(request.POST)
     if formset.is_valid():
         try:
             location = SQLLocation.objects.get(site_code=kwargs['site_code'], domain=self.domain)
         except SQLLocation.DoesNotExist:
             raise Http404()
         data = []
         for form in formset:
             product = Product.get(docid=form.cleaned_data['product_id'])
             if form.cleaned_data['receipts']:
                 data.append(
                     StockTransaction(
                         domain=self.domain,
                         location_id=location.location_id,
                         case_id=location.supply_point_id,
                         product=product,
                         action=const.StockActions.RECEIPTS,
                         quantity=form.cleaned_data['receipts']
                     ),
                 )
             if form.cleaned_data['stock_on_hand'] is not None:
                 data.append(
                     StockTransaction(
                         domain=self.domain,
                         location_id=location.location_id,
                         case_id=location.supply_point_id,
                         product=product,
                         action=const.StockActions.STOCKONHAND,
                         quantity=form.cleaned_data['stock_on_hand']
                     ),
                 )
         if data:
             unpacked_data = {
                 'timestamp': datetime.utcnow(),
                 'user': self.request.couch_user,
                 'phone': 'ewsghana-input-stock',
                 'location': location.couch_location,
                 'transactions': data,
             }
             process(self.domain, unpacked_data)
         url = make_url(
             StockLevelsReport,
             self.domain,
             '?location_id=%s&filter_by_program=%s&startdate='
             '&enddate=&report_type=&filter_by_product=%s',
             (location.location_id, ALL_OPTION, ALL_OPTION)
         )
         return HttpResponseRedirect(url)
     context = self.get_context_data(**kwargs)
     context['formset'] = formset
     return self.render_to_response(context)
Example #17
0
def archive_product(request, domain, prod_id, archive=True):
    """
    Archive product
    """
    product = Product.get(prod_id)
    product.archive()
    return json_response({
        'success': True,
        'message': _("Product '{product_name}' has successfully been {action}.").format(
            product_name=product.name,
            action="archived",
        )
    })
Example #18
0
def unarchive_product(request, domain, prod_id, archive=True):
    """
    Unarchive product
    """
    product = Product.get(prod_id)
    product.unarchive()
    return json_response({
        'success': True,
        'message': _("Product '{product_name}' has successfully been {action}.").format(
            product_name=product.name,
            action="unarchived",
        )
    })
Example #19
0
def archive_product(request, domain, prod_id, archive=True):
    """
    Archive product
    """
    product = Product.get(prod_id)
    product.archive()
    return json_response(
        {
            "success": True,
            "message": _("Product '{product_name}' has successfully been {action}.").format(
                product_name=product.name, action="archived"
            ),
        }
    )
Example #20
0
 def leaf_node_data(self, stock_states):
     for state in stock_states:
         product = Product.get(state.product_id)
         yield {
             'category': state.stock_category,
             'product_id': product._id,
             'consumption': state.get_monthly_consumption(),
             'months_remaining': state.months_remaining,
             'location_id': SupplyPointCase.get(state.case_id).location_id,
             'product_name': product.name,
             'current_stock': format_decimal(state.stock_on_hand),
             'location_lineage': None,
             'resupply_quantity_needed': state.resupply_quantity_needed
         }
Example #21
0
    def test_delete(self):
        # assign some product to the new program
        self.products[0].program_id = self.new_program._id
        self.products[0].save()

        # make sure start state is okay
        self.assertEqual(
            2,
            len(Program.by_domain(self.domain.name))
        )
        self.assertEqual(
            2,
            Product.by_program_id(self.domain.name, self.default_program._id).count()
        )
        self.assertEqual(
            1,
            Product.by_program_id(self.domain.name, self.new_program._id).count()
        )
        self.assertEqual(
            self.new_program._id,
            self.products[0].program_id
        )
        self.assertEqual(
            self.new_program._id,
            SQLProduct.objects.get(product_id=self.products[0]._id).program_id
        )

        # stash the id before we delete
        new_program_id = self.new_program._id
        self.new_program.delete()

        with self.assertRaises(ResourceNotFound):
            Program.get(new_program_id)

        self.assertEqual(
            1,
            len(Program.by_domain(self.domain.name))
        )
        self.assertEqual(
            3,
            Product.by_program_id(self.domain.name, self.default_program._id).count()
        )
        self.assertEqual(
            self.default_program._id,
            Product.get(self.products[0]._id).program_id
        )
        self.assertEqual(
            self.default_program._id,
            SQLProduct.objects.get(product_id=self.products[0]._id).program_id
        )
Example #22
0
 def post(self, request, *args, **kwargs):
     InputStockFormSet = formset_factory(InputStockForm)
     formset = InputStockFormSet(request.POST)
     if formset.is_valid():
         try:
             location = SQLLocation.objects.get(
                 site_code=kwargs['site_code'], domain=self.domain)
         except SQLLocation.DoesNotExist:
             raise Http404()
         data = []
         for form in formset:
             product = Product.get(docid=form.cleaned_data['product_id'])
             if form.cleaned_data['receipts']:
                 data.append(
                     StockTransactionHelper(
                         domain=self.domain,
                         location_id=location.location_id,
                         case_id=location.supply_point_id,
                         product_id=product.get_id,
                         action=const.StockActions.RECEIPTS,
                         quantity=form.cleaned_data['receipts']), )
             if form.cleaned_data['stock_on_hand'] is not None:
                 data.append(
                     StockTransactionHelper(
                         domain=self.domain,
                         location_id=location.location_id,
                         case_id=location.supply_point_id,
                         product_id=product.get_id,
                         action=const.StockActions.STOCKONHAND,
                         quantity=form.cleaned_data['stock_on_hand']), )
         if data:
             unpacked_data = {
                 'timestamp': datetime.utcnow(),
                 'user': self.request.couch_user,
                 'phone': 'ewsghana-input-stock',
                 'location': location.couch_location,
                 'transactions': data,
             }
             process(self.domain, unpacked_data)
         url = make_url(
             StockLevelsReport, self.domain,
             '?location_id=%s&filter_by_program=%s&startdate='
             '&enddate=&report_type=&filter_by_product=%s',
             (location.location_id, ALL_OPTION, ALL_OPTION))
         return HttpResponseRedirect(url)
     context = self.get_context_data(**kwargs)
     context['formset'] = formset
     return self.render_to_response(context)
Example #23
0
    def sms_format(self):
        if self.requisition_status == RequisitionStatus.REQUESTED:
            section = 'ct-requested'
        elif self.requisition_status == RequisitionStatus.APPROVED:
            section = 'ct-approved'
        else:
            section = 'stock'

        formatted_strings = []
        states = StockState.objects.filter(case_id=self._id,
                                           section_id=section)
        for state in states:
            product = Product.get(state.product_id)
            formatted_strings.append('%s:%d' %
                                     (product.code, state.stock_on_hand))
        return ' '.join(sorted(formatted_strings))
Example #24
0
def unarchive_product(request, domain, prod_id, archive=True):
    """
    Unarchive product
    """
    product = Product.get(prod_id)
    try:
        product.unarchive()
    except DuplicateProductCodeException:
        success = False
        message = _("Another product is already using the Product ID '{product_id}'").format(product_id=product.code)
    else:
        success = True
        message = _("Product '{product_name}' has successfully been {action}.").format(
            product_name=product.name, action="unarchived"
        )
    return json_response({"success": success, "message": message, "product_id": prod_id})
Example #25
0
    def get_prod_data(self):
        sp_ids = get_relevant_supply_point_ids(self.domain,
                                               self.active_location)

        stock_states = StockState.objects.filter(
            case_id__in=sp_ids,
            last_modified_date__lte=self.datespan.enddate_utc,
            last_modified_date__gte=self.datespan.startdate_utc,
            section_id=STOCK_SECTION_TYPE)

        stock_states = stock_states.order_by('product_id')

        if self.program_id:
            stock_states = stock_states.filter(
                product_id__in=product_ids_filtered_by_program(
                    self.domain, self.program_id))

        product_grouping = {}
        for state in stock_states:
            status = state.stock_category
            if state.product_id in product_grouping:
                product_grouping[state.product_id][status] += 1
                product_grouping[state.product_id]['facility_count'] += 1

            else:
                product_grouping[state.product_id] = {
                    'obj': Product.get(state.product_id),
                    'stockout': 0,
                    'understock': 0,
                    'overstock': 0,
                    'adequate': 0,
                    'nodata': 0,
                    'facility_count': 1
                }
                product_grouping[state.product_id][status] = 1

        for product in product_grouping.values():
            yield [
                product['obj'].name,
                product['facility_count'],
                100.0 * product['stockout'] / product['facility_count'],
                100.0 * product['understock'] / product['facility_count'],
                100.0 * product['adequate'] / product['facility_count'],
                100.0 * product['overstock'] / product['facility_count'],
                100.0 * product['nodata'] / product['facility_count'],
            ]
Example #26
0
    def get_prod_data(self):
        sp_ids = get_relevant_supply_point_ids(self.domain, self.active_location)

        stock_states = StockState.objects.filter(
            case_id__in=sp_ids,
            last_modified_date__lte=self.datespan.enddate_utc,
            last_modified_date__gte=self.datespan.startdate_utc,
            section_id=STOCK_SECTION_TYPE
        )

        stock_states = stock_states.order_by('product_id')

        if self.program_id:
            stock_states = stock_states.filter(sql_product__program_id=self.program_id)

        product_grouping = {}
        for state in stock_states:
            status = state.stock_category
            if state.product_id in product_grouping:
                product_grouping[state.product_id][status] += 1
                product_grouping[state.product_id]['facility_count'] += 1

            else:
                product_grouping[state.product_id] = {
                    'obj': Product.get(state.product_id),
                    'stockout': 0,
                    'understock': 0,
                    'overstock': 0,
                    'adequate': 0,
                    'nodata': 0,
                    'facility_count': 1
                }
                product_grouping[state.product_id][status] = 1

        rows = [[
            product['obj'].name,
            product['facility_count'],
            100.0 * product['stockout'] / product['facility_count'],
            100.0 * product['understock'] / product['facility_count'],
            100.0 * product['adequate'] / product['facility_count'],
            100.0 * product['overstock'] / product['facility_count'],
            100.0 * product['nodata'] / product['facility_count'],
        ] for product in product_grouping.values()]

        return sorted(rows, key=lambda r: r[0].lower())
Example #27
0
def approve_requisition(requisition_cases, openlmis_endpoint):
    groups = defaultdict( list )
    for case in requisition_cases:
        groups[case.external_id].append(case)

    for group in groups.keys():
        if(group):
            cases = groups.get(group)
            products = []
            approver = CommCareUser.get(cases[0].user_id)
            for rec in cases:
                product = Product.get(rec.product_id)
                products.append({"productCode": product.code, "quantityApproved": rec.amount_approved})

            approve_data = {
                "approverName": approver.human_friendly_name,
                "products": products
            }
            openlmis_endpoint.approve_requisition(approve_data, group)
Example #28
0
    def sms_format(self):
        if self.requisition_status == RequisitionStatus.REQUESTED:
            section = 'ct-requested'
        elif self.requisition_status == RequisitionStatus.APPROVED:
            section = 'ct-approved'
        else:
            section = 'stock'

        formatted_strings = []
        states = StockState.objects.filter(
            case_id=self._id,
            section_id=section
        )
        for state in states:
            product = Product.get(state.product_id)
            formatted_strings.append(
                '%s:%d' % (product.code, state.stock_on_hand)
            )
        return ' '.join(sorted(formatted_strings))
Example #29
0
    def handle(self, **options):

        self.stdout.write("Processing products...\n")
        products = set()
        total = StockState.objects.count()
        failed = []
        for i, ss in enumerate(StockState.objects.all()):
            if i % 500 == 0:
                self.stdout.write('done {}/{}'.format(i, total))
            if ss.product_id not in products:
                try:
                    product = Product.get(ss.product_id)
                    assert product.doc_type == 'Product'
                    products.add(ss.product_id)
                except (ResourceNotFound, AssertionError):
                    try:
                        case = CommCareCase.get(ss.case_id)
                    except ResourceNotFound:
                        case = CommCareCase()
                    failed.append((ss, case))
Example #30
0
def approve_requisition(requisition_cases, openlmis_endpoint):
    groups = defaultdict(list)
    for case in requisition_cases:
        groups[case.external_id].append(case)

    for group in groups.keys():
        if (group):
            cases = groups.get(group)
            products = []
            approver = CommCareUser.get(cases[0].user_id)
            for rec in cases:
                product = Product.get(rec.product_id)
                products.append({
                    "productCode": product.code,
                    "quantityApproved": rec.amount_approved
                })

            approve_data = {
                "approverName": approver.human_friendly_name,
                "products": products
            }
            openlmis_endpoint.approve_requisition(approve_data, group)
Example #31
0
    def test_delete(self):
        # assign some product to the new program
        self.products[0].program_id = self.new_program._id
        self.products[0].save()

        # make sure start state is okay
        self.assertEqual(
            2,
            len(Program.by_domain(self.domain.name))
        )
        self.assertEqual(2, self.default_program.get_products_count())
        self.assertEqual(1, self.new_program.get_products_count())
        self.assertEqual(
            self.new_program._id,
            self.products[0].program_id
        )
        self.assertEqual(
            self.new_program._id,
            SQLProduct.objects.get(product_id=self.products[0]._id).program_id
        )

        # stash the id before we delete
        new_program_id = self.new_program._id
        self.new_program.delete()

        with self.assertRaises(ResourceNotFound):
            Program.get(new_program_id)

        self.assertEqual(1, len(Program.by_domain(self.domain.name)))
        self.assertEqual(3, self.default_program.get_products_count())
        self.assertEqual(
            self.default_program._id,
            Product.get(self.products[0]._id).program_id
        )
        self.assertEqual(
            self.default_program._id,
            SQLProduct.objects.get(product_id=self.products[0]._id).program_id
        )
Example #32
0
def unarchive_product(request, domain, prod_id, archive=True):
    """
    Unarchive product
    """
    product = Product.get(prod_id)
    try:
        product.unarchive()
    except DuplicateProductCodeException:
        success = False
        message = _("Another product is already using the Product ID '{product_id}'").format(
            product_id=product.code
        )
    else:
        success = True
        message = _("Product '{product_name}' has successfully been {action}.").format(
            product_name=product.name,
            action="unarchived",
        )
    return json_response({
        'success': success,
        'message': message,
        'product_id': prod_id
    })
Example #33
0
 def product(self):
     return Product.get(self.request_params["product_id"]) if "product_id" in self.request_params else None
Example #34
0
 def active_product(self):
     prod_id = self.config.get('product_id')
     if prod_id:
         return Product.get(prod_id)
    def get_prod_data(self):
        def get_months_until_stockout_icon(value):
            STOCKOUT = 0.0
            LOW = 1
            ADEQUATE = 3
            if float(value) == STOCKOUT:
                return '%s <span class="icon-remove" style="color:red"/>' % value
            elif float(value) < LOW:
                return '%s <span class="icon-warning-sign" style="color:orange"/>' % value
            elif float(value) <= ADEQUATE:
                return '%s <span class="icon-ok" style="color:green"/>' % value
            elif float(value) > ADEQUATE:
                return '%s <span class="icon-arrow-up" style="color:purple"/>' % value

        state_grouping = {}
        if self.config['program'] and not self.config['product']:
            product_ids = [product.get_id for product in Product.by_program_id(self.config['domain'],
                                                                               self.config['program'])]
        elif self.config['program'] and self.config['product']:
            product_ids = [self.config['product']]
        else:
            product_ids = Product.ids_by_domain(self.config['domain'])

        stock_states = StockState.objects.filter(
            case_id__in=get_relevant_supply_point_ids(self.config['domain'], self.sublocations[0]),
            section_id=STOCK_SECTION_TYPE,
            product_id__in=product_ids
        ).order_by('-last_modified_date')

        for state in stock_states:
            days = (datetime.now() - state.last_modified_date).days
            monthly_consumption = int(state.get_monthly_consumption()) if state.get_monthly_consumption() else 0
            if state.product_id not in state_grouping:
                state_grouping[state.product_id] = {
                    'commodity': Product.get(state.product_id).name,
                    'months_until_stockout': "%.2f" % (days / 30.0) if state.stock_on_hand else '',
                    'months_until_stockout_helper': state.stock_on_hand != 0,
                    'stockout_duration': timesince(state.last_modified_date) if state.stock_on_hand == 0 else '',
                    'stockout_duration_helper': state.stock_on_hand == 0,
                    'current_stock': state.stock_on_hand,
                    'monthly_consumption': monthly_consumption,
                    'reorder_level': int(monthly_consumption * REORDER_LEVEL),
                    'maximum_level': int(monthly_consumption * MAXIMUM_LEVEL),
                    'date_of_last_report': state.last_modified_date.strftime("%Y-%m-%d")
                }
            else:
                if not state_grouping[state.product_id]['months_until_stockout_helper']:
                    if state.stock_on_hand:
                        state_grouping[state.product_id]['months_until_stockout'] = "%.2f" % (days / 30.0)
                    else:
                        state_grouping[state.product_id]['stockout_duration_helper'] = False
                if state_grouping[state.product_id]['stockout_duration_helper']:
                    if not state.stock_on_hand:
                        state_grouping[state.product_id]['stockout_duration'] = timesince(state.last_modified_date)
                    else:
                        state_grouping[state.product_id]['stockout_duration_helper'] = False

        for values in state_grouping.values():
            yield {
                'commodity': values['commodity'],
                'current_stock': int(values['current_stock']),
                'monthly_consumption': values['monthly_consumption'] if values['monthly_consumption'] != 0.00
                else 'not enough data',
                'months_until_stockout': get_months_until_stockout_icon(values['months_until_stockout']
                                                                        if values['months_until_stockout']
                                                                        else 0.0),
                'stockout_duration': values['stockout_duration'],
                'date_of_last_report': values['date_of_last_report'],
                'reorder_level': values['reorder_level'] if values['reorder_level'] != 0.00
                else 'unknown',
                'maximum_level': values['maximum_level'] if values['maximum_level'] != 0.00
                else 'unknown'}
Example #36
0
 def product_name(product_id):
     return Product.get(product_id).name
Example #37
0
 def get_headers(self):
     for product_id, section in self._column_tuples:
         yield u"{product} ({section})".format(
             product=Product.get(product_id).name,
             section=section
         )
Example #38
0
    def aggregated_data(self, stock_states):
        def _convert_to_daily(consumption):
            return consumption / 30 if consumption is not None else None

        if self._include_advanced_data():
            product_aggregation = {}
            for state in stock_states:
                if state.product_id in product_aggregation:
                    product = product_aggregation[state.product_id]
                    product['current_stock'] = format_decimal(
                        product['current_stock'] + state.stock_on_hand)

                    consumption = state.get_monthly_consumption()
                    if product['consumption'] is None:
                        product['consumption'] = consumption
                    elif consumption is not None:
                        product['consumption'] += consumption

                    product['count'] += 1

                    if state.sql_location is not None:
                        location_type = state.sql_location.location_type
                        product['category'] = stock_category(
                            product['current_stock'],
                            _convert_to_daily(product['consumption']),
                            location_type.understock_threshold,
                            location_type.overstock_threshold,
                        )
                    else:
                        product['category'] = 'nodata'

                    product['months_remaining'] = months_of_stock_remaining(
                        product['current_stock'],
                        _convert_to_daily(product['consumption']))
                else:
                    product = Product.get(state.product_id)
                    consumption = state.get_monthly_consumption()

                    product_aggregation[state.product_id] = {
                        'product_id':
                        product._id,
                        'location_id':
                        None,
                        'product_name':
                        product.name,
                        'location_lineage':
                        None,
                        'resupply_quantity_needed':
                        None,
                        'current_stock':
                        format_decimal(state.stock_on_hand),
                        'count':
                        1,
                        'consumption':
                        consumption,
                        'category':
                        state_stock_category(state),
                        'months_remaining':
                        months_of_stock_remaining(
                            state.stock_on_hand,
                            _convert_to_daily(consumption))
                    }

            return product_aggregation.values()
        else:
            # If we don't need advanced data, we can
            # just do some orm magic.
            #
            # Note: this leaves out some harder to get quickly
            # values like location_id, but shouldn't be needed
            # unless we expand what uses this.
            aggregated_states = stock_states.values_list(
                'sql_product__name',
                'sql_product__product_id',
            ).annotate(stock_on_hand=Sum('stock_on_hand'))
            result = []
            for ag in aggregated_states:
                result.append({
                    'product_name': ag[0],
                    'product_id': ag[1],
                    'current_stock': format_decimal(ag[2])
                })

            return result
Example #39
0
 def get_headers(self):
     for product_id, section in self._column_tuples:
         yield "{product} ({section})".format(
             product=Product.get(product_id).name,
             section=section
         )
Example #40
0
 def active_product(self):
     prod_id = self.config.get('product_id')
     if prod_id:
         return Product.get(prod_id)
Example #41
0
    def aggregated_data(self, stock_states):
        def _convert_to_daily(consumption):
            return consumption / 30 if consumption is not None else None

        if self._include_advanced_data():
            product_aggregation = {}
            for state in stock_states:
                if state.product_id in product_aggregation:
                    product = product_aggregation[state.product_id]
                    product['current_stock'] = format_decimal(
                        product['current_stock'] + state.stock_on_hand
                    )

                    consumption = state.get_monthly_consumption()
                    if product['consumption'] is None:
                        product['consumption'] = consumption
                    elif consumption is not None:
                        product['consumption'] += consumption

                    product['count'] += 1

                    if state.sql_location is not None:
                        location_type = state.sql_location.location_type
                        product['category'] = stock_category(
                            product['current_stock'],
                            _convert_to_daily(product['consumption']),
                            location_type.understock_threshold,
                            location_type.overstock_threshold,
                        )
                    else:
                        product['category'] = 'nodata'

                    product['months_remaining'] = months_of_stock_remaining(
                        product['current_stock'],
                        _convert_to_daily(product['consumption'])
                    )
                else:
                    product = Product.get(state.product_id)
                    consumption = state.get_monthly_consumption()

                    product_aggregation[state.product_id] = {
                        'product_id': product._id,
                        'location_id': None,
                        'product_name': product.name,
                        'location_lineage': None,
                        'resupply_quantity_needed': None,
                        'current_stock': format_decimal(state.stock_on_hand),
                        'count': 1,
                        'consumption': consumption,
                        'category': state_stock_category(state),
                        'months_remaining': months_of_stock_remaining(
                            state.stock_on_hand,
                            _convert_to_daily(consumption)
                        )
                    }

            return product_aggregation.values()
        else:
            # If we don't need advanced data, we can
            # just do some orm magic.
            #
            # Note: this leaves out some harder to get quickly
            # values like location_id, but shouldn't be needed
            # unless we expand what uses this.
            aggregated_states = stock_states.values_list(
                'sql_product__name',
                'sql_product__product_id',
            ).annotate(stock_on_hand=Sum('stock_on_hand'))
            result = []
            for ag in aggregated_states:
                result.append({
                    'product_name': ag[0],
                    'product_id': ag[1],
                    'current_stock': format_decimal(ag[2])
                })

            return result
Example #42
0
 def product(self):
     try:
         return Product.get(self.product_id)
     except ResourceNotFound:
         raise Http404()
Example #43
0
 def product(self):
     try:
         return Product.get(self.product_id)
     except ResourceNotFound:
         raise Http404()
Example #44
0
 def product(self):
     return Product.get(self.request_params['product_id']) if 'product_id' in self.request_params else None
Example #45
0
 def product(self):
     return Product.get(self.request_params['product_id']
                        ) if 'product_id' in self.request_params else None
Example #46
0
 def product_name(product_id):
     return Product.get(product_id).name