def test_get_total_won_quote_this_year04(self): "'acceptation_date' is hidden + populate_entities()" user = self.login() quote1, source1, target1 = self.create_quote_n_orgas('Quote1') quote2, source2, target2 = self.create_quote_n_orgas('Quote2') FieldsConfig.create(Quote, descriptions=[('acceptation_date', { FieldsConfig.HIDDEN: True })]) # funf = target1.function_fields.get('total_won_quote_this_year') funf = function_field_registry.get(Organisation, 'total_won_quote_this_year') FieldsConfig.get_4_model(Quote) # Fill cache with self.assertNumQueries(0): funf.populate_entities([target1, target2], user) with self.assertNumQueries(0): total1 = get_total_won_quote_this_year(target1, user) total2 = get_total_won_quote_this_year(target2, user) msg = _('Error: «Acceptation date» is hidden') self.assertEqual(msg, total1) self.assertEqual(msg, total2)
def test_get_4_models(self): model1 = FakeContact model2 = FakeOrganisation h_field1 = 'phone' h_field2 = 'url_site' create_fc = FieldsConfig.create create_fc(model1, descriptions=[(h_field1, { FieldsConfig.HIDDEN: True })]) create_fc(model2, descriptions=[(h_field2, { FieldsConfig.HIDDEN: True })]) with self.assertNumQueries(1): fconfigs = FieldsConfig.get_4_models([model1, model2]) self.assertIsInstance(fconfigs, dict) self.assertEqual(2, len(fconfigs)) fc1 = fconfigs.get(model1) self.assertIsInstance(fc1, FieldsConfig) self.assertEqual(model1, fc1.content_type.model_class()) self.assertTrue(fc1.is_fieldname_hidden(h_field1)) self.assertTrue(fconfigs.get(model2).is_fieldname_hidden(h_field2)) with self.assertNumQueries(0): FieldsConfig.get_4_models([model1, model2]) with self.assertNumQueries(0): FieldsConfig.get_4_model(model1)
def test_get_4_model01(self): model = FakeContact h_field1 = 'phone' h_field2 = 'mobile' FieldsConfig.create( model, descriptions=[ (h_field1, { FieldsConfig.HIDDEN: True }), (h_field2, { FieldsConfig.HIDDEN: True }), ], ) with self.assertNumQueries(1): fc = FieldsConfig.get_4_model(model) is_hidden = fc.is_fieldname_hidden self.assertTrue(is_hidden(h_field1)) self.assertTrue(is_hidden(h_field2)) self.assertFalse(is_hidden('description')) with self.assertNumQueries(0): # cache FieldsConfig.get_4_model(model)
def test_get_total_won_quote_last_year03(self): "'populate_entities()" user = self.login() previous_year = self.today_date - timedelta(days=365) def set_date(quote): quote.acceptation_date = previous_year quote.save() quote01, source01, target01 = self.create_quote_n_orgas( 'Quote01', status=self.won_status) quote02, source02, target02 = self.create_quote_n_orgas( 'Quote02', status=self.won_status) # Not won status => not used quote03 = self.create_quote('Quote #3', source01, target01) self.assertFalse(quote03.status.won) # Current year => not used quote04 = self.create_quote('Quote #4', source01, target02, status=self.won_status) quote04.acceptation_date = self.today_date quote04.save() set_date(quote01) set_date(quote02) set_date(quote03) self._set_managed(source01) self._set_managed(source02) self.create_line(quote01, 5000, 1) self.create_line(quote02, 4000, 1) self.create_line(quote03, 500, 1) # Not used self.create_line(quote04, 300, 1) # Not used # funf = target01.function_fields.get('total_won_quote_last_year') funf = function_field_registry.get(Organisation, 'total_won_quote_last_year') self.assertIsNotNone(funf) FieldsConfig.get_4_model(Quote) # Fill cache bool(Organisation.get_all_managed_by_creme()) # Fill cache with self.assertNumQueries(2): funf.populate_entities([target01, target02], user) with self.assertNumQueries(0): total1 = funf(target01, user).for_csv() total2 = funf(target02, user).for_csv() self.assertEqual(number_format('5000.00', use_l10n=True), total1) self.assertEqual(number_format('4000.00', use_l10n=True), total2)
def test_get_total_won_quote_this_year01(self): user = self.login() def set_date(quote): quote.acceptation_date = self.today_date quote.save() quote01, source, target = self.create_quote_n_orgas( 'Quote #1', status=self.won_status) set_date(quote01) self._set_managed(source) quote02 = self.create_quote('Quote #2', source, target, status=self.won_status) set_date(quote02) # Not won status => not used quote03 = self.create_quote('Quote #3', source, target) self.assertFalse(quote03.status.won) set_date(quote03) self.create_line(quote03, 500, 1) # Previous year => not used quote04 = self.create_quote('Quote #4', source, target, status=self.won_status) quote04.acceptation_date = self.today_date - timedelta(days=366) quote04.save() self.create_line(quote04, 300, 1) FieldsConfig.get_4_model(Quote) # Fill cache bool(Organisation.get_all_managed_by_creme()) # Fill cache with self.assertNumQueries(2): total = get_total_won_quote_this_year(target, user) self.assertEqual(0, total) self.create_line(quote01, 5000, 1) self.create_line(quote02, 1000, 1) self.assertEqual(6000, get_total_won_quote_this_year(target, user)) # funf = target.function_fields.get('total_won_quote_this_year') funf = function_field_registry.get(Organisation, 'total_won_quote_this_year') self.assertIsNotNone(funf) val = number_format('6000.00', use_l10n=True) self.assertEqual(val, funf(target, user).for_html()) self.assertEqual(val, funf(target, user).for_csv())
def persons_pretty_address(address): is_field_hidden = FieldsConfig.get_4_model(address.__class__).is_fieldname_hidden with StringIO() as sio: write = sio.write addr = '' if is_field_hidden('address') else address.address if addr: write(addr) po_box = '' if is_field_hidden('po_box') else address.po_box if po_box: if sio.tell(): write('\n') write(po_box) zipcode = '' if is_field_hidden('zipcode') else address.zipcode city = '' if is_field_hidden('city') else address.city if zipcode or city: if sio.tell(): write('\n') if not zipcode: write(city) elif not city: write(zipcode) else: write(city) write(' ') write(zipcode) return sio.getvalue()
def info_field_names(cls): is_field_hidden = FieldsConfig.get_4_model(cls).is_field_hidden excluded = {'id', 'content_type', 'object'} # TODO: just exclude not viewable ? return tuple(f.name for f in cls._meta.fields if f.name not in excluded and not is_field_hidden(f) )
def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) # TODO: should be in the view ? field_name = self.field_name if FieldsConfig.get_4_model(self._entity.__class__).is_fieldname_hidden(field_name): raise ConflictError('"{}" is hidden & so it cannot be edited'.format(field_name))
def get_merge_form_builder(model, base_form_class=_PersonMergeForm): address_field_names = [*Address.info_field_names()] # TODO: factorise with lv_import.py try: address_field_names.remove('name') except ValueError: pass attrs = {'_address_field_names': address_field_names} get_field = Address._meta.get_field fields = [get_field(field_name) for field_name in address_field_names] is_hidden = FieldsConfig.get_4_model(model).is_fieldname_hidden def add_fields(attr_name, prefix): fnames = [] if not is_hidden(attr_name): for field in fields: form_fieldname = prefix + field.name attrs[form_fieldname] = mergefield_factory(field) fnames.append(form_fieldname) return fnames billing_address_fnames = add_fields('billing_address', _BILL_PREFIX) shipping_address_fnames = add_fields('shipping_address', _SHIP_PREFIX) attrs['blocks'] = MergeEntitiesBaseForm.blocks.new( ('billing_address', _('Billing address'), billing_address_fnames), ('shipping_address', _('Shipping address'), shipping_address_fnames), ) return type('PersonMergeForm', (base_form_class,), attrs)
def test_get_total_won_quote_this_year02(self): "'acceptation_date' is hidden" user = self.login() quote, source, target = self.create_quote_n_orgas('Quote #1') FieldsConfig.create(Quote, descriptions=[('acceptation_date', {FieldsConfig.HIDDEN: True})] ) funf = function_field_registry.get(Organisation, 'total_won_quote_this_year') FieldsConfig.get_4_model(Quote) # Fill cache with self.assertNumQueries(0): total = funf(target, user).for_csv() self.assertEqual(_('Error: «Acceptation date» is hidden'), total)
def test_get_4_model03(self): "Cache not created" model = FakeContact FieldsConfig.create( model, descriptions=[('phone', { FieldsConfig.HIDDEN: True })], ) set_global_info(per_request_cache=None) with self.assertNumQueries(1): FieldsConfig.get_4_model(model) with self.assertNumQueries(0): FieldsConfig.get_4_model(model)
def finalize_recipient_field(name, model): if FieldsConfig.get_4_model(model).is_fieldname_hidden('email'): self.fields[name] = CharField( label=self.fields[name].label, required=False, widget=Label, initial=ugettext('Beware: the field «Email address» is hidden ;' ' please contact your administrator.' ), )
def test_get_total_won_quote_last_year02(self): "'acceptation_date' is hidden" user = self.login() quote, source, target = self.create_quote_n_orgas("YOLO") FieldsConfig.create(Quote, descriptions=[('acceptation_date', {FieldsConfig.HIDDEN: True})] ) quote.acceptation_date = self.today_date self._set_managed(source) FieldsConfig.get_4_model(Quote) # Fill cache with self.assertNumQueries(0): total = get_total_won_quote_last_year(target, user) self.assertEqual(_('Error: «Acceptation date» is hidden'), total)
def test_get_4_model02(self): "No query for model which cannot be registered." ContentType.objects.get_for_model(FakeCivility) # Fill cache if needed with self.assertNumQueries(0): # fc = FieldsConfig.get_4_model(CremeEntity) fc = FieldsConfig.get_4_model(FakeCivility) self.assertFalse([*fc.hidden_fields])
def content_type(self, ct): EntityCellsField.content_type.fset(self, ct) if ct is not None: builders = self._builders widget = self.widget model = ct.model_class() # Related ---------------------------------------------------------- widget.related_entities = related_choices = [] for related_name, related_vname in Report.get_related_fields_choices(model): rel_id = _RELATED_PREFIX + related_name related_choices.append((rel_id, related_vname)) builders[rel_id] = ReportHandsField._build_4_related # Aggregates ------------------------------------------------------- widget.regular_aggregates = reg_agg_choices = [] widget.custom_aggregates = cust_agg_choices = [] authorized_fields = field_aggregation_registry.authorized_fields authorized_customfields = field_aggregation_registry.authorized_customfields fconf = FieldsConfig.get_4_model(model) non_hiddable_aggnames = { cell.value for cell in self._non_hiddable_cells if cell.type_id == _EntityCellAggregate.type_id } for aggregate in field_aggregation_registry.aggregations: pattern = aggregate.pattern title = aggregate.title for f_name, f_vname in ModelFieldEnumerator( model, deep=0, ).filter( (lambda f, deep: isinstance(f, authorized_fields)), viewable=True, ).choices(): agg_name = pattern.format(f_name) if fconf.is_fieldname_hidden(f_name) and agg_name not in non_hiddable_aggnames: continue agg_id = _REGULAR_AGG_PREFIX + agg_name reg_agg_choices.append((agg_id, '{} - {}'.format(title, f_vname))) builders[agg_id] = ReportHandsField._build_4_regular_aggregate for cf in self._custom_fields: if cf.field_type in authorized_customfields: agg_id = _CUSTOM_AGG_PREFIX + pattern.format(cf.id) cust_agg_choices.append((agg_id, '{} - {}'.format(title, cf.name))) builders[agg_id] = ReportHandsField._build_4_custom_aggregate
def get_total_won_quote_last_year(entity, user): if FieldsConfig.get_4_model(Quote).is_fieldname_hidden('acceptation_date'): return ugettext('Error: «Acceptation date» is hidden') return sum_totals_no_vat( Quote, entity, user, status__won=True, acceptation_date__year=datetime.date.today().year - 1, )
def get_total_won_quote_this_year(entity, user): # TODO: factorise (decorator in creme_core ?) if FieldsConfig.get_4_model(Quote).is_fieldname_hidden('acceptation_date'): return ugettext('Error: «Acceptation date» is hidden') return sum_totals_no_vat( Quote, entity, user, status__won=True, acceptation_date__year=datetime.date.today().year, )
def get_total_won_quote_this_year_multi(entities, user): # TODO: factorise if FieldsConfig.get_4_model(Quote).is_fieldname_hidden('acceptation_date'): msg = ugettext('Error: «Acceptation date» is hidden') return ((entity, msg) for entity in entities) return sum_totals_no_vat_multi( Quote, entities, user, status__won=True, acceptation_date__year=datetime.date.today().year, )
def test_get_weighted_sales02(self): "With field 'estimated_sales' hidden with FieldsConfig" user = self.login() FieldsConfig.create(Opportunity, descriptions=[('estimated_sales', { FieldsConfig.HIDDEN: True })]) opportunity = self._create_opportunity_n_organisations()[0] FieldsConfig.get_4_model(Opportunity) # with self.assertNumQueries(0): # w_sales = opportunity.get_weighted_sales() # # self.assertEqual(_('Error: «Estimated sales» is hidden'), w_sales) funf = function_field_registry.get(Opportunity, 'get_weighted_sales') with self.assertNumQueries(0): w_sales = funf(opportunity, user).for_html() self.assertEqual(_('Error: «Estimated sales» is hidden'), w_sales)
def set_default(request, payment_information_id, billing_id): pi = get_object_or_404(PaymentInformation, pk=payment_information_id) # billing_doc = get_object_or_404(CremeEntity, pk=billing_id).get_real_entity() entity = get_object_or_404(CremeEntity.objects.select_for_update(), pk=billing_id) user = request.user real_model = entity.entity_type.model_class() # if not isinstance(billing_doc, (billing.get_invoice_model(), billing.get_quote_model(), # billing.get_sales_order_model(), billing.get_credit_note_model(), # billing.get_template_base_model(), # ) # ): if real_model not in {billing.get_invoice_model(), billing.get_quote_model(), billing.get_sales_order_model(), billing.get_credit_note_model(), billing.get_template_base_model(), }: raise Http404('This entity is not a billing document') # if FieldsConfig.get_4_model(billing_doc.__class__).is_fieldname_hidden('payment_info'): if FieldsConfig.get_4_model(real_model).is_fieldname_hidden('payment_info'): raise ConflictError('The field "payment_info" is hidden.') billing_doc = entity.get_real_entity() organisation = pi.get_related_entity() user.has_perm_to_view_or_die(organisation) user.has_perm_to_link_or_die(organisation) user.has_perm_to_change_or_die(billing_doc) inv_orga_source = billing_doc.get_source() if not inv_orga_source or inv_orga_source.id != organisation.id: raise Http404('No organisation in this invoice.') billing_doc.payment_info = pi billing_doc.save() return {}
def get_massimport_form_builder(header_dict, choices, model, base_form=_PersonMassImportForm): address_field_names = [*Address.info_field_names() ] # TODO: remove not-editable fields ?? try: address_field_names.remove('name') except ValueError: pass attrs = {'_address_field_names': address_field_names} get_field = Address._meta.get_field fields = [get_field(field_name) for field_name in address_field_names] is_hidden = FieldsConfig.get_4_model(model).is_fieldname_hidden def add_fields(attr_name, prefix): fnames = [] hidden = is_hidden(attr_name) if not hidden: for field in fields: form_fieldname = prefix + field.name attrs[form_fieldname] = extractorfield_factory( field, header_dict, choices) fnames.append(form_fieldname) attrs['_{}_hidden'.format(attr_name)] = hidden return fnames billing_address_fnames = add_fields('billing_address', _BILL_PREFIX) shipping_address_fnames = add_fields('shipping_address', _SHIP_PREFIX) attrs['blocks'] = ImportForm4CremeEntity.blocks.new( ('billing_address', _('Billing address'), billing_address_fnames), ('shipping_address', _('Shipping address'), shipping_address_fnames)) return type('PersonMassImportForm', (base_form, ), attrs)
def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) instance = self.instance selected_fnames = [sf.name for sf in instance.searchfields] # TODO: work with Fields instead of Field names + split()... not_hiddable_fnames = OrderedSet( fname.split('__', 1)[0] for fname in selected_fnames) is_hidden = FieldsConfig.get_4_model( instance.content_type.model_class()).is_fieldname_hidden def keep_field(name): root_name = name.split('__', 1)[0] return not is_hidden(root_name) or root_name in not_hiddable_fnames fields_f = self.fields['fields'] fields_f.choices = [ choice for choice in self.instance.get_modelfields_choices() if keep_field(choice[0]) ] fields_f.initial = selected_fnames
def post(self, request, *args, **kwargs): pi = self.get_payment_information() billing_doc = self.get_related_entity() if FieldsConfig.get_4_model(type(billing_doc))\ .is_fieldname_hidden(self.payment_info_fk): raise ConflictError('The field "{}" is hidden.'.format( self.payment_info_fk)) user = request.user organisation = pi.get_related_entity() user.has_perm_to_view_or_die(organisation) user.has_perm_to_link_or_die(organisation) source = billing_doc.get_source() if not source or source.id != organisation.id: raise ConflictError('The related organisation does not match.') billing_doc.payment_info = pi billing_doc.save() return HttpResponse()
def __call__(self, entity, user): is_hidden = FieldsConfig.get_4_model( entity.__class__).is_fieldname_hidden # if is_hidden('estimated_sales'): # value = gettext('Error: «Estimated sales» is hidden') # elif is_hidden('chance_to_win'): # value = gettext(r'Error: «% of chance to win» is hidden') # else: # value = (entity.estimated_sales or 0) * (entity.chance_to_win or 0) / 100.0 # # return self.result_type(value) if is_hidden('estimated_sales'): return FunctionFieldResult( gettext('Error: «Estimated sales» is hidden')) if is_hidden('chance_to_win'): return FunctionFieldResult( gettext(r'Error: «% of chance to win» is hidden')) return self.result_type((entity.estimated_sales or 0) * (entity.chance_to_win or 0) / 100.0)
def __init__(self, contact): is_hidden = FieldsConfig.get_4_model( contact.__class__).is_fieldname_hidden def get_field_value(fname, default=None): return default if is_hidden(fname) else getattr( contact, fname, default) self.first_name = get_field_value('first_name', None) or '' self.last_name = get_field_value('last_name', '') self.civility = get_field_value('civility') self.phone = get_field_value('phone') self.mobile = get_field_value('mobile') self.fax = get_field_value('fax') self.email = get_field_value('email') self.url = get_field_value('url_site') # TODO: manage several employers self.employer = contact.get_employers().first() self._address_field_names = {*Address.info_field_names()} self.addresses = Address.objects.filter( object_id=contact.id).order_by('id')
def test_get_4_model02(self): "No query for model which cannot be registered" with self.assertNumQueries(0): fc = FieldsConfig.get_4_model(CremeEntity) self.assertFalse(list(fc.hidden_fields))
def __call__(self): stats = [] opp_model = self.opp_model if FieldsConfig.get_4_model(opp_model).is_fieldname_hidden( 'closing_date'): stats.append(str(self.invalid_message)) else: # TODO: use this previous code when there is only one managed organisation ?? # # filter_opp = partial( # # opp_model.objects.filter, # # relations__type_id=self.relation_type_id, # # closing_date__gte=date.today().replace(month=1, day=1), # # ) # # for orga in self.orga_model.get_all_managed_by_creme(): # # won_count = filter_opp(sales_phase__won=True, # # relations__object_entity_id=orga.id, # # ).count() # # lost_count = filter_opp(sales_phase__lost=True, # # relations__object_entity_id=orga.id, # # ).count() # # agg = opp_model.objects \ # .annotate(relations_w_orga=FilteredRelation( # 'relations', # condition=Q(relations__object_entity_id=orga.id) # ) # ) \ # .filter(relations_w_orga__type_id=self.relation_type_id, # closing_date__gte=date.today().replace(month=1, day=1), # )\ # .aggregate( # won=Count('pk', filter=Q(sales_phase__won=True)), # lost=Count('pk', filter=Q(sales_phase__lost=True)), # ) # won_count = agg['won'] # lost_count = agg['lost'] # # if won_count or lost_count: # stats.append( # self.message_format.format( # organisation=orga, # won_stats=ungettext('{count} won opportunity', # '{count} won opportunities', # won_count # ).format(count=won_count), # lost_stats=ungettext('{count} lost opportunity', # '{count} lost opportunities', # lost_count # ).format(count=lost_count), # ) # ) # TODO: query by chunks if there are lots of managed Organisation ? mngd_orgas = [*self.orga_model.objects.filter_managed_by_creme()] mngd_orga_ids = [o.id for o in mngd_orgas] agg_kwargs = {} for orga_id in mngd_orga_ids: agg_kwargs['won_{}'.format(orga_id)] = Count( 'relations_w_orga__object_entity_id', filter=Q( relations_w_orga__object_entity=orga_id, sales_phase__won=True, ), ) agg_kwargs['lost_{}'.format(orga_id)] = Count( 'relations_w_orga__object_entity_id', filter=Q( relations_w_orga__object_entity=orga_id, sales_phase__lost=True, ), ) agg = opp_model.objects \ .annotate(relations_w_orga=FilteredRelation( 'relations', condition=Q(relations__object_entity_id__in=mngd_orga_ids), )).filter( relations_w_orga__type_id=self.relation_type_id, closing_date__gte=date.today().replace(month=1, day=1), ).aggregate(**agg_kwargs) for orga in mngd_orgas: orga_id = orga.id won_count = agg['won_{}'.format(orga_id)] lost_count = agg['lost_{}'.format(orga_id)] if won_count or lost_count: stats.append( self.message_format.format( organisation=orga, won_stats=ngettext( '{count} won opportunity', '{count} won opportunities', won_count).format(count=won_count), lost_stats=ngettext( '{count} lost opportunity', '{count} lost opportunities', lost_count).format(count=lost_count), )) return stats