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( len( Product.archived_by_domain(self.domain.name, wrap=False, include_archived=True)), 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_make_def_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 product_edit(request, domain, prod_id=None): if prod_id: try: product = Product.get(prod_id) except ResourceNotFound: raise Http404 else: product = Product(domain=domain) if request.method == "POST": form = ProductForm(product, request.POST) if form.is_valid(): form.save() messages.success(request, 'Product saved!') return HttpResponseRedirect( reverse('commtrack_product_list', kwargs={'domain': domain})) else: form = ProductForm(product) context = { 'domain': domain, 'product': product, 'form': form, } template = "commtrack/manage/product.html" return render(request, template, context)
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): 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( len(Product.archived_by_domain(self.domain.name, wrap=False, include_archived=True)), 1 ) self.products[0].unarchive() self.assertEqual( len(original_list), len(Product.by_domain(self.domain.name, wrap=False)) )
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 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 make_product(domain, name, code, program_id): p = Product() p.domain = domain p.name = name p.code = code.lower() p.program_id = program_id p.save() return p
def test_migration(self): bootstrap_domain(ILSGatewayAPI(TEST_DOMAIN, MockEndpoint('http://test-api.com/', 'dummy', 'dummy'))) self.assertEqual(6, len(list(Product.by_domain(TEST_DOMAIN)))) self.assertEqual(5, len(list(Location.by_domain(TEST_DOMAIN)))) self.assertEqual(6, len(list(CommCareUser.by_domain(TEST_DOMAIN)))) self.assertEqual(5, len(list(WebUser.by_domain(TEST_DOMAIN)))) self.assertEqual(ILSMigrationStats.objects.filter(domain=TEST_DOMAIN).count(), 1)
def wrap_from_json(cls, obj, domain, location_id): product = Product.get_by_code(domain, obj['product']) obj['product'] = product._id obj['supply_point'] = location_id obj['external_id'] = obj['id'] del obj['id'] return cls(**obj)
def product_fetch(request, domain): page = int(request.GET.get('page', 1)) limit = int(request.GET.get('limit', DEFAULT_PRODUCT_LIST_LIMIT)) skip = (page - 1) * limit sort_by = request.GET.get('sortBy', 'abc') show_inactive = json.loads(request.GET.get('show_inactive', 'false')) products = Product.by_domain(domain) #limit=limit, skip=skip) def product_data(p): info = p._doc info['edit_url'] = reverse('commtrack_product_edit', kwargs={ 'domain': domain, 'prod_id': p._id }) return info return HttpResponse( json.dumps( dict( success=True, current_page=page, product_list=[product_data(p) for p in products], )), 'text/json')
def handle(self, *args, **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 product_data(self): data = [] products = Product.by_program_id(domain=self.domain, prog_id=self.program_id, skip=self.skip(), limit=self.limit) for p in products: data.append(p._doc) return data
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 product_edit(request, domain, prod_id=None): if prod_id: try: product = Product.get(prod_id) except ResourceNotFound: raise Http404 else: product = Product(domain=domain) if request.method == "POST": form = ProductForm(product, request.POST) if form.is_valid(): form.save() messages.success(request, 'Product saved!') return HttpResponseRedirect(reverse('commtrack_product_list', kwargs={'domain': domain})) else: form = ProductForm(product) context = { 'domain': domain, 'product': product, 'form': form, } template="commtrack/manage/product.html" return render(request, template, context)
def setUp(self): self.endpoint = MockEndpoint('http://test-api.com/', 'dummy', 'dummy') self.api_object = EWSApi(TEST_DOMAIN, self.endpoint) self.datapath = os.path.join(os.path.dirname(__file__), 'data') initial_bootstrap(TEST_DOMAIN) for product in Prod.by_domain(TEST_DOMAIN): product.delete()
def setUp(self): # might as well clean house before doing anything delete_all_xforms() delete_all_cases() self.backend = test.bootstrap(TEST_BACKEND, to_console=True) self.domain = bootstrap_domain(requisitions_enabled=self.requisitions_enabled) self.user = bootstrap_user(**MAIN_USER) self.verified_number = self.user.get_verified_number() # bootstrap additional users for requisitions self.approver = bootstrap_user(**APPROVER_USER) self.packer = bootstrap_user(**PACKER_USER) self.users = [self.user, self.approver, self.packer] # 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.save() self.loc = make_loc('loc1') self.sp = make_supply_point(self.domain.name, self.loc, owner_id=self.group._id) self.products = Product.by_domain(self.domain.name) self.assertEqual(3, len(self.products)) self.spps = {} for p in self.products: self.spps[p.code] = make_supply_point_product(self.sp, p._id) self.assertEqual(self.spps[p.code].owner_id, self.group._id)
def setUp(self): # might as well clean house before doing anything delete_all_xforms() delete_all_cases() self.backend = test.bootstrap(TEST_BACKEND, to_console=True) self.domain = bootstrap_domain(requisitions_enabled=self.requisitions_enabled) self.loc = make_loc('loc1') self.reporters = dict((k, bootstrap_user(self, **v)) for k, v in REPORTING_USERS.iteritems()) # backwards compatibility self.user = self.reporters['roaming'] # bootstrap additional users for requisitions self.approver = bootstrap_user(self, **APPROVER_USER) self.packer = bootstrap_user(self, **PACKER_USER) self.users = self.reporters.values() + [self.approver, self.packer] # 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.save() self.sp = make_supply_point(self.domain.name, self.loc, owner_id=self.group._id) self.products = Product.by_domain(self.domain.name) self.assertEqual(3, len(self.products)) self.spps = {} for p in self.products: self.spps[p.code] = make_supply_point_product(self.sp, p._id) self.assertEqual(self.spps[p.code].owner_id, self.group._id)
def setUp(self): # might as well clean house before doing anything delete_all_xforms() delete_all_cases() StockReport.objects.all().delete() StockTransaction.objects.all().delete() self.backend = test.bootstrap(TEST_BACKEND, to_console=True) self.domain = bootstrap_domain() self.ct_settings = CommtrackConfig.for_domain(self.domain.name) if self.requisitions_enabled: self.ct_settings.requisition_config = get_default_requisition_config() self.ct_settings.save() self.loc = make_loc('loc1') self.sp = make_supply_point(self.domain.name, self.loc) self.users = [bootstrap_user(self, **user_def) for user_def in self.user_definitions] if False: # bootstrap additional users for requisitions # needs to get reinserted for requisition stuff later self.approver = bootstrap_user(self, **APPROVER_USER) self.packer = bootstrap_user(self, **PACKER_USER) self.users += [self.approver, self.packer] # 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.save() self.sp.owner_id = self.group._id self.sp.save() self.products = sorted(Product.by_domain(self.domain.name), key=lambda p: p._id) self.assertEqual(3, len(self.products))
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 make_supply_point_product(supply_point_case, product_uuid, owner_id=None): domain = supply_point_case.domain id = uuid.uuid4().hex user_id = const.get_commtrack_user_id(domain) owner_id = owner_id or get_owner_id(supply_point_case) or user_id username = const.COMMTRACK_USERNAME product_name = Product.get(product_uuid).name caseblock = CaseBlock( case_id=id, create=True, version=V2, case_name=product_name, user_id=user_id, owner_id=owner_id, case_type=const.SUPPLY_POINT_PRODUCT_CASE_TYPE, update={ "product": product_uuid }, index={ const.PARENT_CASE_REF: (const.SUPPLY_POINT_CASE_TYPE, supply_point_case._id), } ) casexml = ElementTree.tostring(caseblock.as_xml()) submit_case_blocks(casexml, domain, username, user_id, xmlns=const.COMMTRACK_SUPPLY_POINT_PRODUCT_XMLNS) sppc = SupplyPointProductCase.get(id) sppc.bind_to_location(supply_point_case.location) sppc.save() return sppc
def get_default_column_data(domain, location_types): data = { 'headers': {}, 'values': {} } if Domain.get_by_name(domain).commtrack_settings.individual_consumption_defaults: products = Product.by_domain(domain) for loc_type in location_types: loc = get_loc_config(domain)[loc_type] if not loc.administrative: data['headers'][loc_type] = [ 'default_' + p.code for p in products ] locations = Location.filter_by_type(domain, loc_type) for loc in locations: sp = SupplyPointCase.get_or_create_by_location(loc) data['values'][loc._id] = [ get_default_consumption( domain, p._id, loc_type, sp._id ) or '' for p in products ] else: data['headers'][loc_type] = [] return data
def main_context(self): try: facilities = Location.filter_by_type_count(self.domain, 'FACILITY') except TypeError: facilities = 0 contacts = CommCareUser.by_domain(self.domain, reduce=True) web_users = WebUser.by_domain(self.domain, reduce=True) try: products = len(Product.by_domain(self.domain)) except ResourceNotFound: products = 0 main_context = super(GlobalStats, self).main_context context = { 'supply_points': len(list(Location.by_domain(self.domain))), 'facilities': facilities, 'contacts': contacts[0]['value'] if contacts else 0, 'web_users': web_users[0]['value'] if web_users else 0, 'products': products, #TODO add next after the enlargement ILS migration 'product_stocks': 0, 'stock_transactions': 0, 'inbound_messages': 0, 'outbound_messages': 0 } main_context.update(context) return main_context
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 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 # otherwise we use the defaults else: 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 setUp(self): self.datapath = os.path.join(os.path.dirname(__file__), 'data') self.api = MockOpenLMISEndpoint("uri://mock/lmis/endpoint", username='******', password='******') bootstrap_domain(TEST_DOMAIN) delete_all_cases() for product in Product.by_domain(TEST_DOMAIN): product.delete()
def get_default_column_data(domain, location_types): data = { 'headers': {}, 'values': {} } if Domain.get_by_name(domain).commtrack_settings.individual_consumption_defaults: products = Product.by_domain(domain) for loc_type in location_types: loc = get_loc_config(domain)[loc_type] if not loc.administrative: data['headers'][loc_type] = [ 'default_' + p.code for p in products ] locations = Location.filter_by_type(domain, loc_type) for loc in locations: sp = SupplyPointCase.get_or_create_by_location(loc) data['values'][loc._id] = [ get_default_monthly_consumption( domain, p._id, loc_type, sp._id ) or '' for p in products ] else: data['headers'][loc_type] = [] return data
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).order_by('product_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_data(self): sp_ids = get_relevant_supply_point_ids( self.domain, self.active_location ) products = Product.by_domain(self.domain) if self.program_id: products = filter( lambda product: product.program_id == self.program_id, products ) for sp_id in sp_ids: for product in products: loc = SupplyPointCase.get(sp_id).location last_transaction = StockTransaction.latest( sp_id, STOCK_SECTION_TYPE, product._id ) yield { 'loc_id': loc._id, 'loc_path': loc.path, 'name': loc.name, 'type': loc.location_type, 'reporting_status': reporting_status( last_transaction, self.start_date, self.end_date ), 'geo': loc._geopoint, }
def setUp(self): self.endpoint = MockEndpoint("http://test-api.com/", "dummy", "dummy") self.api_object = ILSGatewayAPI(TEST_DOMAIN, self.endpoint) self.datapath = os.path.join(os.path.dirname(__file__), "data") initial_bootstrap(TEST_DOMAIN) for product in Prod.by_domain(TEST_DOMAIN): product.delete()
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 get_data(self): startkey = [self.domain, self.active_location._id if self.active_location else None] product_cases = SPPCase.view('commtrack/product_cases', startkey=startkey, endkey=startkey + [{}], include_docs=True) if self.program_id: product_cases = filter(lambda c: Product.get(c.product).program_id == self.program_id, product_cases) def latest_case(cases): # getting last report date should probably be moved to a util function in a case wrapper class return max(cases, key=lambda c: getattr(c, 'last_reported', datetime(2000, 1, 1)).date()) cases_by_site = map_reduce(lambda c: [(tuple(c.location_),)], lambda v: reporting_status(latest_case(v), self.start_date, self.end_date), data=product_cases, include_docs=True) # TODO if aggregating, won't want to fetch all these locs (will only want to fetch aggregation sites) locs = dict((loc._id, loc) for loc in Location.view( '_all_docs', keys=[path[-1] for path in cases_by_site.keys()], include_docs=True)) for path, status in cases_by_site.iteritems(): loc = locs[path[-1]] yield { 'loc_id': loc._id, 'loc_path': loc.path, 'name': loc.name, 'type': loc.location_type, 'reporting_status': status, 'geo': loc._geopoint, }
def make_supply_point_product(supply_point_case, product_uuid, owner_id=None): domain = supply_point_case.domain id = uuid.uuid4().hex user_id = get_commtrack_user_id(domain) owner_id = owner_id or get_owner_id(supply_point_case) or user_id username = const.COMMTRACK_USERNAME product_name = Product.get(product_uuid).name caseblock = CaseBlock(case_id=id, create=True, version=V2, case_name=product_name, user_id=user_id, owner_id=owner_id, case_type=const.SUPPLY_POINT_PRODUCT_CASE_TYPE, update={"product": product_uuid}, index={ const.PARENT_CASE_REF: (const.SUPPLY_POINT_CASE_TYPE, supply_point_case._id), }) casexml = ElementTree.tostring(caseblock.as_xml()) submit_case_blocks(casexml, domain, username, user_id, xmlns=const.COMMTRACK_SUPPLY_POINT_PRODUCT_XMLNS) return SupplyPointProductCase.get(id)
def get_default_column_data(domain, location_types): data = { 'headers': {}, 'values': {} } if Domain.get_by_name(domain).commtrack_settings.individual_consumption_defaults: products = Product.by_domain(domain, wrap=False) for loc_type in location_types: loc = get_loc_config(domain)[loc_type] if not loc.administrative: data['headers'][loc_type] = [ 'default_' + p['code_'] for p in products ] locations = Location.filter_by_type(domain, loc_type) for loc in locations: data['values'][loc._id] = [ get_default_consumption( domain, p['_id'], loc_type, loc._id ) or '' for p in products ] else: data['headers'][loc_type] = [] return data
def submit_form(domain, parent, form_data, properties, existing, location_type, consumption): # don't save if there is nothing to save if no_changes_needed(domain, existing, properties, form_data, consumption): return { 'id': existing._id, 'message': 'no changes for %s %s' % (location_type, existing.name) } form_data.update(properties) form = make_form(domain, parent, form_data, existing) form.strict = False # optimization hack to turn off strict validation if form.is_valid(): loc = form.save() sp = SupplyPointCase.get_by_location(loc) if consumption else None if consumption and sp: for product_code, value in consumption: try: amount = Decimal(value) # only set it if there is a non-negative/non-null value if amount and amount >= 0: set_default_consumption_for_supply_point( domain, Product.get_by_code(domain, product_code)._id, sp._id, amount ) except (TypeError, InvalidOperation): # should inform user, but failing hard due to non numbers # being used on consumption is strange since the # locations would be in a very inconsistent state continue if existing: message = 'updated %s %s' % (location_type, loc.name) else: message = 'created %s %s' % (location_type, loc.name) return { 'id': loc._id, 'message': message } else: message = 'Form errors when submitting: ' # TODO move this to LocationForm somehow forms = filter(None, [form, form.sub_forms.get(location_type)]) for k, v in itertools.chain(*(f.errors.iteritems() for f in forms)): if k != '__all__': message += u'{0} {1}; {2}: {3}. '.format( location_type, form_data.get('name', 'unknown'), k, v[0] ) return { 'id': None, 'message': message }
def product_data(self): data = [] products = Product.by_domain(self.domain) for p in products: info = p._doc info['edit_url'] = reverse('commtrack_product_edit', kwargs={'domain': self.domain, 'prod_id': p._id}) data.append(info) return data
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 test_migration(self): ils_bootstrap_domain_test_task( TEST_DOMAIN, MockEndpoint('http://test-api.com/', 'dummy', 'dummy')) self.assertEqual(6, len(list(Product.by_domain(TEST_DOMAIN)))) self.assertEqual(5, len(list(Location.by_domain(TEST_DOMAIN)))) self.assertEqual(6, len(list(CommCareUser.by_domain(TEST_DOMAIN)))) self.assertEqual(5, len(list(WebUser.by_domain(TEST_DOMAIN))))
def clean_name(self): name = self.cleaned_data['name'] other_products = [p for p in Product.by_domain(self.product.domain) if p._id != self.product._id] if name in [p.name for p in other_products]: raise forms.ValidationError('name already in use') return name
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 make_product(domain, name, code): p = Product() p.domain = domain p.name = name p.code = code.lower() p.save() return p
def test_selective_product_sync(self): user = bootstrap_user(self, phone_number="1234567890") expected_xml = self.generate_product_fixture_xml(user) product_list = Product.by_domain(user.domain) self._initialize_product_names(len(product_list)) fixture_original = product_fixture_generator(user, V1, None) generate_restore_payload(user.to_casexml_user()) self.assertXmlEqual( expected_xml, ElementTree.tostring(fixture_original[0]) ) first_sync = sorted(SyncLog.view( "phone/sync_logs_by_user", include_docs=True, reduce=False ).all(), key=lambda x: x.date)[-1] # 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 = product_fixture_generator(user, V1, first_sync) generate_restore_payload(user.to_casexml_user()) self.assertEqual( [], fixture_pre_change, "Fixture was not empty on second sync" ) second_sync = sorted(SyncLog.view( "phone/sync_logs_by_user", include_docs=True, reduce=False ).all(), key=lambda x: x.date)[-1] 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 = product_fixture_generator(user, V1, second_sync) # regenerate the fixture xml to make sure it is still legit self.assertXmlEqual( expected_xml, ElementTree.tostring(fixture_post_change[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)
def test_create_product(self): with open(os.path.join(self.datapath, 'sample_products.json')) as f: product = Product(json.loads(f.read())[0]) self.assertEqual(0, len(Prod.by_domain(TEST_DOMAIN))) ilsgateway_product = self.api_object.product_sync(product) self.assertEqual(product.sms_code, ilsgateway_product.code.lower()) self.assertEqual(product.name, ilsgateway_product.name) self.assertEqual(product.description, ilsgateway_product.description) self.assertEqual(product.units, str(ilsgateway_product.unit))
def aggregated_data(self, stock_states): product_aggregation = {} for state in stock_states: if state.product_id in product_aggregation: product = product_aggregation[state.product_id] product['current_stock'] = self.format_decimal( product['current_stock'] + state.stock_on_hand ) if product['total_consumption'] is None: product['total_consumption'] = state.get_consumption() elif state.get_consumption() is not None: product['total_consumption'] += state.get_consumption() product['count'] += 1 if product['total_consumption'] is not None: product['consumption'] = product['total_consumption'] / product['count'] else: product['consumption'] = None product['category'] = stock_category( product['current_stock'], product['consumption'], Domain.get_by_name(self.domain) ) product['months_remaining'] = months_of_stock_remaining( product['current_stock'], product['consumption'] ) else: product = Product.get(state.product_id) consumption = state.get_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': self.format_decimal(state.stock_on_hand), 'total_consumption': consumption, 'count': 1, 'consumption': consumption, 'category': stock_category( state.stock_on_hand, consumption, Domain.get_by_name(self.domain) ), 'months_remaining': months_of_stock_remaining( state.stock_on_hand, consumption ) } return product_aggregation.values()
def forwards(self, orm): # sync products first properties_to_sync = [ ('product_id', '_id'), 'domain', 'name', 'is_archived', ('code', 'code_'), 'description', 'category', 'program_id', 'cost', ('units', 'unit'), 'product_data', ] product_ids = [ r['id'] for r in Product.get_db().view( 'commtrack/products', reduce=False, ).all() ] for product in iter_docs(Product.get_db(), product_ids): sql_product = SQLProduct() for prop in properties_to_sync: if isinstance(prop, tuple): sql_prop, couch_prop = prop else: sql_prop = couch_prop = prop if couch_prop in product: setattr(sql_product, sql_prop, product[couch_prop]) sql_product.save() # now update stock states for ss in StockState.include_archived.all(): ss.sql_product = SQLProduct.objects.get(product_id=ss.product_id) ss.save()
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 testCreateProgram(self): with open(os.path.join(self.datapath, 'sample_program.json')) as f: lmis_program = Program.from_json(json.loads(f.read())) # program sync self.assertEqual(0, len(Product.by_domain(TEST_DOMAIN))) commtrack_program = sync_openlmis_program(TEST_DOMAIN, lmis_program) self.assertEqual(lmis_program.name, commtrack_program.name) self.assertEqual(lmis_program.code.lower(), commtrack_program.code) # product sync self.assertEqual(len(lmis_program.products), len(Product.by_domain(TEST_DOMAIN))) lmis_product = lmis_program.products[0] product = Product.get_by_code(TEST_DOMAIN, lmis_product.code) self.assertEqual(product.code, lmis_product.code.lower()) self.assertEqual(product.name, lmis_product.name) self.assertEqual(product.description, lmis_product.description) self.assertEqual(product.unit, str(lmis_product.unit)) self.assertEqual(product.category, str(lmis_product.category))
def product_data(self): def _scrub(product_doc): product_doc['code'] = product_doc.pop('code_') return product_doc data = [] products = Product.by_program_id(domain=self.domain, prog_id=self.program_id, skip=self.skip(), limit=self.limit) for p in products: data.append(_scrub(p._doc)) return data
def save(self): for field in self.fields: val = self.cleaned_data[field] set_default_consumption_for_product( self.domain, Product.get_by_code( self.domain, field.split('_')[1] )._id, val )
def test_product_fixture(self): user = bootstrap_user(self, phone_number="1234567890") user_id = user.user_id products = '' product_list = Product.by_domain(user.domain) self._initialize_product_names(len(product_list)) for i, product in enumerate(product_list): product_id = product._id product_name = self.product_names.next() product_unit = self._random_string(20) product_code = self._random_string(20) product_description = self._random_string(20) product_category = self._random_string(20) product_program_id = self._random_string(20) product_cost = 0 if i == 0 else float('%g' % random.uniform(1, 100)) products += ''' <product id="{id}"> <name>{name}</name> <unit>{unit}</unit> <code>{code}</code> <description>{description}</description> <category>{category}</category> <program_id>{program_id}</program_id> <cost>{cost}</cost> </product> '''.format(id=product_id, name=product_name, unit=product_unit, code=product_code, description=product_description, category=product_category, program_id=product_program_id, cost=product_cost) product.name = product_name product.unit = product_unit product.code = product_code product.description = product_description product.category = product_category product.program_id = product_program_id product.cost = product_cost product.save() fixture = product_fixture_generator(user, V1, None) self.assertXmlEqual( '''<fixture id="commtrack:products" user_id="{user_id}"> <products> {products} </products> </fixture>'''.format(user_id=user_id, products=products), ElementTree.tostring(fixture[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, )
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)))