Пример #1
0
    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)))
Пример #2
0
    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
Пример #3
0
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)
Пример #4
0
    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
Пример #5
0
    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()
Пример #7
0
    def test_delete(self):
        # assign some product to the new program
        self.products[0].program_id = self.new_program._id
        self.products[0].save()

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

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

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

        self.assertEqual(
            1,
            len(Program.by_domain(self.domain.name))
        )
        self.assertEqual(
            3,
            Product.by_program_id(self.domain.name, self.default_program._id).count()
        )
        self.assertEqual(
            self.default_program._id,
            Product.get(self.products[0]._id).program_id
        )
        self.assertEqual(
            self.default_program._id,
            SQLProduct.objects.get(product_id=self.products[0]._id).program_id
        )
Пример #8
0
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
Пример #9
0
 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)
Пример #10
0
 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)
Пример #11
0
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))
Пример #13
0
 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
Пример #14
0
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
Пример #15
0
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)
Пример #16
0
 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()
Пример #17
0
    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)
Пример #18
0
    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)
Пример #19
0
    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))
Пример #20
0
    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]
Пример #21
0
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
Пример #22
0
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
Пример #23
0
    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
Пример #24
0
 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
Пример #25
0
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"
Пример #26
0
    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):
     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()
Пример #28
0
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
Пример #29
0
    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
Пример #30
0
    def get_prod_data(self):
        sp_ids = get_relevant_supply_point_ids(self.domain, self.active_location)

        stock_states = StockState.objects.filter(case_id__in=sp_ids).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'],
            ]
Пример #31
0
    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,
                }
Пример #32
0
 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()
Пример #33
0
    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]
Пример #34
0
    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,
            }
Пример #35
0
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)
Пример #36
0
 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
Пример #37
0
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
Пример #38
0
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
        }
Пример #39
0
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
        }
Пример #40
0
 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
Пример #41
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)
Пример #42
0
 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))))
Пример #43
0
    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
Пример #44
0
def delivery_update(requisition_cases, openlmis_endpoint):
    order_id = requisition_cases[0].get_case_property("order_id")
    products = []
    for rec in requisition_cases:
        product = Product.get(rec.product_id)
        products.append({'productCode': product.code, 'quantityReceived': rec.amount_received})
    delivery_data = {'podLineItems': products}
    return openlmis_endpoint.confirm_delivery(order_id, delivery_data)
Пример #45
0
def make_product(domain, name, code):
    p = Product()
    p.domain = domain
    p.name = name
    p.code = code.lower()
    p.save()
    return p
Пример #46
0
    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])
        )
Пример #47
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)
Пример #48
0
 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))
Пример #49
0
    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()
Пример #50
0
    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))
Пример #53
0
    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
Пример #54
0
 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
         )
Пример #55
0
    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]))
Пример #56
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,
         )
Пример #57
0
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)))