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
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))
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
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 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)
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 )
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 )
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)
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)
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, )
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)
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()
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, )
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'], ]
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)
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", ) })
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", ) })
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" ), } )
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 }
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 )
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)
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))
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})
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'], ]
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())
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)
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))
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))
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)
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 )
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 })
def product(self): return Product.get(self.request_params["product_id"]) if "product_id" in self.request_params else None
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'}
def product_name(product_id): return Product.get(product_id).name
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 )
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
def get_headers(self): for product_id, section in self._column_tuples: yield "{product} ({section})".format( product=Product.get(product_id).name, section=section )
def active_product(self): prod_id = self.config.get('product_id') if prod_id: return Product.get(prod_id)
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
def product(self): try: return Product.get(self.product_id) except ResourceNotFound: raise Http404()
def product(self): try: return Product.get(self.product_id) except ResourceNotFound: raise Http404()
def product(self): return Product.get(self.request_params['product_id']) if 'product_id' in self.request_params else None
def product(self): return Product.get(self.request_params['product_id'] ) if 'product_id' in self.request_params else None
def product_name(product_id): return Product.get(product_id).name