def setUp(self): p1 = Product.get_by_code(TEST_DOMAIN, 'mc') p2 = Product.get_by_code(TEST_DOMAIN, 'lf') p3 = Product.get_by_code(TEST_DOMAIN, 'mg') self._create_stock_state(p1, 5) self._create_stock_state(p2, 10) self._create_stock_state(p3, 5)
def delete(self): # you cannot delete the default program if self.default: raise Exception(_('You cannot delete the default program')) default = Program.default_for_domain(self.domain) products = Product.by_program_id( self.domain, self._id, wrap=False ) to_save = [] for product in products: product['program_id'] = default._id to_save.append(product) # break up saving in case there are many products if to_save > 500: Product.get_db().bulk_save(to_save) to_save = [] Product.get_db().bulk_save(to_save) # bulk update sqlproducts SQLProduct.objects.filter(program_id=self._id).update(program_id=default._id) return super(Program, self).delete()
def _create_data(self, domain_name, i): product = Product(domain=domain_name, name='test-{}'.format(i)) product.save() location = Location( domain=domain_name, site_code='testcode-{}'.format(i), name='test-{}'.format(i), location_type='facility' ) location.save() SupplyPointCase.create_from_location(domain_name, location) report = StockReport.objects.create( type='balance', domain=domain_name, form_id='fake', date=datetime.utcnow() ) StockTransaction.objects.create( report=report, product_id=product.get_id, sql_product=SQLProduct.objects.get(product_id=product.get_id), section_id='stock', type='stockonhand', case_id=location.linked_supply_point().get_id, stock_on_hand=100 )
def test_archive(self): original_list = Product.by_domain(self.domain.name, wrap=False) self.products[0].archive() new_list = Product.by_domain(self.domain.name, wrap=False) self.assertTrue( self.products[0]._id not in [p['_id'] for p in new_list], "Archived product still returned by Product.by_domain()" ) self.assertEqual( len(new_list), len(original_list) - 1 ) self.assertEqual( len(Product.by_domain(self.domain.name, wrap=False, include_archived=True)), len(original_list) ) self.assertEqual( SQLProduct.objects.filter(domain=self.domain.name, is_archived=True).count(), 1 ) self.products[0].unarchive() self.assertEqual( len(original_list), len(Product.by_domain(self.domain.name, wrap=False)) )
def product_data(self): data = [] if self.show_inactive: products = Product.archived_by_domain( domain=self.domain, limit=self.limit, skip=self.skip(), ) else: products = Product.by_domain( domain=self.domain, limit=self.limit, skip=self.skip(), ) for p in products: if p.program_id: program = Program.get(p.program_id) else: program = get_or_create_default_program(self.domain) p.program_id = program.get_id p.save() info = p._doc info['program'] = program.name info['edit_url'] = reverse('commtrack_product_edit', kwargs={'domain': self.domain, 'prod_id': p._id}) info['archive_action_desc'] = self.get_archive_text(self.show_inactive) info['archive_action_text'] = _("Un-Archive") if self.show_inactive else _("Archive") info['archive_url'] = reverse( 'unarchive_product' if self.show_inactive else 'archive_product', kwargs={'domain': self.domain, 'prod_id': p._id} ) data.append(info) return data
def test_archive(self): bootstrap_products(self.domain) products = sorted(Product.by_domain(self.domain), key=lambda p: p._id) original_list = Product.by_domain(self.domain, wrap=False) products[0].archive() new_list = Product.by_domain(self.domain, wrap=False) self.assertTrue( products[0]._id not in [p['_id'] for p in new_list], "Archived product still returned by Product.by_domain()" ) self.assertEqual( len(new_list), len(original_list) - 1 ) self.assertEqual( len(Product.by_domain(self.domain, wrap=False, include_archived=True)), len(original_list) ) self.assertEqual( SQLProduct.objects.filter(domain=self.domain, is_archived=True).count(), 1 ) products[0].unarchive() self.assertEqual( len(original_list), len(Product.by_domain(self.domain, wrap=False)) )
def delete(self): # you cannot delete the default program if self.default: raise Exception(_('You cannot delete the default program')) default = Program.default_for_domain(self.domain) sql_products = SQLProduct.objects.filter(domain=self.domain, program_id=self.get_id) to_save = [] for product in sql_products.couch_products(): product['program_id'] = default._id to_save.append(product) # break up saving in case there are many products if len(to_save) > 500: Product.bulk_save(to_save) to_save = [] Product.bulk_save(to_save) # bulk update sqlproducts sql_products.update(program_id=default._id) return super(Program, self).delete()
def handle(self, *args, **options): for domain in Domain.get_all(): if domain['commtrack_enabled']: fields_definition = CustomDataFieldsDefinition.get_or_create( domain['name'], 'ProductFields' ) product_ids = Product.ids_by_domain(domain['name']) existing_field_slugs = set( [field.slug for field in fields_definition.fields] ) for product in iter_docs(Product.get_db(), product_ids): product_data = product.get('product_data', {}) for key in product_data.keys(): if key and key not in existing_field_slugs: existing_field_slugs.add(key) fields_definition.fields.append(CustomDataField( slug=key, label=key, is_required=False )) # Only save a definition for domains which use custom product data if fields_definition.fields: fields_definition.save()
def get_products(self): 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']) return product_ids
def import_products(domain, importer): from corehq.apps.products.views import ProductFieldsView results = {'errors': [], 'messages': []} to_save = [] product_count = 0 seen_product_ids = set() custom_data_validator = ProductFieldsView.get_validator(domain) for row in importer.worksheet: try: p = Product.from_excel(row, custom_data_validator) except Exception, e: results['errors'].append( _(u'Failed to import product {name}: {ex}'.format( name=row['name'] or '', ex=e, )) ) continue importer.add_progress() if not p: # skip if no product is found (or the row is blank) continue if not p.domain: # if product doesn't have domain, use from context p.domain = domain elif p.domain != domain: # don't let user import against another domains products results['errors'].append( _(u"Product {product_name} belongs to another domain and was not updated").format( product_name=p.name ) ) continue if p.code and p.code in seen_product_ids: results['errors'].append(_( u"Product {product_name} could not be imported \ due to duplicated product ids in the excel \ file" ).format( product_name=p.name )) continue elif p.code: seen_product_ids.add(p.code) product_count += 1 to_save.append(p) if len(to_save) > 500: Product.get_db().bulk_save(to_save) for couch_product in to_save: couch_product.sync_to_sql() to_save = []
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 setUp(self): self.facility = make_loc('test-faciity', 'Test Facility', TEST_DOMAIN, 'Polyclinic') self.commodity = Product(domain=TEST_DOMAIN, name='Drug A', code_='ab', unit='cycle') self.commodity.save() self.commodity2 = Product(domain=TEST_DOMAIN, name='Drug B', code_='cd', unit='cycle') self.commodity2.save() self.sql_facility = self.facility.sql_location self.sql_facility.products = [] self.sql_facility.save()
def _create_data(self, domain_name): product = Product(domain=domain_name, name="test-product") product.save() location = Location(domain=domain_name, site_code="testcode", name="test1", location_type="facility") location.save() self.locations[domain_name] = location.sql_location user = CommCareUser.create(domain=domain_name, username="******".format(domain_name), password="******") FacilityInCharge.objects.create(user_id=user.get_id, location=location.sql_location)
class EWSTestReminders(TestCase): """Moved from EWS""" @classmethod def setUpClass(cls): cls.domain = prepare_domain(TEST_DOMAIN) cls.sms_backend_mapping, cls.backend = create_backend() def setUp(self): self.facility = make_loc('test-faciity', 'Test Facility', TEST_DOMAIN, 'Polyclinic') self.commodity = Product(domain=TEST_DOMAIN, name='Drug A', code_='ab', unit='cycle') self.commodity.save() self.commodity2 = Product(domain=TEST_DOMAIN, name='Drug B', code_='cd', unit='cycle') self.commodity2.save() self.sql_facility = self.facility.sql_location self.sql_facility.products = [] self.sql_facility.save() def test_reminders(self): products_reported, products_not_reported = report_status(self.facility.sql_location, days_until_late=1) self.assertEqual(len(products_reported), 0) self.assertEqual(len(products_not_reported), 0) assign_products_to_location(self.facility, [self.commodity]) products_reported, products_not_reported = report_status(self.facility.sql_location, days_until_late=1) self.assertEqual(len(products_reported), 0) sql_commodity = SQLProduct.objects.get(product_id=self.commodity.get_id) self.assertEqual(products_not_reported[0], sql_commodity) sql_commodity2 = SQLProduct.objects.get(product_id=self.commodity2.get_id) create_stock_report(self.facility, {'ab': 10}) products_reported, products_not_reported = report_status(self.facility.sql_location, days_until_late=1) self.assertEqual(products_reported[0], sql_commodity) self.assertEqual(len(products_not_reported), 0) assign_products_to_location(self.facility, [self.commodity, self.commodity2]) products_reported, products_not_reported = report_status(self.facility.sql_location, days_until_late=1) self.assertEqual(products_reported[0], sql_commodity) self.assertEqual(products_not_reported[0], sql_commodity2) create_stock_report(self.facility, {'cd': 10}) products_reported, products_not_reported = report_status(self.facility.sql_location, days_until_late=1) self.assertTrue(sql_commodity in products_reported) self.assertTrue(sql_commodity2 in products_reported) self.assertEqual(len(products_not_reported), 0) @classmethod def tearDownClass(cls): cls.backend.delete() cls.sms_backend_mapping.delete()
def test_incomplete_report2(self): create_stock_report(self.facility, {'tp': 100}, date=datetime.utcnow()) self.product.program_id = self.program2.get_id self.product.save() other_product = Product( domain=self.TEST_DOMAIN, name='Test Product2', code_='tp2', unit='each', program_id=self.program.get_id ) other_product.save() assign_products_to_location(self.facility, [self.product, other_product]) generated = list(OnGoingNonReporting(self.TEST_DOMAIN).get_notifications()) self.assertEqual(len(generated), 0)
def test_partial_product_stockout(self): """Multiple products but only one is stocked out. Should be reported.""" other_product = Product(domain=self.TEST_DOMAIN, name='Test Product2', code_='tp2', unit='each') other_product.save() assign_products_to_location(self.facility, [self.product, other_product]) create_stock_report(self.facility, {'tp': 0}) create_stock_report(self.facility, {'tp2': 10}) generated = list(OnGoingStockouts(self.TEST_DOMAIN).get_notifications()) self.assertEqual(len(generated), 1) self.assertEqual(generated[0].user.get_id, self.user.get_id)
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 update_product_availability_facility_data(org_summary): # product availability facility = Location.get(docid=org_summary.supply_point) assert facility.location_type == "FACILITY" prods = Product.ids_by_domain(facility.domain) for p in prods: product_data, created = ProductAvailabilityData.objects.get_or_create( product=p, supply_point=facility._id, date=org_summary.date ) if created: # set defaults product_data.total = 1 previous_reports = ProductAvailabilityData.objects.filter( product=p, supply_point=facility._id, date__lt=org_summary.date ) if previous_reports.count(): prev = previous_reports.order_by("-date")[0] product_data.with_stock = prev.with_stock product_data.without_stock = prev.without_stock product_data.without_data = prev.without_data else: # otherwise we use the defaults product_data.with_stock = 0 product_data.without_stock = 0 product_data.without_data = 1 product_data.save() assert (product_data.with_stock + product_data.without_stock + product_data.without_data) == 1, \ "bad product data config"
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 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 _column_tuples(self): product_ids = [p._id for p in Product.by_domain(self.domain)] return sorted( list( StockState.objects.filter(product_id__in=product_ids).values_list("product_id", "section_id").distinct() ) )
def sync_requisition_from_openlmis(domain, requisition_id, openlmis_endpoint): cases = [] send_notification = False lmis_requisition_details = openlmis_endpoint.get_requisition_details(requisition_id) if lmis_requisition_details: rec_cases = [c for c in RequisitionCase.get_by_external_id(domain, str(lmis_requisition_details.id)) if c.type == const.REQUISITION_CASE_TYPE] if len(rec_cases) == 0: products = [product for product in lmis_requisition_details.products if product.skipped == False] for product in products: pdt = Product.get_by_code(domain, product.code.lower()) if pdt: case = lmis_requisition_details.to_requisition_case(pdt._id) case.save() if case.requisition_status == 'AUTHORIZED': send_notification = True cases.append(case) else: for case in rec_cases: before_status = case.requisition_status if apply_updates(case, lmis_requisition_details.to_dict(case.product_id)): after_status = case.requisition_status case.save() if before_status in ['INITIATED', 'SUBMITTED'] and after_status == 'AUTHORIZED': send_notification = True cases.append(case) return cases, send_notification else: return None, False
def rows(self): def row_in_names(row, names): if row in names: return True, names.index(row)+1 else: for idx, val in enumerate(names): if unicode(row).lower() in PRODUCT_NAMES.get(val, []): return True, idx+1 return False, 0 commandes = ['Comanndes'] raux = ['Recu'] taux = ['Taux'] products = Product.by_domain(self.config['domain']) for product in products: commandes.append(0) raux.append(0) taux.append(0) names = [] for product in products: names.append(unicode(product.name).lower()) rows = super(DispDesProducts, self).rows for row in rows: exits, index = row_in_names(row[0], names) if exits: commandes[index] = row[1] raux[index] = row[2] taux[index] = "%d%%" % (100*row[2]['html']/(row[1]['html'] or 1)) return [commandes, raux, taux]
def __init__(self, domain, *args, **kwargs): self.domain = domain super(ConsumptionForm, self).__init__(*args, **kwargs) self.helper = FormHelper() self.helper.form_tag = False self.helper.label_class = 'col-sm-3 col-md-4 col-lg-2' self.helper.field_class = 'col-sm-4 col-md-5 col-lg-3' layout = [] products = Product.by_domain(domain) for p in products: field_name = 'default_%s' % p._id display = _('Default %(product_name)s') % {'product_name': p.name} layout.append(field_name) self.fields[field_name] = forms.DecimalField( label=display, required=False, initial=get_default_monthly_consumption( self.domain, p._id, None, None ) ) layout.append(hqcrispy.FormActions( ButtonHolder( Submit('submit', ugettext_lazy('Update Default Consumption Info')) ) )) self.helper.layout = Layout(*layout)
def product_from_code(self, prod_code): """return the product doc referenced by prod_code""" prod_code = prod_code.lower() p = Product.get_by_code(self.domain.name, prod_code) if p is None: raise SMSError('invalid product code "%s"' % prod_code) return p
def wrap_from_json(cls, obj, domain, location_id): product = Product.get_by_code(domain, obj['product']) obj['product'] = product._id obj['location_id'] = location_id obj['external_id'] = obj['id'] del obj['id'] return cls(**obj)
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 drilldown_map(self): options = [{"val": ALL_OPTION, "text": "All", "next": []}] for program in Program.by_domain(self.domain): products = [{"val": ALL_OPTION, "text": "All", "next": []}] for product in Product.by_program_id(self.domain, program._id): products.append({"val": product.get_id, "text": product.name + ' (%s)' % product.code}) options.append({"val": program.get_id, "text": program.name, "next": products}) return options
def setUp(self): self.datapath = os.path.join(os.path.dirname(__file__), 'data') self.api = MockOpenLMISEndpoint("uri://mock/lmis/endpoint", username='******', password='******') initial_bootstrap(TEST_DOMAIN) bootstrap_domain(TEST_DOMAIN) delete_all_cases() for product in Product.by_domain(TEST_DOMAIN): product.delete()
def all_sms_codes(domain): config = CommtrackConfig.for_domain(domain) actions = dict((action.keyword, action) for action in config.actions) products = dict((p.code, p) for p in Product.by_domain(domain)) sms_codes = zip(('action', 'product'), (actions, products)) return dict(itertools.chain(*([(k.lower(), (type, v)) for k, v in six.iteritems(codes)] for type, codes in sms_codes)))
def setUp(self): super(UrgentStockoutNotificationTestCase, self).setUp() self.product = Product(domain=self.TEST_DOMAIN, name='Test Product', code_='tp', unit='each', program_id=self.program.get_id) self.product.save() self.country = make_loc('test-country', 'Test country', self.TEST_DOMAIN, 'country') self.region = make_loc('test-region', 'Test Region', self.TEST_DOMAIN, 'region', parent=self.country) self.district = make_loc('test-district', 'Test District', self.TEST_DOMAIN, 'district', parent=self.region) self.facility = make_loc('test-facility', 'Test Facility', self.TEST_DOMAIN, 'Polyclinic', self.district) self.other_facility = make_loc('test-facility2', 'Test Facility 2', self.TEST_DOMAIN, 'Polyclinic', self.district) self.last_facility = make_loc('test-facility3', 'Test Facility 3', self.TEST_DOMAIN, 'Polyclinic', self.district) self.user = bootstrap_web_user(username='******', domain=self.TEST_DOMAIN, phone_number='+4444', location=self.region, email='*****@*****.**', password='******', user_data={})
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 test_selective_product_sync(self): user = self.user expected_xml = self.generate_product_fixture_xml(user) product_list = Product.by_domain(user.domain) self._initialize_product_names(len(product_list)) fixture_original = call_fixture_generator(product_fixture_generator, user)[1] deprecated_generate_restore_payload(self.domain_obj, user) self.assertXmlEqual( expected_xml, ElementTree.tostring(fixture_original, encoding='utf-8')) first_sync = self._get_latest_synclog() # make sure the time stamp on this first sync is # not on the same second that the products were created first_sync.date += datetime.timedelta(seconds=1) # second sync is before any changes are made, so there should # be no products synced fixture_pre_change = call_fixture_generator(product_fixture_generator, user, last_sync=first_sync) deprecated_generate_restore_payload(self.domain_obj, user) self.assertEqual([], fixture_pre_change, "Fixture was not empty on second sync") second_sync = self._get_latest_synclog() self.assertTrue(first_sync._id != second_sync._id) # save should make the product more recently updated than the # last sync for product in product_list: product.save() # now that we've updated a product, we should get # product data in sync again fixture_post_change = call_fixture_generator(product_fixture_generator, user, last_sync=second_sync)[1] # regenerate the fixture xml to make sure it is still legit self.assertXmlEqual( expected_xml, ElementTree.tostring(fixture_post_change, encoding='utf-8'))
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 test_product_type_filter(self): """User can recieve missing notifications for only certain product type.""" bootstrap_web_user( username='******', domain=self.TEST_DOMAIN, phone_number='+44445', location=self.district, password='******', email='*****@*****.**', user_data={}, program_id=self.program.get_id ) other_product = Product(domain=self.TEST_DOMAIN, name='Test Product2', code_='tp2', unit='each') other_product2 = Product(domain=self.TEST_DOMAIN, name='Test Product3', code_='tp3', unit='each') other_product.save() other_product2.save() assign_products_to_location(self.facility, [self.product, other_product, other_product2]) generated = list(OnGoingNonReporting(self.TEST_DOMAIN).get_notifications()) self.assertEqual(len(generated), 1) self.assertEqual(generated[0].user.get_id, self.user.get_id)
def setUp(self): super(CommTrackTest, self).setUp() # might as well clean house before doing anything delete_all_xforms() delete_all_cases() delete_all_sync_logs() StockReport.objects.all().delete() StockTransaction.objects.all().delete() self.backend, self.backend_mapping = setup_default_sms_test_backend() self.domain = bootstrap_domain(TEST_DOMAIN) bootstrap_location_types(self.domain.name) bootstrap_products(self.domain.name) self.ct_settings = CommtrackConfig.for_domain(self.domain.name) self.ct_settings.consumption_config = ConsumptionConfig( min_transactions=0, min_window=0, optimal_window=60, min_periods=0, ) # todo: remove? if self.requisitions_enabled: self.ct_settings.requisition_config = get_default_requisition_config( ) self.ct_settings.save() self.domain = Domain.get(self.domain._id) self.loc = make_loc('loc1') self.sp = self.loc.linked_supply_point() self.users = [ bootstrap_user(self, **user_def) for user_def in self.user_definitions ] # everyone should be in a group. self.group = Group(domain=TEST_DOMAIN, name='commtrack-folks', users=[u._id for u in self.users], case_sharing=True) self.group._id = self.sp.owner_id self.group.save() self.products = sorted(Product.by_domain(self.domain.name), key=lambda p: p._id) self.assertEqual(3, len(self.products))
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 __init__(self, domain, *args, **kwargs): self.domain = domain super(ConsumptionForm, self).__init__(*args, **kwargs) products = Product.by_domain(domain) for p in products: field_name = 'default_%s' % p._id display = _('Default %(product_name)s') % {'product_name': p.name} self.fields[field_name] = forms.DecimalField( label=display, required=False, initial=get_default_monthly_consumption( self.domain, p._id, None, None ) )
def include_consumption(self): if bool( self.include_consumption_flag and self.domain_obj.commtrack_settings.individual_consumption_defaults ): # we'll be needing these, so init 'em: self.products = Product.by_domain(self.domain) self.product_codes = [p.code for p in self.products] self.supply_point_map = get_supply_point_ids_in_domain_by_location( self.domain) self.administrative_types = { lt.name for lt in self.location_types if lt.administrative } return True return False
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 product_sync(self, ilsgateway_product): product = Product.get_by_code(self.domain, ilsgateway_product.sms_code) product_dict = { 'domain': self.domain, 'name': ilsgateway_product.name, 'code': ilsgateway_product.sms_code, 'unit': str(ilsgateway_product.units), 'description': ilsgateway_product.description, } if product is None: product = Product(**product_dict) product.save() else: if apply_updates(product, product_dict): product.save() return product
def all_sms_codes(domain): config = CommtrackConfig.for_domain(domain) actions = dict((action.keyword, action) for action in config.actions) products = dict((p.code, p) for p in Product.by_domain(domain)) commands = { config.multiaction_keyword: { 'type': 'stock_report_generic', 'caption': 'Stock Report' }, } sms_codes = zip(('action', 'product', 'command'), (actions, products, commands)) return dict( itertools.chain(*([(k.lower(), (type, v)) for k, v in codes.iteritems()] for type, codes in sms_codes)))
def setUpClass(cls): super(StockStateTest, cls).setUpClass() cls.domain_obj = util.bootstrap_domain(cls.domain) util.bootstrap_location_types(cls.domain) util.bootstrap_products(cls.domain) cls.ct_settings = CommtrackConfig.for_domain(cls.domain) cls.ct_settings.use_auto_consumption = True cls.ct_settings.consumption_config = ConsumptionConfig( min_transactions=0, min_window=0, optimal_window=60, min_periods=0, ) cls.ct_settings.save() cls.loc = util.make_loc('loc1', domain=cls.domain) cls.sp = cls.loc.linked_supply_point() cls.products = sorted(Product.by_domain(cls.domain), key=lambda p: p._id)
def recalculate_domain_consumption(domain): """ Given a domain, recalculate all saved consumption settings in that domain. """ # note: might get slow as this gets huge found_doc_ids = DocDomainMapping.objects.filter( domain_name=domain, doc_type='CommCareCase', ).values_list('doc_id', flat=True) products = Product.by_domain(domain) for supply_point_id in found_doc_ids: for product in products: filtered_transactions = StockTransaction.objects.filter( case_id=supply_point_id, product_id=product._id, section_id=const.SECTION_TYPE_STOCK, ).order_by('-report__date', '-pk') if filtered_transactions: update_stock_state_for_transaction(filtered_transactions[0])
def tearDownClass(cls): MobileBackend.load_by_name(TEST_DOMAIN, TEST_BACKEND).delete() CommCareUser.get_by_username('stella').delete() CommCareUser.get_by_username('bella').delete() CommCareUser.get_by_username('trella').delete() CommCareUser.get_by_username('msd_person').delete() for product in Product.by_domain(TEST_DOMAIN): product.delete() SQLProduct.objects.all().delete() ILSGatewayConfig.for_domain(TEST_DOMAIN).delete() DocDomainMapping.objects.all().delete() Location.by_site_code(TEST_DOMAIN, 'loc1').delete() Location.by_site_code(TEST_DOMAIN, 'loc2').delete() Location.by_site_code(TEST_DOMAIN, 'dis1').delete() Location.by_site_code(TEST_DOMAIN, 'reg1').delete() Location.by_site_code(TEST_DOMAIN, 'moh1').delete() SQLLocation.objects.all().delete() generator.delete_all_subscriptions() Domain.get_by_name(TEST_DOMAIN).delete()
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 setUp(self): super(XMLTest, self).setUp() self.domain = util.bootstrap_domain(util.TEST_DOMAIN) util.bootstrap_location_types(self.domain.name) util.bootstrap_products(self.domain.name) self.products = sorted(Product.by_domain(self.domain.name), key=lambda p: p._id) self.ct_settings = CommtrackConfig.for_domain(self.domain.name) self.ct_settings.consumption_config = ConsumptionConfig( min_transactions=0, min_window=0, optimal_window=60, min_periods=0, ) self.ct_settings.save() self.domain = Domain.get(self.domain._id) self.loc = make_loc('loc1') self.sp = self.loc.linked_supply_point() self.users = [util.bootstrap_user(self, **user_def) for user_def in self.user_definitions] self.user = self.users[0]
def copy_products(self): from corehq.apps.products.models import Product from corehq.apps.programs.models import Program from corehq.apps.products.views import ProductFieldsView self._copy_custom_data(ProductFieldsView.field_type) program_map = {} programs = Program.by_domain(self.existing_domain) for program in programs: old_id, new_id = self.save_couch_copy(program, self.new_domain) program_map[old_id] = new_id products = Product.by_domain(self.existing_domain) for product in products: if product.program_id: try: product.program_id = program_map[product.program_id] except: self.stderr('Missing program {} for product {}'.format(product.program_id, product._id)) self.save_couch_copy(product, self.new_domain)
def tearDownClass(cls): delete_domain_phone_numbers(TEST_DOMAIN) if cls.sms_backend_mapping.id is not None: cls.sms_backend_mapping.delete() if cls.sms_backend.id is not None: cls.sms_backend.delete() users = get_user_docs_by_username([ 'stella', 'bella', 'trella', 'msd_person', ]) if users: CommCareUser.bulk_delete([ CommCareUser.wrap_correctly(user) for user in users ]) for product in Product.by_domain(TEST_DOMAIN): product.delete() SQLProduct.objects.all().delete() ils_gateway_config = ILSGatewayConfig.for_domain(TEST_DOMAIN) if ils_gateway_config: ils_gateway_config.delete() DocDomainMapping.objects.all().delete() for site_code in [ 'loc1', 'loc2', 'dis1', 'reg1', 'moh1', ]: location = cls.get_location_by_site_code(site_code) if location: location.delete() SQLLocation.objects.all().delete() test_domain = Domain.get_by_name(TEST_DOMAIN, strict=True) if test_domain: test_domain.delete() super(ILSTestScript, cls).tearDownClass()
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_should_import_consumption(self): existing = make_loc('existingloc', type='state') sp = make_supply_point(self.loc.domain, existing) data = { 'site_code': existing.site_code, 'name': 'existingloc', 'consumption': { 'pp': 77 }, } import_location(self.domain.name, 'state', data) self.assertEqual( float( get_default_consumption( self.domain.name, Product.get_by_code(self.domain.name, 'pp')._id, 'state', sp._id, )), 77 / DAYS_IN_MONTH)
def handle(self, *args, **options): self.stdout.write("Processing products...\n") relevant_ids = set([ r['id'] for r in Product.get_db().view( 'commtrack/products', reduce=False, ).all() ]) to_save = [] for product in iter_docs(Product.get_db(), relevant_ids): if 'last_modified' not in product or not product['last_modified']: product['last_modified'] = datetime.utcnow().isoformat() to_save.append(product) if len(to_save) > 500: Product.bulk_save(to_save) to_save = [] if to_save: Product.bulk_save(to_save) self.stdout.write("Processing programs...\n") relevant_ids = set([ r['id'] for r in Program.get_db().view( 'commtrack/programs', reduce=False, ).all() ]) to_save = [] for program in iter_docs(Program.get_db(), relevant_ids): if 'last_modified' not in program or not program['last_modified']: program['last_modified'] = datetime.utcnow().isoformat() to_save.append(program) if len(to_save) > 500: Program.get_db().bulk_save(to_save) to_save = [] if to_save: Program.get_db().bulk_save(to_save)
def tearDownClass(cls): delete_domain_phone_numbers(TEST_DOMAIN) if cls.sms_backend_mapping.id is not None: cls.sms_backend_mapping.delete() if cls.sms_backend.id is not None: cls.sms_backend.delete() for username in [ 'stella', 'bella', 'trella', 'msd_person', ]: user = CommCareUser.get_by_username(username) if user: user.delete() for product in Product.by_domain(TEST_DOMAIN): product.delete() SQLProduct.objects.all().delete() ils_gateway_config = ILSGatewayConfig.for_domain(TEST_DOMAIN) if ils_gateway_config: ils_gateway_config.delete() DocDomainMapping.objects.all().delete() for site_code in [ 'loc1', 'loc2', 'dis1', 'reg1', 'moh1', ]: location = Location.by_site_code(TEST_DOMAIN, site_code) if location: location.delete() SQLLocation.objects.all().delete() generator.delete_all_subscriptions() test_domain = Domain.get_by_name(TEST_DOMAIN) if test_domain: test_domain.delete() super(ILSTestScript, cls).tearDownClass()
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 setUpClass(cls): super(StockStateTest, cls).setUpClass() cls.domain_obj = util.bootstrap_domain(cls.domain) util.bootstrap_location_types(cls.domain) util.bootstrap_products(cls.domain) cls.ct_settings = SQLCommtrackConfig.for_domain(cls.domain) cls.ct_settings.use_auto_consumption = True cls.ct_settings.sqlconsumptionconfig = SQLConsumptionConfig( min_transactions=0, min_window=0, optimal_window=60, ) cls.ct_settings.save() cls.ct_settings.sqlconsumptionconfig.commtrack_settings = cls.ct_settings cls.ct_settings.sqlconsumptionconfig.save() cls.loc = util.make_loc('loc1', domain=cls.domain) cls.sp = cls.loc.linked_supply_point() cls.products = sorted(Product.by_domain(cls.domain), key=lambda p: p._id) cls.process_ledger_changes = process_pillow_changes( 'LedgerToElasticsearchPillow')
def recalculate_domain_consumption(domain): """ Given a domain, recalculate all saved consumption settings in that domain. """ # note: might get slow as this gets huge found_doc_ids = DocDomainMapping.objects.filter( domain_name=domain, doc_type='CommCareCase', ).values_list('doc_id', flat=True) products = Product.by_domain(domain) for supply_point_id in found_doc_ids: for product in products: try: latest_transaction = StockTransaction.get_ordered_transactions_for_stock( supply_point_id, const.SECTION_TYPE_STOCK, product._id)[0] except IndexError: pass else: state = get_stock_state_for_transaction(latest_transaction) daily_consumption = get_consumption_for_ledger(state) state.daily_consumption = daily_consumption with drop_connected_signals(post_save): state.save()
def sync_openlmis_product(domain, program, lmis_product): product = get_product(domain, lmis_product) product_dict = { 'domain': domain, 'name': lmis_product.name, 'code': lmis_product.code, 'unit': str(lmis_product.unit), 'description': lmis_product.description, 'category': lmis_product.category, 'program_id': program._id, } if product is None: product = Product(**product_dict) product.save() else: if apply_updates(product, product_dict): product.save() return product
def test_product_fixture_cache(self): user = self.user expected_xml = self.generate_product_fixture_xml(user) fixture_original = call_fixture_generator(product_fixture_generator, user)[1] self.assertXmlEqual(expected_xml, fixture_original) product = Product.by_domain(user.domain)[0] product.name = 'new_name' super(Product, product).save() # save but skip clearing the cache fixture_cached = call_fixture_generator(product_fixture_generator, user)[1] self.assertXmlEqual(expected_xml, fixture_cached) # This will update all the products and re-save them. expected_xml_new = self.generate_product_fixture_xml(user) fixture_cached = call_fixture_generator(product_fixture_generator, user)[1] self.assertXmlEqual(expected_xml_new, fixture_cached) self.assertXMLNotEqual(expected_xml_new, expected_xml)
def test_should_import_consumption(self): parent = make_loc('originalparent', type='village') existing = make_loc('existingloc', type='outlet', parent=parent) sp = existing.linked_supply_point() data = { 'site_code': existing.site_code, 'name': 'existingloc', 'parent_site_code': parent.site_code, 'consumption': { 'pp': 77 }, } import_location(self.domain.name, 'outlet', data) self.assertEqual( float( get_default_consumption( self.domain.name, Product.get_by_code(self.domain.name, 'pp')._id, 'state', sp.case_id, )), 77 / DAYS_IN_MONTH)