def show_excerpts(severe=True): ses = rt.login() # dd.logger.info("20141029 %s", settings.SITE) coll = {} def collect(obj): l = coll.setdefault(obj.excerpt_type, []) if len(l) > 2: return try: rv = ses.run(obj.do_print) except Warning as e: return if rv['success']: pass # print("\n\n%s\n\n" % rv['open_url']) else: if severe: raise Exception("Oops: %s" % rv['message']) else: return if not 'open_url' in rv: if severe: raise Exception("Oops: %s" % rv['message']) else: return # tmppath = settings.SITE.project_dir + rv['open_url'] tmppath = settings.SITE.cache_dir if not 'media' in rv['open_url']: # if not tmppath.endswith('media'): tmppath = tmppath.child('media') tmppath += rv['open_url'] head, tail = os.path.split(tmppath) # tail = 'tested/' + tail tail = 'dl/excerpts/' + tail kw = dict(tail=tail) kw.update(type=obj.excerpt_type) kw.update(owner=obj.owner) try: # dd.logger.info("20141029 copy %s to %s", tmppath, tail) shutil.copyfile(tmppath, tail) except IOError as e: kw.update(error=str(e)) msg = "%(type)s %(owner)s %(tail)s Oops: %(error)s" % kw # raise Exception(msg) kw.update(owner=msg) l.append(kw) for o in rt.models.excerpts.Excerpt.objects.order_by('excerpt_type'): collect(o) def asli(et, items): s = str(et) s += " : " + ', '.join( "`%(owner)s <../%(tail)s>`__" % kw % kw for kw in items) return s return rstgen.ul([asli(k, v) for k, v in coll.items()])
def handle(self, *args, **options): settings.SITE.startup() ar = rt.login() # fn = rt.find_config_file("status.jinja.rst", "jinja") fn = "jinja/status.jinja.rst" context = ar.get_printable_context() print(dd.plugins.jinja.render_jinja(ar, fn, context))
def show_excerpts(severe=True): ses = rt.login() # dd.logger.info("20141029 %s", settings.SITE) coll = {} def collect(obj): l = coll.setdefault(obj.excerpt_type, []) if len(l) > 2: return try: rv = ses.run(obj.do_print) except Warning as e: return if rv['success']: pass # print("\n\n%s\n\n" % rv['open_url']) else: if severe: raise Exception("Oops: %s" % rv['message']) else: return if not 'open_url' in rv: if severe: raise Exception("Oops: %s" % rv['message']) else: return # tmppath = settings.SITE.project_dir + rv['open_url'] tmppath = settings.SITE.cache_dir if not 'media' in rv['open_url']: # if not tmppath.endswith('media'): tmppath = tmppath.child('media') tmppath += rv['open_url'] head, tail = os.path.split(tmppath) # tail = 'tested/' + tail tail = 'dl/excerpts/' + tail kw = dict(tail=tail) kw.update(type=obj.excerpt_type) kw.update(owner=obj.owner) try: # dd.logger.info("20141029 copy %s to %s", tmppath, tail) shutil.copyfile(tmppath, tail) except IOError as e: kw.update(error=str(e)) msg = "%(type)s %(owner)s %(tail)s Oops: %(error)s" % kw # raise Exception(msg) kw.update(owner=msg) l.append(kw) for o in rt.models.excerpts.Excerpt.objects.order_by('excerpt_type'): collect(o) def asli(et, items): s = str(et) s += " : " + ', '.join("`%(owner)s <../%(tail)s>`__" % kw % kw for kw in items) return s return rstgen.ul([asli(k, v) for k, v in coll.items()])
def send_summary_emails(cls, mm): qs = cls.objects.filter(sent__isnull=True) qs = qs.exclude(user__email='') qs = qs.filter(mail_mode=mm).order_by('user') if qs.count() == 0: return from lino.core.renderer import MailRenderer ar = rt.login(renderer=MailRenderer()) context = ar.get_printable_context() sender = settings.SERVER_EMAIL template = rt.get_template('notify/summary.eml') users = dict() for obj in qs: lst = users.setdefault(obj.user, []) lst.append(obj) dd.logger.debug( "Send out %s summaries for %d users.", mm, len(users)) for user, messages in users.items(): with translation.override(user.language): if len(messages) == 1: subject = messages[0].subject else: subject = _("{} notifications").format(len(messages)) subject = settings.EMAIL_SUBJECT_PREFIX + subject context.update(user=user, messages=messages) body = template.render(**context) # dd.logger.debug("20170112 %s", body) rt.send_email(subject, sender, body, [user.email]) for msg in messages: msg.sent = timezone.now() msg.save()
def objects(): ses = rt.login('wilfried') dd.plugins.b2c.import_statements_path = HERE settings.SITE.site_config.import_b2c(ses) # That file contains a few dozen of accounts which are now # "orphaned". We are now going to assign theses accounts to a # random partner TODO: find a more realistic rule for selecting # the candidates. The filter might be a plugin attribute. IA = rt.modules.b2c.Account SA = rt.modules.sepa.Account PARTNERS = Cycler(rt.modules.contacts.Partner.objects.all()) count = 0 for ia in IA.objects.all(): try: SA.objects.get(iban=ia.iban) except SA.DoesNotExist: yield SA(partner=PARTNERS.pop(), iban=ia.iban) count += 1 if count == 0: dd.logger.info("%d statements", rt.modules.b2c.Statement.objects.count()) raise Exception( "There's something wrong: no accounts have been imported")
def objects(): ExcerptType = rt.modules.excerpts.ExcerptType Excerpt = rt.modules.excerpts.Excerpt if not dd.plugins.excerpts.responsible_user: return ses = rt.login(dd.plugins.excerpts.responsible_user) for et in ExcerptType.objects.all(): model = et.content_type.model_class() if issubclass(model, Certifiable): qs = model.get_printable_demo_objects(et) else: qs = model.objects.all() if qs.count() > 0: qs = [qs[0]] for obj in qs: ses.selected_rows = [obj] yield et.get_or_create_excerpt(ses) # qs2 = Excerpt.objects.filter(excerpt_type=et) # if qs2.count() == 0: # if qs.count() > 0: # ses.selected_rows = [qs[0]] # yield et.get_or_create_excerpt(ses) for obj in Excerpt.objects.all(): # dd.logger.info("20150526 rendering %s", obj) rv = ses.run(obj.do_print) assert rv['success']
def objects(): # vt = dd.plugins.invoicing.get_voucher_type() # jnl_list = vt.get_journals() # if len(jnl_list) == 0: # return from lino_cosi.lib.ledger.roles import LedgerStaff accountants = LedgerStaff.get_user_profiles() users = rt.models.users.User.objects.filter( language=dd.get_default_language(), profile__in=accountants) if users.count() == 0: return ses = rt.login(users[0].username) Plan = rt.modules.invoicing.Plan # we don't write invoices the last two months because we want to # have something in our invoicing plan. today = datetime.date(dd.plugins.ledger.start_year, 1, 1) while today < dd.demo_date(-60): plan = Plan.start_plan(ses.get_user(), today=today) yield plan plan.fill_plan(ses) # for i in plan.items.all()[:9]: for i in plan.items.all(): obj = i.create_invoice(ses) assert obj is not None yield obj today = DurationUnits.months.add_duration(today, 1)
def objects(): ses = rt.login('wilfried') dd.plugins.b2c.import_statements_path = HERE settings.SITE.site_config.import_b2c(ses) # That file contains a few dozen of accounts which are now # "orphaned". We are now going to assign theses accounts to a # random partner TODO: find a more realistic rule for selecting # the candidates. The filter might be a plugin attribute. IA = rt.modules.b2c.Account SA = rt.modules.sepa.Account PARTNERS = Cycler(rt.modules.contacts.Partner.objects.all()) count = 0 for ia in IA.objects.all(): try: SA.objects.get(iban=ia.iban) except SA.DoesNotExist: yield SA(partner=PARTNERS.pop(), iban=ia.iban) count += 1 if count == 0: dd.logger.info( "%d statements", rt.modules.b2c.Statement.objects.count()) raise Exception( "There's something wrong: no accounts have been imported")
def objects(): # vt = dd.plugins.invoicing.get_voucher_type() # jnl_list = vt.get_journals() # if len(jnl_list) == 0: # return from lino_xl.lib.ledger.roles import LedgerStaff accountants = LedgerStaff.get_user_profiles() users = rt.models.users.User.objects.filter( language=dd.get_default_language(), user_type__in=accountants) if users.count() == 0: return ses = rt.login(users.first().username) for area in Area.objects.all(): today = datetime.date(dd.plugins.ledger.start_year, 1, 1) while today < dd.demo_date(-60): plan = Plan.run_start_plan(ses.get_user(), today=today, area=area) yield plan plan.fill_plan(ses) # for i in plan.items.all()[:9]: for i in plan.items.all(): obj = i.create_invoice(ses) if obj is not None: yield obj else: msg = "create_invoice failed for {}".format(i) raise Exception(msg) # dd.logger.warning(msg) # return today = DurationUnits.months.add_duration(today, 1)
def send_summary_emails(cls, mm): """Send summary emails for all pending notifications with the given mail_mode `mm`. """ qs = cls.objects.filter(sent__isnull=True) qs = qs.exclude(user__email='') qs = qs.filter(mail_mode=mm).order_by('user') if qs.count() == 0: return from lino.core.renderer import MailRenderer ar = rt.login(renderer=MailRenderer()) context = ar.get_printable_context() sender = settings.SERVER_EMAIL template = rt.get_template('notify/summary.eml') users = dict() for obj in qs: lst = users.setdefault(obj.user, []) lst.append(obj) dd.logger.debug("Send out %s summaries for %d users.", mm, len(users)) for user, messages in users.items(): with translation.override(user.language): if len(messages) == 1: subject = messages[0].subject else: subject = _("{} notifications").format(len(messages)) subject = settings.EMAIL_SUBJECT_PREFIX + subject context.update(user=user, messages=messages) body = template.render(**context) # dd.logger.debug("20170112 %s", body) rt.send_email(subject, sender, body, [user.email]) for msg in messages: msg.sent = timezone.now() msg.save()
def objects(): Member = rt.modules.households.Member MemberRoles = rt.modules.households.MemberRoles # Household = resolve_model('households.Household') Person = resolve_model(dd.plugins.households.person_model) Type = resolve_model('households.Type') MEN = Cycler(Person.objects.filter(gender=dd.Genders.male).order_by('-id')) WOMEN = Cycler( Person.objects.filter(gender=dd.Genders.female).order_by('-id')) TYPES = Cycler(Type.objects.all()) ses = rt.login() for i in range(5): pv = dict(head=MEN.pop(), partner=WOMEN.pop(), type=TYPES.pop()) ses.run(Person.create_household, action_param_values=pv) # yield ses.response['data_record'] # he = MEN.pop() # she = WOMEN.pop() # fam = Household(name=he.last_name + "-" + she.last_name, type_id=3) # yield fam # yield Member(household=fam, person=he, role=Role.objects.get(pk=1)) # yield Member(household=fam, person=she, role=Role.objects.get(pk=2)) i = 0 for m in Member.objects.filter(role=MemberRoles.head): i += 1 if i % 3 == 0: m.end_date = i2d(20020304) yield m pv = dict(head=m.person, partner=WOMEN.pop(), type=TYPES.pop()) ses.run(Person.create_household, action_param_values=pv)
def test_create_entry(self): """# cal.MyEntries.insert({'requesting_panel': u'ext-comp-3913', 'user': u'luc'}) """ ses = rt.login("robin", renderer=dd.plugins.extjs.renderer) ba = rt.models.cal.MyEntries.get_action_by_name('submit_insert') # a = rt.models.cal.MyEntries.submit_insert # ba = rt.models.cal.MyEntries.insert_action pv = dict(user=ses.get_user()) resp = ses.run(ba, param_values=pv) # ba.request_from(ses).run_from_ui(ses) self.assertEqual(sorted(resp.keys()), [ 'close_window', 'data_record', 'detail_handler_name', 'info_message', 'message', 'refresh_all', 'rows', 'success']) # self.assertEqual(resp['data_record'].keys(), None) # The return message is of style 'Event "Event #69 (23.10.2014 # 15:42)" has been created.' The start_time is the real time # runtime and thus not predictable. So we retrieve the # created object and use it to build that message: pk = resp['data_record']['id'] obj = rt.models.cal.Event.objects.get(pk=pk) msg = 'Calendar entry "{0}" has been created.'.format(obj) self.assertEqual(resp['message'], msg)
def objects(): # vt = dd.plugins.invoicing.get_voucher_type() # jnl_list = vt.get_journals() # if len(jnl_list) == 0: # return from lino_xl.lib.ledger.roles import LedgerStaff accountants = LedgerStaff.get_user_profiles() users = rt.models.users.User.objects.filter( language=dd.get_default_language(), user_type__in=accountants) if users.count() == 0: return ses = rt.login(users[0].username) Plan = rt.models.invoicing.Plan # we don't write invoices the last two months because we want to # have something in our invoicing plan. today = datetime.date(dd.plugins.ledger.start_year, 1, 1) while today < dd.demo_date(-60): plan = Plan.start_plan(ses.get_user(), today=today) yield plan plan.fill_plan(ses) # for i in plan.items.all()[:9]: for i in plan.items.all(): obj = i.create_invoice(ses) if obj is not None: yield obj else: msg = "create_invoice failed for {}".format(i) raise Exception(msg) # dd.logger.warning(msg) # return today = DurationUnits.months.add_duration(today, 1)
def test_dupable_hidden(self): """Since `dupable_clients` is hidden, we can create duplicate partners without warning. """ Client = rt.models.pcsw.Client User = settings.SITE.user_model User(username='******', user_type=UserTypes.admin).save() Client(first_name="First", last_name="Last").save() data = dict(an="submit_insert") data.update(first_name="First") data.update(last_name="Last") data.update(genderHidden="M") data.update(gender="Male") self.client.force_login(rt.login("robin").user) response = self.client.post('/api/pcsw/Clients', data=data, REMOTE_USER="******") result = self.check_json_result( response, "detail_handler_name data_record rows " "close_window success message navinfo") self.assertEqual(result['success'], True) self.assertEqual( result['message'], 'B\xe9n\xe9ficiaire "LAST First (101)" a \xe9t\xe9 cr\xe9\xe9')
def finalize(self): if len(self.duplicate_zip_codes): for country, codes in self.duplicate_zip_codes.items(): dd.logger.warning( "%d duplicate zip codes in %s : %s", len(codes), country, ', '.join(codes)) if self.ROOT is None: return ses = rt.login(self.ROOT.username) Journal = rt.models.ledger.Journal dd.logger.info("Register %d vouchers", len(self.must_register)) failures = 0 for doc in progress.bar(self.must_register): # puts("Registering {0}".format(doc)) try: doc.register(ses) except Exception as e: dd.logger.warning("Failed to register %s : %s ", doc, e) failures += 1 if failures > 100: dd.logger.warning("Abandoned after 100 failures.") break # Given a string `ms` of type 'VKR940095', locate the corresponding # movement. dd.logger.info("Resolving %d matches", len(self.must_match)) for ms, lst in self.must_match.items(): for (voucher, matching) in lst: if matching.pk is None: dd.logger.warning("Ignored match %s in %s (pk is None)" % ( ms, matching)) continue idjnl, iddoc = ms[:3], ms[3:] try: year, num = year_num(iddoc) except ValueError as e: dd.logger.warning("Ignored match %s in %s (%s)" % ( ms, matching, e)) try: jnl = Journal.objects.get(ref=idjnl) except Journal.DoesNotExist: dd.logger.warning("Ignored match %s in %s (invalid JNL)" % ( ms, matching)) continue qs = Movement.objects.filter( voucher__journal=jnl, voucher__number=num, voucher__year=year, partner__isnull=False) if qs.count() == 0: dd.logger.warning("Ignored match %s in %s (no movement)" % ( ms, matching)) continue matching.match = qs[0] matching.save() voucher.deregister(ses) voucher.register(ses)
def finalize(self): if len(self.duplicate_zip_codes): for country, codes in self.duplicate_zip_codes.items(): dd.logger.warning("%d duplicate zip codes in %s : %s", len(codes), country, ', '.join(codes)) if self.ROOT is None: return ses = rt.login(self.ROOT.username) Journal = rt.models.ledger.Journal dd.logger.info("Register %d vouchers", len(self.must_register)) failures = 0 for doc in progress.bar(self.must_register): # puts("Registering {0}".format(doc)) try: doc.register(ses) except Exception as e: dd.logger.warning("Failed to register %s : %s ", doc, e) failures += 1 if failures > 100: dd.logger.warning("Abandoned after 100 failures.") break # Given a string `ms` of type 'VKR940095', locate the corresponding # movement. dd.logger.info("Resolving %d matches", len(self.must_match)) for ms, lst in self.must_match.items(): for (voucher, matching) in lst: if matching.pk is None: dd.logger.warning("Ignored match %s in %s (pk is None)" % (ms, matching)) continue idjnl, iddoc = ms[:3], ms[3:] try: year, num = year_num(iddoc) except ValueError as e: dd.logger.warning("Ignored match %s in %s (%s)" % (ms, matching, e)) try: jnl = Journal.objects.get(ref=idjnl) except Journal.DoesNotExist: dd.logger.warning("Ignored match %s in %s (invalid JNL)" % (ms, matching)) continue qs = Movement.objects.filter(voucher__journal=jnl, voucher__number=num, voucher__year=year, partner__isnull=False) if qs.count() == 0: dd.logger.warning("Ignored match %s in %s (no movement)" % (ms, matching)) continue matching.match = qs[0] matching.save() voucher.deregister(ses) voucher.register(ses)
def test_makecopy(self): UserTypes = rt.models.users.UserTypes Partner = rt.models.contacts.Partner Account = rt.models.ledger.Account AnaAccountInvoice = rt.models.ana.AnaAccountInvoice jnl = rt.models.ledger.Journal.objects.get(ref="PRC") # acc = rt.models.ledger.Account.objects.get(ref="PRC") user = create_row(rt.models.users.User, username="******", user_type=UserTypes.admin) ses = rt.login('robin', renderer=TestRenderer()) partner = create_row(Partner, name="Foo") self.assertEqual(AnaAccountInvoice.objects.count(), 0) invoice = jnl.create_voucher(partner=partner, user=user) self.assertEqual(invoice.__class__, AnaAccountInvoice) invoice.full_clean() invoice.save() ga = Account.objects.filter( needs_ana=True, ana_account__isnull=False).order_by('ref')[0] for n in range(3): i = invoice.add_voucher_item( account=ga, seqno=3 - n, # enter them in reverse order to reproduce # #2470 total_incl=123 + n) i.full_clean() i.save() s = ses.show('ana.ItemsByInvoice', invoice, column_names="seqno account total_incl") # print(s) expected = """\ ==================== ============================= ================= No. Account Total incl. VAT -------------------- ----------------------------- ----------------- 1 (6010) Purchase of services 125,00 2 (6010) Purchase of services 124,00 3 (6010) Purchase of services 123,00 **Total (3 rows)** **372,00** ==================== ============================= ================= """ self.assertEqual(s, expected) self.assertEqual(AnaAccountInvoice.objects.count(), 1) self.assertEqual(invoice.number, 1) invoice.make_copy.run_from_session(ses) self.assertEqual(AnaAccountInvoice.objects.count(), 2) invoice = AnaAccountInvoice.objects.get(number=2) s = ses.show('ana.ItemsByInvoice', invoice, column_names="seqno account total_incl") # print(s) self.assertEqual(s, expected)
def objects(): ses = rt.login() Client = rt.modules.pcsw.Client CLIENTS = Cycler(Client.objects.all()) for obj in lino_objects(): if obj.__class__.__name__ == "Event": if obj.event_type.invite_client: obj.project = CLIENTS.pop() yield obj obj.update_guests.run_from_code(ses)
def test_makecopy(self): UserTypes = rt.models.users.UserTypes Partner = rt.models.contacts.Partner Account = rt.models.ledger.Account AnaAccountInvoice = rt.models.ana.AnaAccountInvoice jnl = rt.models.ledger.Journal.objects.get(ref="PRC") # acc = rt.models.ledger.Account.objects.get(ref="PRC") user = create_row(rt.models.users.User, username="******", user_type=UserTypes.admin) ses = rt.login('robin', renderer=TestRenderer()) partner = create_row(Partner, name="Foo") self.assertEqual(AnaAccountInvoice.objects.count(), 0) invoice = jnl.create_voucher(partner=partner, user=user) self.assertEqual( invoice.__class__, AnaAccountInvoice) invoice.full_clean() invoice.save() ga = Account.objects.filter( needs_ana=True, ana_account__isnull=False).order_by('ref')[0] for n in range(3): i = invoice.add_voucher_item( account=ga, seqno=3-n, # enter them in reverse order to reproduce # #2470 total_incl=123+n) i.full_clean() i.save() s = ses.show('ana.ItemsByInvoice', invoice, column_names="seqno account total_incl") # print(s) expected = """\ ==================== ============================= ================= No. Account Total incl. VAT -------------------- ----------------------------- ----------------- 1 (6010) Purchase of services 125,00 2 (6010) Purchase of services 124,00 3 (6010) Purchase of services 123,00 **Total (3 rows)** **372,00** ==================== ============================= ================= """ self.assertEqual(s, expected) self.assertEqual(AnaAccountInvoice.objects.count(), 1) self.assertEqual(invoice.number, 1) invoice.make_copy.run_from_session(ses) self.assertEqual(AnaAccountInvoice.objects.count(), 2) invoice = AnaAccountInvoice.objects.get(number=2) s = ses.show('ana.ItemsByInvoice', invoice, column_names="seqno account total_incl") # print(s) self.assertEqual(s, expected)
def objects(): yield rt.login('alicia').get_user() if False: # done in lino_welfare/modlib/integ/fixtures/ TT = Cycler(rt.modules.immersion.ContractType.objects.all()) TG = Cycler(rt.modules.immersion.Goal.objects.all()) Training = rt.modules.immersion.Contract alicia = rt.login('alicia').get_user() selected_clients = (131, 149, 161) for i, pk in enumerate(selected_clients): kw = dict(client_id=pk) kw.update(type=TT.pop()) kw.update(user=alicia) kw.update(goal=TG.pop()) kw.update(applies_from=dd.demo_date(i*30)) kw.update(applies_until=dd.demo_date(i*30+60*(i+1))) yield Training(**kw)
def objects(): yield lib_objects() SECTIONS = Cycler(rt.models.courses.Sections.objects()) for obj in rt.models.courses.Pupil.objects.order_by('id'): if obj.id % 5 == 0: obj.is_lfv = True if obj.id % 6 == 0: obj.is_ckk = True if obj.id % 4 == 0: obj.section = SECTIONS.pop() elif obj.id % 10 != 0: obj.member_until = dd.demo_date().replace(month=12, day=31) yield obj fee_account = rt.models.accounts.Account( ref=dd.plugins.courses.membership_fee_account, type=rt.models.accounts.AccountTypes.incomes, default_amount=15, **dd.str2kw('name', _("Membership fee"))) yield fee_account Journal = rt.models.ledger.Journal USERS = Cycler(rt.models.users.User.objects.all()) MEMBERS = Cycler(rt.models.courses.Pupil.objects.all()) jnl = Journal.objects.get(ref='CSH') membership_payments = [ (1, 3), (2, 1), (10, 2), (11, 4), (12, 5), ] REQUEST = rt.login() for month, number in membership_payments: date = dd.demo_date().replace(month=month) voucher = jnl.create_voucher( user=USERS.pop(), voucher_date=date) yield voucher for i in range(number): M = jnl.voucher_type.get_items_model() kw = dict(voucher=voucher) kw.update(partner=MEMBERS.pop(), date=date, account=fee_account) kw.update( amount=fee_account.default_amount, dc=fee_account.type.dc) yield M(**kw) voucher.register(REQUEST) voucher.save()
def test02(self): # This case demonstratest that ordering does not ignore case, at # least in sqlite. we would prefer to have `['adams', 'Zybulka']`, # but we get `['Zybulka', 'adams']`. contacts = rt.modules.contacts contacts.Partner(name="Zybulka").save() contacts.Partner(name="adams").save() ar = rt.login().spawn(contacts.Partners) l = [p.name for p in ar] expected = ['Zybulka', 'adams'] self.assertEqual(l, expected)
def test02(self): # This case demonstrates that ordering does not ignore case, at # least in sqlite. we would prefer to have `['adams', 'Zybulka']`, # but we get `['Zybulka', 'adams']`. contacts = rt.models.contacts contacts.Partner(name="Zybulka").save() contacts.Partner(name="adams").save() ar = rt.login().spawn(contacts.Partners) l = [p.name for p in ar] expected = ['Zybulka', 'adams'] self.assertEqual(l, expected)
def objects(): Member = rt.modules.households.Member MemberRoles = rt.modules.households.MemberRoles # Household = resolve_model('households.Household') Person = dd.plugins.households.person_model Type = resolve_model('households.Type') men = Person.objects.filter(gender=dd.Genders.male).order_by('-id') women = Person.objects.filter(gender=dd.Genders.female).order_by('-id') # avoid interference with persons created by humanlinks demo # because these have already their households: men = men.filter(household_members__isnull=True) men = men.filter(humanlinks_children__isnull=True) men = men.filter(humanlinks_parents__isnull=True) women = women.filter(humanlinks_children__isnull=True) women = women.filter(humanlinks_parents__isnull=True) women = women.filter(household_members__isnull=True) MEN = Cycler(men) WOMEN = Cycler(women) TYPES = Cycler(Type.objects.all()) if not len(MEN) or not len(WOMEN): raise Exception("Not enough persons in {} and {} (all: {})".format( men, women, Person.objects.all())) # avoid automatic creation of children # loading_from_dump = settings.SITE.loading_from_dump # settings.SITE.loading_from_dump = True ses = rt.login() for i in range(5): pv = dict(head=MEN.pop(), partner=WOMEN.pop(), type=TYPES.pop()) ses.run(Person.create_household, action_param_values=pv) # yield ses.response['data_record'] # he = MEN.pop() # she = WOMEN.pop() # fam = Household(name=he.last_name + "-" + she.last_name, type_id=3) # yield fam # yield Member(household=fam, person=he, role=Role.objects.get(pk=1)) # yield Member(household=fam, person=she, role=Role.objects.get(pk=2)) i = 0 for m in Member.objects.filter(role=MemberRoles.head): i += 1 if i % 3 == 0: m.end_date = i2d(20020304) yield m pv = dict(head=m.person, partner=WOMEN.pop(), type=TYPES.pop()) ses.run(Person.create_household, action_param_values=pv)
def objects(self): self.ignored_journals = set() self.ignored_accounts = set() self.ignored_bank_accounts = set() self.undefined_bank_accounts = set() self.unknown_users = set() self.missing_partners = set() self.missing_clients = set() self.rows_by_year = SumCollector() self.ignored_matches = SumCollector() self.ignored_partners = SumCollector() yield wanted_accounts() # self.group = accounts.Group(name="Imported from TIM") # self.group.full_clean() # self.group.save() # yield self.load_dbf('BUD') # # self.after_gen_load() # yield self.load_dbf('JNL') # from lino_cosi.lib.vat.fixtures import euvatrates # yield euvatrates.objects() settings.SITE.loading_from_dump = True yield self.load_dbf('IML') yield self.load_dbf('IMP') # yield self.load_dbf('MVI') settings.SITE.loading_from_dump = False if len(self.must_register) == 0: return ses = rt.login('roger') dd.logger.info("Register %d vouchers", len(self.must_register)) failures = 0 for doc in progress.bar(self.must_register): # puts("Registering {0}".format(doc)) try: doc.register(ses) except Exception as e: dd.logger.warning("Failed to register %s : %s ", doc, e) failures += 1 if failures > 100: dd.logger.warning("Abandoned after 100 failures.") break
def objects(): # dd.logger.info( # "sheets %s %s", # dd.plugins.ledger.start_year, dd.today().year+1) from datetime import date Report = rt.models.sheets.Report AccountingPeriod = rt.models.ledger.AccountingPeriod ses = rt.login("robin") for year in range(dd.plugins.ledger.start_year, dd.today().year+1): sp = AccountingPeriod.get_default_for_date(date(year, 1, 1)) ep = AccountingPeriod.get_default_for_date(date(year, 12, 31)) obj = Report(start_period=sp, end_period=ep, user=ses.get_user()) yield obj obj.run_update_plan(ses)
def test01(self): from lino.modlib.users.choicelists import UserTypes User = rt.models.users.User Account = rt.models.accounts.Account AccountTypes = rt.models.accounts.AccountTypes Journal = rt.models.ledger.Journal Partner = rt.models.contacts.Partner Person = rt.models.contacts.Person Company = rt.models.contacts.Company Role = rt.models.contacts.Role # Account = rt.models.sepa.Account Invoice = rt.models.vat.VatAccountInvoice VoucherTypes = rt.models.ledger.VoucherTypes JournalGroups = rt.models.ledger.JournalGroups robin = create_row( User, username='******', user_type=UserTypes.admin, language="en") ar = rt.login('robin') a = create_row(Account, name="A", type=AccountTypes.expenses) b = create_row(Account, name="B", type=AccountTypes.expenses) c = create_row(Account, name="C", type=AccountTypes.expenses) d = create_row(Account, name="D", type=AccountTypes.expenses) lst = [i.seqno for i in Account.objects.order_by('name')] self.assertEqual(lst, [1, 2, 3, 4]) self.assertEqual(a.seqno, 1) self.assertEqual(b.seqno, 2) self.assertEqual(c.seqno, 3) self.assertEqual(d.seqno, 4) a.move_down(ar) self.assertEqual(ar.response, { 'message': 'Renumbered 1 of 3 siblings.', 'success': True, 'refresh_all': True}) # NOTE that a, b, c and d are invalid now a = b = c = d = None lst = [i.seqno for i in Account.objects.order_by('name')] self.assertEqual(lst, [2, 1, 3, 4]) lst = [i.name for i in Account.objects.order_by('seqno')] self.assertEqual(''.join(lst), "BACD")
def test01(self): from lino.modlib.users.choicelists import UserTypes User = rt.models.users.User Account = rt.models.ledger.Account Journal = rt.models.ledger.Journal Partner = rt.models.contacts.Partner Person = rt.models.contacts.Person Company = rt.models.contacts.Company Role = rt.models.contacts.Role # Account = rt.models.sepa.Account Invoice = rt.models.vat.VatAccountInvoice VoucherTypes = rt.models.ledger.VoucherTypes JournalGroups = rt.models.ledger.JournalGroups robin = create_row( User, username='******', user_type=UserTypes.admin, language="en") ar = rt.login('robin') a = create_row(Account, name="A") b = create_row(Account, name="B") c = create_row(Account, name="C") d = create_row(Account, name="D") lst = [i.seqno for i in Account.objects.order_by('name')] self.assertEqual(lst, [1, 2, 3, 4]) self.assertEqual(a.seqno, 1) self.assertEqual(b.seqno, 2) self.assertEqual(c.seqno, 3) self.assertEqual(d.seqno, 4) response = a.move_down() self.assertEqual(response, { 'message': 'Renumbered 1 of 3 siblings.', 'success': True, 'refresh_all': True}) # NOTE that a, b, c and d are invalid now a = b = c = d = None lst = [i.seqno for i in Account.objects.order_by('name')] self.assertEqual(lst, [2, 1, 3, 4]) lst = [i.name for i in Account.objects.order_by('seqno')] self.assertEqual(''.join(lst), "BACD")
def objects(): Member = rt.modules.households.Member MemberRoles = rt.modules.households.MemberRoles # Household = resolve_model('households.Household') Person = resolve_model(dd.plugins.households.person_model) Type = resolve_model('households.Type') MEN = Cycler(Person.objects.filter(gender=dd.Genders.male) .order_by('-id')) WOMEN = Cycler(Person.objects.filter(gender=dd.Genders.female) .order_by('-id')) TYPES = Cycler(Type.objects.all()) ses = rt.login() for i in range(5): pv = dict( head=MEN.pop(), partner=WOMEN.pop(), type=TYPES.pop()) ses.run( Person.create_household, action_param_values=pv) # yield ses.response['data_record'] # he = MEN.pop() # she = WOMEN.pop() # fam = Household(name=he.last_name + "-" + she.last_name, type_id=3) # yield fam # yield Member(household=fam, person=he, role=Role.objects.get(pk=1)) # yield Member(household=fam, person=she, role=Role.objects.get(pk=2)) i = 0 for m in Member.objects.filter(role=MemberRoles.head): i += 1 if i % 3 == 0: m.end_date = i2d(20020304) yield m pv = dict( head=m.person, partner=WOMEN.pop(), type=TYPES.pop()) ses.run( Person.create_household, action_param_values=pv)
def objects(): Company = rt.models.contacts.Company ar = rt.login(request=PseudoRequest("robin")) obj = Company(name="My pub") obj.full_clean() obj.save_new_instance(ar) cw = ChangeWatcher(obj) obj.name = "Our pub" obj.save_watched_instance(ar, cw) obj.delete_instance(ar) # this is a special fixture : it creates objects as a side effect # but does not yield them. return []
def objects(): ExcerptType = rt.models.excerpts.ExcerptType Excerpt = rt.models.excerpts.Excerpt if not dd.plugins.excerpts.responsible_user: return ses = rt.login(dd.plugins.excerpts.responsible_user) for et in ExcerptType.objects.all(): model = et.content_type.model_class() qs = model.get_printable_demo_objects() # if issubclass(model, Certifiable): # qs = model.get_printable_demo_objects(et) # else: # qs = model.objects.all() # if qs.count() > 0: # qs = [qs[0]] # if et.certifying: for obj in qs: ses.selected_rows = [obj] yield et.get_or_create_excerpt(ses) # qs2 = Excerpt.objects.filter(excerpt_type=et) # if qs2.count() == 0: # if qs.count() > 0: # ses.selected_rows = [qs[0]] # yield et.get_or_create_excerpt(ses) for obj in Excerpt.objects.all(): # dd.logger.info("20150526 rendering %s", obj) try: rv = ses.run(obj.do_print) assert rv['success'] except Warning as e: dd.logger.warning( "Failed to render %s : %s", obj, e) except Exception as e: if SEVERE: raise else: traceback.print_exc() dd.logger.warning( "20160311 failed to render %s : %s", obj, e)
def objects(): ExcerptType = rt.models.excerpts.ExcerptType Excerpt = rt.models.excerpts.Excerpt if not dd.plugins.excerpts.responsible_user: return ses = rt.login(dd.plugins.excerpts.responsible_user) for et in ExcerptType.objects.all().order_by('id'): model = et.content_type.model_class() qs = model.get_printable_demo_objects() # if issubclass(model, Certifiable): # qs = model.get_printable_demo_objects(et) # else: # qs = model.objects.all() # if qs.count() > 0: # qs = [qs[0]] # if et.certifying: for obj in qs: ses.selected_rows = [obj] yield et.get_or_create_excerpt(ses) # qs2 = Excerpt.objects.filter(excerpt_type=et) # if qs2.count() == 0: # if qs.count() > 0: # ses.selected_rows = [qs[0]] # yield et.get_or_create_excerpt(ses) for obj in Excerpt.objects.all(): # dd.logger.info("20150526 rendering %s", obj) try: rv = ses.run(obj.do_print) assert rv['success'] except Warning as e: dd.logger.warning("Failed to render %s : %s", obj, e) except Exception as e: if SEVERE: raise else: traceback.print_exc() dd.logger.warning("20160311 failed to render %s : %s", obj, e)
def test_create_entry(self): """# cal.MyEvents.insert({'requesting_panel': u'ext-comp-3913', 'user': u'luc'}) """ ses = rt.login("robin") ba = rt.modules.cal.MyEvents.get_action_by_name("submit_insert") # a = rt.modules.cal.MyEvents.submit_insert # ba = rt.modules.cal.MyEvents.insert_action pv = dict(user=ses.get_user()) resp = ses.run(ba, param_values=pv) # ba.request_from(ses).run_from_ui(ses) self.assertEqual( sorted(resp.keys()), [ "close_window", "data_record", "detail_handler_name", "info_message", "message", "refresh_all", "rows", "success", ], ) # self.assertEqual(resp['data_record'].keys(), None) # The return message is of style 'Event "Event #69 (23.10.2014 # 15:42)" has been created.' The start_time is the real time # runtime and thus not predictable. So we retrieve the # created object and use it to build that message: pk = resp["data_record"]["id"] obj = rt.modules.cal.Event.objects.get(pk=pk) msg = 'Event "{0}" has been created.'.format(obj) self.assertEqual(resp["message"], msg)
def show_excerpts(severe=True): ses = rt.login() # dd.logger.info("20141029 %s", settings.SITE) coll = {} def collect(obj): l = coll.setdefault(obj.excerpt_type, []) mf = obj.build_method.get_target(None, obj) tmppath = Path(mf.name) if tmppath.exists(): tail = tmppath.name tail = 'dl/excerpts/' + tail kw = dict(tail=tail) kw.update(type=obj.excerpt_type) kw.update(owner=obj.owner) try: # dd.logger.info("20141029 copy %s to %s", tmppath, tail) shutil.copyfile(tmppath, tail) except IOError as e: kw.update(error=str(e)) msg = "%(type)s %(owner)s %(tail)s Oops: %(error)s" % kw # raise Exception(msg) kw.update(owner=msg) l.append(kw) for o in rt.models.excerpts.Excerpt.objects.order_by('excerpt_type'): collect(o) def asli(et, items): s = str(et) s += " : " + ', '.join("`%(owner)s <../%(tail)s>`__" % kw % kw for kw in items) return s return rstgen.ul([asli(k, v) for k, v in coll.items()])
def objects(refs="PMO BNK"): # welfare calls it with customized refs. Journal = rt.models.ledger.Journal Company = rt.models.contacts.Company Movement = rt.models.ledger.Movement USERS = Cycler(settings.SITE.user_model.objects.all()) OFFSETS = Cycler(12, 20, 28) START_YEAR = dd.plugins.ledger.start_year end_date = settings.SITE.demo_date(-30) site_company = settings.SITE.site_config.site_company ses = rt.login('robin') qs = Company.objects.filter(country__isnull=False) # if qs.count() < 10: # raise Exception("20171009") for p in qs: if Movement.objects.filter(partner=p, cleared=False).count(): add_demo_account(p) if dd.is_installed("vat") and dd.plugins.vat.declaration_plugin is None: dd.logger.warning("No demo payments because declaration_plugin is None") return for ref in refs.split(): # if ref == 'BNK': # continue # temp 20171007 jnl = Journal.objects.get(ref=ref) sug_table = jnl.voucher_type.table_class.suggestions_table do_fill = sug_table.get_action_by_name('do_fill') if ref == 'PMO': assert site_company is not None if site_company.country is None: raise Exception( "Oops, site company {} has no country".format( site_company)) acct = add_demo_account(site_company) jnl.sepa_account = acct yield jnl offset = OFFSETS.pop() date = datetime.date(START_YEAR, 1, 1) while date < end_date: voucher = jnl.create_voucher( user=USERS.pop(), entry_date=date + delta(days=offset)) yield voucher # print("20201009", voucher) # start action request for do_fill: ar = do_fill.request(master_instance=voucher) # select all rows: suggestions = sug_table.request(voucher) ar.selected_rows = list(suggestions) # run the action: ar.run() # manually introduce some payment differences: if ref == 'BNK': for item in voucher.items.all(): pd = PAYMENT_DIFFS.pop() if pd: pd = Decimal(pd) item.amount += item.amount * pd if item.amount: item.save() else: item.delete() # if no items have been created (or if they have been # deleted by PAYMENT_DIFFS), remove the empty voucher: if voucher.items.count() == 0: voucher.delete() else: # if ref == 'PMO': # voucher.execution_date = voucher.entry_date # assert voucher.execution_date is not None voucher.register(REQUEST) # voucher.full_clean() # voucher.save() # for i in voucher.items.all(): # if i.partner: # yield add_demo_account(i.partner) # For payment orders we also write the XML file if ref == 'PMO': rv = voucher.write_xml.run_from_session(ses) if not rv['success']: raise Exception("20170630") if False: # not needed here because write_xml validates fn = Path(settings.SITE.cache_dir + rv['open_url']) if not fn.exists(): raise Exception("20170630") validate_pain001(fn) date += delta(months=1)
def test01(self): from lino.modlib.users.choicelists import UserTypes Ticket = rt.models.tickets.Ticket # Project = rt.models.tickets.Project # Line = rt.models.courses.Line # Activity = rt.models.courses.Course # Enrolment = rt.models.courses.Enrolment # Meeting = rt.models.meetings.Meeting Change = rt.models.changes.Change User = rt.models.users.User # Vote = rt.models.votes.Vote # VoteStates = rt.models.votes.VoteStates # VotesByVotable = rt.models.votes.VotesByVotable # ContentType = rt.models.contenttypes.ContentType # ct_Ticket = ContentType.objects.get_for_model(Ticket) # create(Project, name='project') robin = create(User, username='******', first_name="Robin", user_type=UserTypes.admin, language="en") anna = create(User, username='******', first_name="Anna", user_type=UserTypes.user, language="en") berta = create(User, username='******', first_name="Berta", user_type=UserTypes.user, language="en") # meeting = create(Meeting, name="Test") # sprints = create(Line, name="Sprints") # sprint = create(Activity, line=sprints) # # Enrolment(course=sprint, pupil=robin) ses = rt.login('robin') ticket = create(Ticket, summary="First", user=robin) ticket.after_ui_save(ses, None) # vote = Vote.objects.get(votable=ticket) # self.assertEqual(vote.user, robin) # self.assertEqual(vote.state, VoteStates.author) def check_success(ia, **kwargs): rv = ia.run_from_session(ses, **kwargs) self.assertEqual(rv, {'success': True, 'refresh': True}) check_success(ticket.mark_talk) check_success(ticket.mark_started) check_success(ticket.mark_refused) check_success(ticket.mark_closed) check_success(ticket.mark_refused) # Vote.objects.all().delete() Ticket.objects.all().delete() # self.assertEqual(Vote.objects.count(), 0) ticket = create( Ticket, summary="Second", user=robin, end_user=anna) ticket.after_ui_save(ses, None)
def objects(): Granting = rt.modules.aids.Granting AidType = rt.modules.aids.AidType Person = rt.modules.contacts.Person Client = rt.modules.pcsw.Client ClientStates = rt.modules.pcsw.ClientStates ClientContactType = rt.modules.pcsw.ClientContactType Board = rt.modules.boards.Board ExcerptType = rt.modules.excerpts.ExcerptType ConfirmationStates = rt.modules.aids.ConfirmationStates Project = resolve_model('pcsw.Client') qs = Project.objects.filter(client_state=ClientStates.coached) # if qs.count() > 10: # qs = qs[:10] PROJECTS = Cycler(qs) l = [] qs = ClientContactType.objects.filter(can_refund=True) for cct in qs: qs2 = Person.objects.filter(client_contact_type=cct) if qs2.count(): i = (cct, Cycler(qs2)) l.append(i) PARTNERS = Cycler(l) BOARDS = Cycler(Board.objects.all()) CONFIRMSTATES = Cycler(ConfirmationStates.objects()) DURATIONS = Cycler(None, 1, 1, 30, 0, None, 365) fkw = dd.str2kw('name', _("Pharmacy")) # Apotheke pharmacy_type = rt.modules.pcsw.ClientContactType.objects.get(**fkw) PHARMACIES = Cycler(rt.modules.contacts.Company.objects.filter( client_contact_type=pharmacy_type)) for i, at in enumerate(AidType.objects.all()): for j in range(2): sd = dd.demo_date(days=i) kw = dict(start_date=sd, board=BOARDS.pop(), decision_date=dd.demo_date(days=i-1), aid_type=at) kw.update(client=PROJECTS.pop()) duration = DURATIONS.pop() if duration is not None: kw.update(end_date=sd+datetime.timedelta(days=duration)) g = Granting(**kw) # g.after_ui_create(None) g.full_clean() if g.signer is not None: g.state = CONFIRMSTATES.pop() yield g # ConfirmationTypes = rt.modules.aids.ConfirmationTypes RefundConfirmation = rt.modules.aids.RefundConfirmation IncomeConfirmation = rt.modules.aids.IncomeConfirmation ClientContact = rt.modules.pcsw.ClientContact COACHES = Cycler(rt.modules.users.User.objects.filter( coaching_type__isnull=False)) AMOUNTS = Cycler(123, 234, 345, 456, 678) CATEGORIES = Cycler(rt.modules.aids.Category.objects.all()) # create 1 or 2 confirmations per granting urgent_aid_generated = 0 for i, g in enumerate(Granting.objects.filter(aid_type__isnull=False)): ct = g.aid_type.confirmation_type num = i % 2 + 1 if ct.model is RefundConfirmation: num = 3 # always create 3 confirmations per refund granting if g.aid_type.pharmacy_type == pharmacy_type: pharmacy = PHARMACIES.pop() yield ClientContact( type=pharmacy_type, company=pharmacy, client=g.client) for j in range(num): kw = dict(granting=g, client=g.client) kw.update(user=COACHES.pop()) kw.update(start_date=g.start_date) kw.update(end_date=g.end_date) if g.signer is not None: kw.update(state=CONFIRMSTATES.pop()) kw.update(signer=g.signer) if ct.model is IncomeConfirmation: kw.update(category=CATEGORIES.pop()) kw.update(amount=AMOUNTS.pop()) if ct.model is RefundConfirmation: doctor_type, doctor_cycler = PARTNERS.pop() doctor = doctor_cycler.pop() kw.update(doctor_type=doctor_type) kw.update(doctor=doctor) yield ClientContact( type=doctor_type, contact_person=doctor, client=g.client) # only the first confirmation has a pharmacy if g.aid_type.pharmacy_type == pharmacy_type and j == 0: kw.update(pharmacy=pharmacy) yield ct.model(**kw) # for two refund grantings, create the corresponding # additional granting of urgent medical help if ct.model is RefundConfirmation and urgent_aid_generated < 2: kw = dict() kw.update(client=g.client) kw.update(start_date=g.start_date) kw.update(end_date=g.end_date) kw.update(aid_type=AidType.objects.get(short_name="DMH")) yield Granting(**kw) urgent_aid_generated += 1 if False: # no need to print them all. # lino_welfare.modlib.welfare.fixtures.demo2 is enough. ses = rt.login('theresia') for at in rt.modules.aids.AidType.objects.exclude( confirmation_type=''): M = at.confirmation_type.model et = ExcerptType.get_for_model(M) qs = M.objects.filter(granting__aid_type=at) for obj in qs: ses.selected_rows = [obj] yield et.get_or_create_excerpt(ses) def person2client(f, l): obj = Person.objects.get(first_name=f, last_name=l) mti.insert_child(obj, Client) person2client("Paul", "Frisch") person2client("Bruno", "Braun") # create a clothing_refund granting and excerpt for Paul Frisch: ses = rt.login("alicia") obj = Client.objects.get(name="Frisch Paul") at = AidType.objects.get( body_template='clothing_bank.body.html') g = Granting(aid_type=at, client=obj) g.full_clean() yield g M = at.confirmation_type.model conf = M(client=obj, granting=g) conf.full_clean() conf.on_create(ses) yield conf et = ExcerptType.get_for_model(M) ses.selected_rows = [conf] yield et.get_or_create_excerpt(ses)
def checksummaries(): rt.login().run(settings.SITE.site_config.check_all_summaries)
def test_suggest_cal_guests(self): """Tests a bugfix in :meth:`suggest_cal_guests <lino_xl.lib.courses.Course.suggest_cal_guests>`. """ User = settings.SITE.user_model Guest = rt.models.cal.Guest Event = rt.models.cal.Event EventType = rt.models.cal.EventType GuestRole = rt.models.cal.GuestRole Recurrencies = rt.models.cal.Recurrencies Room = rt.models.cal.Room Enrolment = rt.models.courses.Enrolment Course = rt.models.courses.Course Line = rt.models.courses.Line EnrolmentStates = rt.models.courses.EnrolmentStates Pupil = rt.models.pcsw.Client robin = User(username='******', user_type=UserTypes.admin) robin.save() ar = rt.login('robin') settings.SITE.verbose_client_info_message = False pupil = Pupil(first_name="First", last_name="Pupil") pupil.save() pupil2 = Pupil(first_name="Second", last_name="Pupil") pupil2.save() et = EventType(name="lesson") et.full_clean() et.save() gr = GuestRole(name="pupil") gr.save() room = Room(name="classroom") room.save() line = Line(name="Test", guest_role=gr, event_type=et, every_unit=Recurrencies.weekly) line.full_clean() line.save() course = Course(max_events=4, line=line, start_date=i2d(20150409), user=robin, monday=True, room=room) course.full_clean() course.save() # Two enrolments, one is requested, the other confirmed. Only # the confirmed enrolments will be inserted as guests. self.create_obj(Enrolment, course=course, state=EnrolmentStates.requested, pupil=pupil2) self.create_obj(Enrolment, course=course, state=EnrolmentStates.confirmed, pupil=pupil) wanted, unwanted = course.get_wanted_auto_events(ar) self.assertEqual( ar.response['info_message'], 'Generating events between 2015-04-13 and 2019-05-22 (max. 4).') self.assertEqual(len(wanted), 4) course.do_update_events.run_from_ui(ar) self.assertEqual(ar.response['success'], True) self.assertEqual(Event.objects.all().count(), 4) self.assertEqual(Guest.objects.all().count(), 4) # self.assertEqual(ar.response['info_message'], '') try: self.create_obj(Enrolment, course=course, state=EnrolmentStates.confirmed, pupil=pupil) self.fail("Expected ValidationError") except ValidationError as e: if six.PY2: expected = "{'__all__': [u'Un object Inscription avec ces " \ "champs Atelier et B\\xe9n\\xe9ficiaire existe " \ "d\\xe9j\\xe0.']}" else: expected = "{'__all__': ['Un object Inscription avec ces champs Atelier et Bénéficiaire existe déjà.']}" self.assertEqual(str(e), expected)
def test_checkin_guest(self): """Test whether notifications are being emitted. - when a visitor checks in - when a client is modified - when a coaching is created or modified - when a note is created or modified """ User = settings.SITE.user_model Message = rt.models.notify.Message Note = rt.models.notes.Note NoteType = rt.models.notes.EventType Guest = rt.models.cal.Guest Event = rt.models.cal.Event EventType = rt.models.cal.EventType Client = rt.models.pcsw.Client ClientStates = rt.models.pcsw.ClientStates Coaching = rt.models.coachings.Coaching ContentType = rt.models.contenttypes.ContentType self.assertEqual(settings.SITE.use_websockets, False) robin = self.create_obj(User, username='******', user_type=UserTypes.admin, language="en") caroline = self.create_obj(User, username='******', user_type='200', language="fr") alicia = self.create_obj(User, username='******', first_name="Alicia", user_type='120', language="fr") roger = self.create_obj(User, username='******', user_type='420', language="en") ses = rt.login('robin') translation.activate('fr') first = self.create_obj(Client, first_name="First", last_name="Gérard", client_state=ClientStates.coached) second = self.create_obj(Client, first_name="Second", last_name="Gérard", client_state=ClientStates.coached) self.create_obj(Coaching, client=second, start_date=i2d(20130501), end_date=i2d(20140501), user=caroline) second_roger = self.create_obj(Coaching, client=second, start_date=i2d(20140501), user=roger) self.create_obj(Coaching, client=second, start_date=i2d(20140520), user=alicia) nt = self.create_obj(NoteType, name="System note") settings.SITE.site_config.update(system_note_type=nt) consultation = self.create_obj(EventType, name="consultation") # gr = self.create_obj(GuestRole, name="client") event = self.create_obj(Event, event_type=consultation, user=caroline) guest = self.create_obj(Guest, event=event, partner=first) self.assertEqual(str(guest), 'Présence #1 (22.05.2014)') # Checkin a guest res = ses.run(guest.checkin) # 'GÉRARD First (100) has started waiting for caroline' self.assertEqual( res, { 'message': "GÉRARD First (100) a commencé d'attendre caróline", 'success': True, 'refresh': True }) # it has caused a notification message: self.assertEqual(Message.objects.count(), 1) msg = Message.objects.all()[0] self.assertEqual(msg.user.username, 'caróline') self.assertEqual(msg.subject, "GÉRARD First (100) a commencé d'attendre caróline") # it does *not* cause a system note: self.assertEqual(Note.objects.count(), 0) # When a client is modified, all active coaches get a # notification. # Note that Caroline doesn't get a notification because her # coaching is not active. # Alicia doesn't get a notification because she did it herself. # Roger doesn't get notified because he is user_type 420 data = dict(first_name="Seconda", an="submit_detail") kwargs = dict(data=urlencode(data)) kwargs['REMOTE_USER'] = '******' url = '/api/pcsw/Clients/{}'.format(second.pk) self.client.force_login(alicia) res = self.client.put(url, **kwargs) self.assertEqual(res.status_code, 200) # self.assertEqual(Message.objects.count(), 2) # self.check_notifications() self.check_notifications(""" =================================================== ======= ============== Sujet Lié à Destinataire --------------------------------------------------- ------- -------------- GÉRARD First (100) a commencé d'attendre caróline caróline =================================================== ======= ============== """) # When a coaching is modified, all active coaches of that # client get a notification. Message.objects.all().delete() data = dict(start_date="02.05.2014", an="grid_put") data.update(mt=51) data.update(mk=second.pk) kwargs = dict(data=urlencode(data)) kwargs['REMOTE_USER'] = '******' self.client.force_login(robin) url = '/api/coachings/CoachingsByClient/{}'.format(second_roger.pk) res = self.client.put(url, **kwargs) self.assertEqual(res.status_code, 200) # self.check_notifications() self.check_notifications(""" ================================== ==================== =========== Subject Controlled by Recipient ---------------------------------- -------------------- ----------- robin a modifié róger / Gérard S *róger / Gérard S* Alicia ================================== ==================== =========== """) # AssignCoach. we are going to Assign caroline as coach for # first client. # Request URL:http://127.0.0.1:8000/api/newcomers/AvailableCoachesByClient/5?_dc=1469707129689&fv=EVERS%20Eberhart%20(127)%20assigned%20to%20Hubert%20Huppertz%20&fv=EVERS%20Eberhart%20(127)%20is%20now%20coached%20by%20Hubert%20Huppertz%20for%20Laufende%20Beihilfe.&fv=false&mt=48&mk=127&an=assign_coach&sr=5 # Request Method:GET # fv:EVERS Eberhart (127) assigned to Hubert Huppertz # fv:EVERS Eberhart (127) is now coached by Hubert Huppertz for Laufende Beihilfe. # fv:false # mt:48 # mk:127 # an:assign_coach # sr:5 Message.objects.all().delete() # self.assertEqual(Coaching.objects.count(), 1) # self.check_coachings() self.check_coachings(""" ==== ====================== ============== ============ ========== ========= ID Client Coached from until Coach Primary ---- ---------------------- -------------- ------------ ---------- --------- 1 GÉRARD Seconda (101) 01/05/2013 01/05/2014 caróline No 2 GÉRARD Seconda (101) 02/05/2014 róger No 3 GÉRARD Seconda (101) 20/05/2014 Alicia No ==== ====================== ============== ============ ========== ========= """) self.assertEqual(Note.objects.count(), 0) data = dict(fv=["First GÉRARD assigned to caróline", "Body", 'false'], an="assign_coach") data.update(mt=ContentType.objects.get_for_model(Client).pk) data.update(mk=first.pk) kwargs = dict(data=data) # kwargs = dict(data=urlencode(data)) kwargs['REMOTE_USER'] = '******' self.client.force_login(alicia) url = '/api/newcomers/AvailableCoachesByClient/{}'.format(caroline.pk) res = self.client.get(url, **kwargs) self.assertEqual(res.status_code, 200) self.check_notifications(""" =================================== ======= ============== Sujet Lié à Destinataire ----------------------------------- ------- -------------- First GÉRARD assigned to caróline caróline =================================== ======= ============== """) # self.check_coachings("") self.check_coachings(""" ==== ====================== ======================== ============ ============= ========== ID Bénéficiaire En intervention depuis au Intervenant Primaire ---- ---------------------- ------------------------ ------------ ------------- ---------- 1 GÉRARD Seconda (101) 01/05/2013 01/05/2014 caróline Non 2 GÉRARD Seconda (101) 02/05/2014 róger Non 3 GÉRARD Seconda (101) 20/05/2014 Alicia Non 4 GÉRARD First (100) 22/05/2014 caróline Oui ==== ====================== ======================== ============ ============= ========== """) self.check_notes(""" ==== ======== ==================== =================================== ID Auteur Bénéficiaire Sujet ---- -------- -------------------- ----------------------------------- 1 Alicia GÉRARD First (100) First GÉRARD assigned to caróline ==== ======== ==================== =================================== """) # Mark client as former # Request URL:http://127.0.0.1:8000/api/pcsw/Clients/181?_dc=1469714189945&an=mark_former&sr=181 # Request Method:GET # an:mark_former Message.objects.all().delete() Note.objects.all().delete() data = dict(an="mark_former") kwargs = dict(data=data) # kwargs = dict(data=urlencode(data)) kwargs['REMOTE_USER'] = '******' self.client.force_login(alicia) url = '/api/pcsw/Clients/{}'.format(second.pk) res = self.client.get(url, **kwargs) self.assertEqual(res.status_code, 200) res = AttrDict(json.loads(res.content)) self.assertEqual(res.message, 'This will end 2 coachings of GÉRARD Seconda (101).') self.assertEqual(res.xcallback['title'], "Confirmation") kwargs = dict() kwargs['REMOTE_USER'] = '******' self.client.force_login(alicia) url = '/callbacks/{}/yes'.format(res.xcallback['id']) res = self.client.get(url, **kwargs) self.assertEqual(res.status_code, 200) res = AttrDict(json.loads(res.content)) self.assertEqual( res.message, 'Alicia a classé GÉRARD Seconda (101) comme <b>Ancien</b>.') self.assertTrue(res.success) self.check_notifications(""" =========================================================== ======================== ============== Sujet Lié à Destinataire ----------------------------------------------------------- ------------------------ -------------- Alicia a classé GÉRARD Seconda (101) comme <b>Ancien</b>. *GÉRARD Seconda (101)* róger =========================================================== ======================== ============== """) # check two coachings have now an end_date set: # self.check_coachings() self.check_coachings(""" ==== ====================== ======================== ============ ============= ========== ID Bénéficiaire En intervention depuis au Intervenant Primaire ---- ---------------------- ------------------------ ------------ ------------- ---------- 1 GÉRARD Seconda (101) 01/05/2013 01/05/2014 caróline Non 2 GÉRARD Seconda (101) 02/05/2014 22/05/2014 róger Non 3 GÉRARD Seconda (101) 20/05/2014 22/05/2014 Alicia Non 4 GÉRARD First (100) 22/05/2014 caróline Oui ==== ====================== ======================== ============ ============= ========== """) # self.check_notes() self.check_notes(""" ==== ======== ====================== =========================================================== ID Auteur Bénéficiaire Sujet ---- -------- ---------------------- ----------------------------------------------------------- 2 Alicia GÉRARD Seconda (101) Alicia a classé GÉRARD Seconda (101) comme <b>Ancien</b>. ==== ======== ====================== =========================================================== """) # # RefuseClient # Message.objects.all().delete() Note.objects.all().delete() self.create_obj(Coaching, client=first, start_date=i2d(20130501), user=roger) first.client_state = ClientStates.newcomer first.save() data = dict(fv=["20", ""], an="refuse_client") kwargs = dict(data=data) # kwargs = dict(data=urlencode(data)) kwargs['REMOTE_USER'] = '******' self.client.force_login(alicia) url = '/api/pcsw/Clients/{}'.format(first.pk) res = self.client.get(url, **kwargs) self.assertEqual(res.status_code, 200) # self.check_notifications("") #if six.PY2: self.check_notifications(""" ========================================================= ====================== ============== Sujet Lié à Destinataire --------------------------------------------------------- ---------------------- -------------- Alicia a classé GÉRARD First (100) comme <b>Refusé</b>. *GÉRARD First (100)* caróline Alicia a classé GÉRARD First (100) comme <b>Refusé</b>. *GÉRARD First (100)* róger ========================================================= ====================== ============== """) # self.check_notes() self.check_notes(""" ==== ======== ==================== ========================================================= ID Auteur Bénéficiaire Sujet ---- -------- -------------------- --------------------------------------------------------- 3 Alicia GÉRARD First (100) Alicia a classé GÉRARD First (100) comme <b>Refusé</b>. ==== ======== ==================== ========================================================= """) # When a note is created, all active coaches of that # client get a notification. Message.objects.all().delete() data = dict() data.update(mt=51) data.update(mk=second.pk) data.update(an='submit_insert') data.update(subject="test", projectHidden=second.pk) kwargs = dict(data=data) kwargs['REMOTE_USER'] = '******' self.client.force_login(alicia) url = '/api/notes/NotesByProject/{}'.format(second.pk) res = self.client.post(url, **kwargs) self.assertEqual(res.status_code, 200) res = AttrDict(json.loads(res.content)) self.assertEqual(res.data_record['id'], 4) new_note_pk = res.data_record['id'] # self.check_notifications() self.check_notifications(""" ============================== ================== ============== Sujet Lié à Destinataire ------------------------------ ------------------ -------------- Alicia created Event/Note #4 *Observation #4* róger ============================== ================== ============== """) Message.objects.all().delete() data = dict() data.update(mt=51) data.update(mk=second.pk) data.update(an='submit_detail') data.update(subject="test 2", body="<p>Bla bla bla</p>", projectHidden=second.pk) kwargs = dict(data=urlencode(data)) # kwargs = dict(data=data) kwargs['REMOTE_USER'] = '******' self.client.force_login(alicia) url = '/api/notes/NotesByProject/{}'.format(new_note_pk) res = self.client.put(url, **kwargs) self.assertEqual(res.status_code, 200) # self.check_notifications() # self.check_notifications("Aucun enregistrement") self.check_notifications(""" =============================== ================== ============== Sujet Lié à Destinataire ------------------------------- ------------------ -------------- Alicia modified Event/Note #4 *Observation #4* róger =============================== ================== ============== """) self.assertEqual(Message.objects.count(), 1) msg = Message.objects.all()[0] # print msg.body self.assertEquivalent( msg.body, """ <div><p>Subject: test 2<br/>Client: [client 101] (Seconda GÉRARD)</p><p>Alicia modified [note 4] (test 2):</p><ul><li><b>Body</b> : 1 lines added</li><li><b>Subject</b> : test --> test 2</li></ul></div> """)
def objects(): Person = dd.resolve_model(dd.apps.humanlinks.person_model) Link = rt.modules.humanlinks.Link LinkTypes = rt.modules.humanlinks.LinkTypes ar = rt.login() households = dd.resolve_app('households') if households: married = households.Type.objects.get( **dd.str2kw('name', _("Married"))) divorced = households.Type.objects.get( **dd.str2kw('name', _("Divorced"))) ig = InstanceGenerator() ig.add_instantiator( 'person', Person, 'first_name last_name gender birth_date') ig.add_instantiator( 'link', Link, 'parent child type') NAME1 = "Frisch" opa = ig.person("Hubert", NAME1, 'M', '1933-07-21') oma = ig.person("Gaby", "Frogemuth", 'F', '1934-08-04') P = ig.person("Paul", NAME1, 'M', '1967-06-19') L = ig.person("Ludwig", NAME1, 'M', '1968-06-01') A = ig.person("Alice", NAME1, 'F', '1969-12-19') B = ig.person("Bernd", NAME1, 'M', '1971-09-10') P1 = ig.person("Paula", "Einzig", 'F', '1968-12-19') P1A = ig.person("Peter", NAME1, 'M', '1987-06-19') P2 = ig.person("Petra", "Zweith", 'F', '1968-12-19') P2A = ig.person("Philippe", NAME1, 'M', '1997-06-19') P2B = ig.person("Clara", NAME1, 'F', '1999-06-19') P3 = ig.person("Dora", "Drosson", 'F', '1971-12-19') P3A = ig.person("Dennis", NAME1, 'M', '2001-06-19') L1 = ig.person("Laura", "Loslever", 'F', '1968-04-27') L1A = ig.person("Melba", NAME1, 'F', '2002-04-05') L1B = ig.person("Irma", NAME1, 'F', '2008-03-24') yield ig.flush() ig.link(opa, oma, LinkTypes.spouse) for i in (P, L, A, B): ig.link(opa, i, LinkTypes.parent) ig.link(oma, i, LinkTypes.parent) ig.link(P, P1A, LinkTypes.parent) ig.link(P1, P1A, LinkTypes.parent) ig.link(P, P2A, LinkTypes.parent) ig.link(P2, P2A, LinkTypes.parent) ig.link(P, P2B, LinkTypes.parent) ig.link(P2, P2B, LinkTypes.parent) ig.link(P, P3A, LinkTypes.parent) ig.link(P3, P3A, LinkTypes.parent) ig.link(P, P2, LinkTypes.spouse) ig.link(L, L1, LinkTypes.spouse) for i in (L1A, L1B): ig.link(L, i, LinkTypes.parent) ig.link(L1, i, LinkTypes.parent) yield ig.flush() if households: households.Household.create_household(ar, opa, oma, married) households.Household.create_household(ar, P, P1, divorced) hh = households.Household.create_household(ar, P, P2, married) hh.members_by_role('head')[0].set_primary(ar) hh.members_by_role('partner')[0].set_primary(ar) households.Household.create_household(ar, L, L1, married) A = ig.person("Albert", "Adam", 'M', '1973-07-21') B = ig.person("Bruno", "Braun", 'M', '1973-07-22') E = ig.person("Eveline", "Evrard", 'F', '1974-08-21') F = ig.person("Françoise", "Freisen", 'F', '1974-08-22') I = ig.person("Ilja", "Adam", 'M', '1994-08-22') J = ig.person("Jan", "Braun", 'M', '1996-08-22') K = ig.person("Kevin", "Braun", 'M', '1998-08-22') L = ig.person("Lars", "Braun", 'M', '1998-08-22') M = ig.person("Monique", "Braun", 'F', '2000-08-22') N = ig.person("Noémie", "Adam", 'F', '2002-08-22') O = ig.person("Odette", "Adam", 'F', '2004-08-22') P = ig.person("Pascale", "Adam", 'F', '2004-08-22') yield ig.flush() ig.link(A, I, LinkTypes.parent) ig.link(A, N, LinkTypes.parent) ig.link(A, O, LinkTypes.parent) ig.link(A, P, LinkTypes.parent) ig.link(B, J, LinkTypes.parent) ig.link(B, K, LinkTypes.parent) ig.link(B, L, LinkTypes.parent) ig.link(B, M, LinkTypes.parent) ig.link(E, I, LinkTypes.parent) ig.link(E, J, LinkTypes.parent) ig.link(E, K, LinkTypes.parent) ig.link(E, L, LinkTypes.parent) ig.link(F, M, LinkTypes.parent) ig.link(F, N, LinkTypes.parent) ig.link(F, O, LinkTypes.parent) ig.link(F, P, LinkTypes.parent) ig.link(A, F, LinkTypes.spouse) ig.link(B, E, LinkTypes.spouse) yield ig.flush() if households: households.Household.create_household(ar, A, E, married) households.Household.create_household(ar, A, F, divorced) households.Household.create_household(ar, B, E, divorced) households.Household.create_household(ar, B, F, married)
def test01(self): # print("20180502 test_debts.test01()") # Member = rt.models.households.Member Household = rt.models.households.Household Person = rt.models.contacts.Person Genders = rt.models.system.Genders Budget = rt.models.debts.Budget Actor = rt.models.debts.Actor Entry = rt.models.debts.Entry def check_count(b, a, e): self.assertEqual(Budget.objects.count(), b) self.assertEqual(Actor.objects.count(), a) self.assertEqual(Entry.objects.count(), e) u = users.User(username='******', user_type=UserTypes.admin, language="en") u.save() # be = countries.Country(name="Belgium", isocode="BE") # be.save() # kw = dict() # # kw.update(card_number="123456789") # # kw.update(national_id="680601 053-29") # kw.update(id=116) # kw.update(first_name="Jean") # kw.update(middle_name="Jacques") # kw.update(last_name="Jeffin") # obj = pcsw.Client(**kw) # obj.full_clean() # obj.save() from lino_welfare.modlib.debts.fixtures.minimal import objects for o in objects(): o.save() # from lino_xl.lib.households.fixtures.std import objects # for o in objects(): # o.save() # Reproduce ticket #521 ar = rt.login('root') p1 = Person(first_name="A", last_name="A", gender=Genders.male) p1.save() p2 = Person(first_name="B", last_name="B", gender=Genders.female) p2.save() h = Household.create_household(ar, p1, p2, None) # The household has for whatever reason an empty member # entry. Lino should ignore this entry. h.add_member(None) check_count(0, 0, 0) b = Budget(partner=h, user=u) b.save() b.fill_defaults() # from django.utils.encoding import force_text # s = ' & '.join([force_text(a) for a in b.get_actors()]) # s = '{0} & {1}'.format(*b.get_actors()) # self.assertEqual(s, "Mr. & Mrs.") ## ## Reproduce ticket #159 ('NoneType' object is not iterable ## (after duplicating a budget)) and verify ticket #471 ## (Become the author after duplicating a budget). ## self.assertEqual(b.user.username, 'root') self.assertEqual(b.id, 1) ou = users.User(username='******', user_type=UserTypes.admin, language="en") ou.save() ar = rt.login('other') check_count(1, 2, 44) new = b.duplicate.run_from_code(ar) self.assertEqual(new.user.username, 'other') self.assertEqual(new.id, 2) check_count(2, 4, 88) new = Budget.objects.get(pk=2) self.assertEqual(new.user.username, 'other') url = "/api/debts/Budgets/1?&an=duplicate&sr=1" dlg = [] dlg.append(( "This will create a copy of Budget 1 for A & B A-B Are you sure?", 'yes')) dlg.append(( 'Duplicated Budget 1 for A & B A-B to Budget 3 for A & B A-B.', None)) self.check_callback_dialog(self.client.get, 'other', url, dlg) check_count(3, 6, 132) new = Budget.objects.get(pk=3) self.assertEqual(new.user.username, 'other')
def test_comment(self, logger): """Test what happens when a comment is posted on a ticket with watchers. """ ContentType = rt.models.contenttypes.ContentType Comment = rt.models.comments.Comment Ticket = rt.models.tickets.Ticket Project = rt.models.tickets.Project Vote = rt.models.votes.Vote Message = rt.models.notify.Message User = settings.SITE.user_model create(Project, name="Project") robin = create( User, username='******', first_name="Robin", user_type=UserTypes.admin) aline = create( User, username='******', first_name="Aline", email="*****@*****.**", language='fr') obj = create( Ticket, summary="Save the world, après moi le déluge", user=robin) create(Vote, votable=obj, user=aline) self.assertEqual(Message.objects.count(), 0) url = "/api/comments/CommentsByRFC" post_data = dict() post_data[constants.URL_PARAM_ACTION_NAME] = 'submit_insert' post_data.update(short_text="I don't agree.") post_data[constants.URL_PARAM_MASTER_PK] = obj.pk ct = ContentType.objects.get_for_model(Ticket) post_data[constants.URL_PARAM_MASTER_TYPE] = ct.id # post_data[constants.URL_PARAM_REQUESTING_PANEL] = '123' response = self.client.post( url, post_data, REMOTE_USER='******', HTTP_ACCEPT_LANGUAGE='en') result = self.check_json_result( response, 'rows success message close_window') self.assertEqual(result['success'], True) self.assertEqual( result['message'], """Comment "Comment #1" has been created.""") self.assertEqual(Message.objects.count(), 1) msg = Message.objects.all()[0] # self.assertEqual(msg.message_type) self.assertEqual(msg.seen, None) self.assertEqual(msg.user, aline) expected = """Robin a commenté [ticket 1] (Save the world, """\ """après moi le déluge): I don't agree.""" self.assertEqual(expected, msg.body) # manually set created timestamp so we can test on it later. now = datetime.datetime(2016, 12, 22, 19, 45, 55) if settings.USE_TZ: now = make_aware(now) msg.created = now msg.save() settings.SERVER_EMAIL = '*****@*****.**' with capture_stdout() as out: send_pending_emails_often() out = out.getvalue().strip() print(out) expected = """send email Sender: [email protected] To: [email protected] Subject: [Django] Robin a comment? #1 (? Save the world, apr?s moi le d?luge) <body> (22/12/2016 19:45) Robin a comment? <a href="http://127.0.0.1:8000/api/tickets/Ticket/1" title="Save the world, après moi le déluge">#1</a> (Save the world, apr?s moi le d?luge): I don't agree. </body> """ self.assertEquivalent(expected, out) self.assertEqual(logger.debug.call_count, 1) logger.debug.assert_called_with( 'Send out %s summaries for %d users.', MailModes.often, 1) # logger.info.assert_called_with( # 'Notify %s users about %s', 1, 'Change by robin') Message.objects.all().delete() self.assertEqual(Message.objects.count(), 0) ar = rt.login('robin') cw = ChangeWatcher(obj) obj.priority = 200 obj.save_watched_instance(ar, cw) with capture_stdout() as out: send_pending_emails_often() out = out.getvalue().strip() # print(out) expected = "" # self.assertEquivalent(expected, out) # we do not test the output because the datetime changes. But # we actually just wanted to see if there is no # UnicodeException. We capture it in order to hide it from # test runner output. self.assertEqual(logger.debug.call_count, 2) logger.debug.assert_called_with( 'Send out %s summaries for %d users.', MailModes.often, 1)
def objects(): yield lib_objects() Client = rt.modules.pcsw.Client ClientStates = rt.modules.pcsw.ClientStates Company = rt.modules.contacts.Company Journal = rt.modules.ledger.Journal AccountInvoice = rt.modules.vatless.AccountInvoice InvoiceItem = rt.modules.vatless.InvoiceItem Account = rt.modules.accounts.Account AccountTypes = rt.modules.accounts.AccountTypes PaymentOrder = rt.modules.finan.PaymentOrder PaymentOrderItem = rt.modules.finan.PaymentOrderItem CLIENTS = Cycler(Client.objects.filter(client_state=ClientStates.coached)[:5]) if len(CLIENTS) == 0: raise Exception("Oops, no CLIENTS in %s" % CLIENTS) qs = Company.objects.filter(sepa_accounts__iban__gt="").distinct() # RECIPIENTS = Cycler(qs[:5]) RECIPIENTS = Cycler(qs) if len(RECIPIENTS) == 0: raise Exception("Oops, no recipients in %s" % qs) ACCOUNTS = Cycler(Account.objects.filter(type=AccountTypes.expenses)) if len(ACCOUNTS) == 0: raise Exception("Oops, no ACCOUNTS in %s" % ACCOUNTS) AMOUNTS = Cycler(10, "12.50", 25, "29.95", 120, "5.33") ITEMNUMS = Cycler(1, 5, 1, 1, 7, 1) ses = rt.login("wilfried") REG = Journal.get_by_ref("REG") SREG = Journal.get_by_ref("SREG") for i in range(30): kw = dict() kw.update(partner=RECIPIENTS.pop()) # if i % 9 != 0: # kw.update(project=CLIENTS.pop()) kw.update(entry_date=dd.today(-5 * i)) kw.update(voucher_date=dd.today(-5 * i - 1)) kw.update(due_date=dd.today(30 - 5 * i)) kw.update(user=ses.get_user()) itemnum = ITEMNUMS.pop() acc = ACCOUNTS.pop() prj = CLIENTS.pop() if itemnum == 1: kw.update(journal=REG) kw.update(project=prj) else: kw.update(journal=SREG) obj = AccountInvoice(**kw) yield obj for j in range(itemnum): yield InvoiceItem(voucher=obj, amount=AMOUNTS.pop(), project=prj, account=acc) prj = CLIENTS.pop() obj.register(ses) obj.save() refs = ("832/3331/01", "832/330/01", "832/330/03F", "832/330/03", "832/3343/21", "832/334/27") ACCOUNTS = list(rt.modules.accounts.Account.objects.filter(ref__in=refs)) AMOUNTS = Cycler("648.91", "817.36", "544.91", "800.08") jnl = Journal.get_by_ref("AAW") for i in range(3): kw = dict() kw.update(entry_date=dd.today(-30 * i)) kw.update(voucher_date=dd.today(-30 * i)) kw.update(journal=jnl) kw.update(user=ses.get_user()) for acc in ACCOUNTS: kw.update(narration=acc.name) kw.update(item_account=acc) obj = PaymentOrder(**kw) yield obj for j in range(5): cli = CLIENTS.pop() yield PaymentOrderItem(seqno=j + 1, voucher=obj, amount=AMOUNTS.pop(), project=cli) # this is especially slow in a sqlite :memory: databae # dd.logger.info( # "20151211 Gonna register PaymentOrder %s %s %s", # dd.fds(obj.entry_date), obj, obj.narration) obj.register(ses) obj.save()
def objects(): Line = rt.models.courses.Line Teacher = dd.plugins.courses.teacher_model Course = rt.models.courses.Course Topic = rt.models.courses.Topic Enrolment = rt.models.courses.Enrolment User = rt.models.users.User EventType = rt.models.cal.EventType Guest = rt.models.cal.Guest GuestRole = rt.models.cal.GuestRole GuestStates = rt.models.cal.GuestStates EntryStates = rt.models.cal.EntryStates Event = rt.models.cal.Event Person = rt.models.contacts.Person CommentType = rt.models.comments.CommentType TrendStage = rt.models.trends.TrendStage TrendArea = rt.models.trends.TrendArea for area, stages in trends_config: ta = named(TrendArea, area) yield ta for stage in stages: yield named(TrendStage, stage, trend_area=ta) yield EventType(**dd.str2kw('name', _("First contact"))) kw = dd.str2kw('name', _("Lesson")) kw.update(dd.str2kw('event_label', _("Lesson"))) event_type = EventType(**kw) yield event_type pupil = named(GuestRole, _("Pupil")) yield pupil yield named(GuestRole, _("Assistant")) topic_citizen = named(Topic, _("Citizen course")) yield topic_citizen topic_lang = named(Topic, _("Language courses")) yield topic_lang kw.update(topic=topic_citizen) kw = dict(event_type=event_type, guest_role=pupil) yield named(Line, _("Citizen course"), **kw) kw.update(topic=topic_lang) alpha = named(Line, _("Alphabetisation"), **kw) yield alpha yield named(Line, _("German for beginners"), **kw) yield named(Line, _("German A1+"), **kw) yield named(Line, _("German A2"), **kw) yield named(Line, _("German A2 (women)"), **kw) yield named(CommentType, _("Phone call")) yield named(CommentType, _("Visit")) yield named(CommentType, _("Individual consultation")) yield named(CommentType, _("Internal meeting")) yield named(CommentType, _("Meeting with partners")) laura = Teacher(first_name="Laura", last_name="Lieblig") yield laura yield User(username="******", user_type=UserTypes.teacher, partner=laura) yield User(username="******", user_type=UserTypes.user) yield User(username="******", user_type=UserTypes.auditor) yield User(username="******", user_type=UserTypes.coordinator) yield User(username="******", user_type=UserTypes.secretary) USERS = Cycler(User.objects.exclude( user_type__in=(UserTypes.auditor, UserTypes.admin))) kw = dict(monday=True, tuesday=True, thursday=True, friday=True) kw.update( line=alpha, start_date=dd.demo_date(-30), start_time="9:00", end_time="12:00", max_date=dd.demo_date(10), every_unit=Recurrencies.daily, user=USERS.pop(), teacher=laura, max_places=5) yield Course(**kw) kw.update(start_time="14:00", end_time="17:00", user=USERS.pop()) yield Course(**kw) PUPILS = Cycler(dd.plugins.courses.pupil_model.objects.all()) # print(20170302, dd.plugins.courses.pupil_model.objects.all()) COURSES = Cycler(Course.objects.all()) STATES = Cycler(EnrolmentStates.objects()) def fits(course, pupil): if course.max_places and course.get_free_places() == 0: return False if Enrolment.objects.filter(course=course, pupil=pupil).count(): return False return True for i in range(10): course = COURSES.pop() pupil = PUPILS.pop() while not fits(course, pupil): course = COURSES.pop() kw = dict(user=USERS.pop(), course=course, pupil=pupil) kw.update(request_date=dd.demo_date(-i)) kw.update(state=STATES.pop()) yield Enrolment(**kw) ar = rt.login('robin') for obj in Course.objects.all(): obj.update_auto_events(ar) # Suggested calendar entries older than 7 days should be marked as # either took_place or cancelled. qs = Event.objects.filter( start_date__lte=dd.demo_date(-7), state=EntryStates.suggested) for i, obj in enumerate(qs): if i % 9: obj.state = EntryStates.took_place else: obj.state = EntryStates.cancelled obj.full_clean() obj.save() # participants of events which took place should be marked as # either absent or present or excused: qs = Guest.objects.filter( event__start_date__lte=dd.demo_date(-7), event__state=EntryStates.took_place) for i, obj in enumerate(qs): if i % 9: obj.state = GuestStates.present elif i % 3: obj.state = GuestStates.absent else: obj.state = GuestStates.excused obj.full_clean() obj.save()
def test_create_entry(self): ses = rt.login() Person = rt.models.app.Person Restaurant = rt.models.app.Restaurant Place = rt.models.app.Place Visit = rt.models.app.Visit Meal = rt.models.app.Meal # Create some initial data: Person(name="Alfred").save() Person(name="Bert").save() Person(name="Claude").save() Person(name="Dirk").save() r = Restaurant(id=1, name="First") r.save() for i in 1, 2: r.owners.add(Person.objects.get(pk=i)) for i in 3, 4: r.cooks.add(Person.objects.get(pk=i)) # Here is our data: lst = list(Person.objects.all()) self.assertEqual(str(lst), "[<Person: Alfred>, <Person: Bert>, <Person: Claude>, <Person: Dirk>]") lst = list(Restaurant.objects.all()) self.assertEqual( str(lst), "[Restaurant #1 ('First (owners=Alfred, Bert, cooks=Claude, Dirk)')]") x = list(Place.objects.all()) self.assertEqual( str(x), "[Place #1 ('First (owners=Alfred, Bert)')]") """ The :func:`delete_child` function --------------------------------- Imagine that a user of our application discovers that Restaurant #1 isn't actually a `Restaurant`, it's just a `Place`. They would like to "remove it's Restaurant data" from the database, but keep the `Place` data. Especially the primary key (#1) and the related objects (the owners) should remain unchanged. But the cooks must be deleted since they exist only for restaurants. It seems that this is not trivial in Django (`How do you delete child class object without deleting parent class object? <http://stackoverflow.com/questions/9439730>`__). That's why we wrote the :func:`delete_child` function. Here is how to "reduce" a Restaurant to a `Place` by calling the :func:`delete_child` function: """ from lino.utils.mti import delete_child p = Place.objects.get(id=1) delete_child(p, Restaurant) # The Place still exists, but no longer as a Restaurant: x = Place.objects.get(pk=1) self.assertEqual( str(x), "First (owners=Alfred, Bert)") try: list(Restaurant.objects.get(pk=1)) self.fail("Expected DoesNotExist") except Restaurant.DoesNotExist: pass # Traceback (most recent call last): # ... # DoesNotExist: Restaurant matching query does not exist. """ The :func:`insert_child` function ---------------------------------- The opposite operation, "promoting a simple Place to a Restaurant", is done using :func:`insert_child`. from lino.utils.mti import insert_child Let's first create a simple Place #2 with a single owner. """ obj = Place(id=2, name="Second") obj.save() obj.owners.add(Person.objects.get(pk=2)) obj.save() self.assertEqual( str(obj), "Second (owners=Bert)") # Now this Place becomes a Restaurant and hires 2 cooks: obj = insert_child(obj, Restaurant) for i in 3, 4: obj.cooks.add(Person.objects.get(pk=i)) self.assertEqual( str(obj), "Second (owners=Bert, cooks=Claude, Dirk)") # If you try to promote a Person to a Restaurant, you'll get an exception: person = Person.objects.get(pk=2) try: insert_child(person, Restaurant).save() self.fail("Expected ValidationError") except ValidationError as e: self.assertEqual( str(e), "['A Person cannot be parent for a Restaurant']") """ The :class:`EnableChild` virtual field -------------------------------------- This section shows how the :class:`EnableChild` virtual field is being used by Lino, and thus is Lino-specific. After the above examples our database looks like this: """ x = list(Person.objects.all()) self.assertEqual( str(x), "[<Person: Alfred>, <Person: Bert>, <Person: Claude>, <Person: Dirk>]") x = list(Place.objects.all()) self.assertEqual( str(x), "[Place #1 ('First (owners=Alfred, Bert)'), Place #2 ('Second (owners=Bert)')]") x = list(Restaurant.objects.all()) self.assertEqual( str(x), "[Restaurant #2 ('Second (owners=Bert, cooks=Claude, Dirk)')]") # Let's take Place #1 and look at it. obj = Place.objects.get(pk=1) self.assertEqual( str(obj), "First (owners=Alfred, Bert)") # How to see whether a given Place is a Restaurant? x = "" for i in Place.objects.all(): x += "{0} -> {1}\n".format(i, i.get_mti_child('restaurant')) self.assertEqual( x, """\ First (owners=Alfred, Bert) -> None Second (owners=Bert) -> Second (owners=Bert, cooks=Claude, Dirk) """) # Let's promote First (currently a simple Place) to a Restaurant: x = insert_child(obj, Restaurant) # Restaurant #1 ('#1 (name=First, owners=Alfred, Bert, cooks=)') # And Second stops being a Restaurant: second = Place.objects.get(pk=2) delete_child(second, Restaurant) # This operation has removed the related Restaurant instance: try: Restaurant.objects.get(pk=2) self.fail("Expected DoesNotExist") except Restaurant.DoesNotExist: pass # And finally, rather to explain why Restaurants sometimes # close and later reopen: bert = Person.objects.get(pk=2) second = Place.objects.get(pk=2) insert_child(second, Restaurant) # Restaurant #2 ('#2 (name=Second, owners=Bert, cooks=)') # Now we can see this place again as a Restaurant second = Restaurant.objects.get(pk=2) # And engage for example a new cook: second.cooks.add(bert) # second # Restaurant #2 ('#2 (name=Second, owners=Bert, cooks=Bert)') # Related objects # --------------- # Now let's have a more detailed look at what happens to the related # objects (Person, Visit and Meal). # Bert, the owner of Restaurant #2 does two visits: second = Restaurant.objects.get(pk=2) Visit(purpose="Say hello", person=bert, place=second).save() Visit(purpose="Hang around", person=bert, place=second).save() x = list(second.visit_set.all()) self.assertEqual( str(x), "[<Visit: Say hello visit by Bert at Second>, <Visit: Hang around visit by Bert at Second>]") # Claude and Dirk, now workless, still go to eat in restaurants: Meal(what="Fish",person=Person.objects.get(pk=3),restaurant=second).save() Meal(what="Meat",person=Person.objects.get(pk=4),restaurant=second).save() x = list(second.meal_set.all()) self.assertEqual( str(x), "[<Meal: Claude eats Fish at Second>, <Meal: Dirk eats Meat at Second>]") # Now we reduce Second to a Place: second = Place.objects.get(pk=2) delete_child(second, Restaurant) # Restaurant #2 no longer exists: try: Restaurant.objects.get(pk=2) self.fail("Expected DoesNotExist") except Restaurant.DoesNotExist: pass # Note that `Meal` has :attr:`allow_cascaded_delete # <lino.core.model.Model.allow_cascaded_delete>` set to # `['restaurant']`, otherwise the above code would have raised a # ValidationError :message:`Cannot delete #2 # (name=Second,owners=Bert,cooks=Bert) because 2 meals refer to it.` But # the meals have been deleted: self.assertEqual(Meal.objects.count(), 0) # Of course, #2 remains as a Place # The owner and visits have been taken over: second = Place.objects.get(pk=2) x = list(second.visit_set.all()) self.assertEqual( str(x), "[<Visit: Say hello visit by Bert at Second>, <Visit: Hang around visit by Bert at Second>]") # The :func:`create_mti_child` function # ------------------------------------- # This function is for rather internal use. :ref:`Python dumps <dpy>` # generated by :class:`lino.utils.dpy.Serializer` use this function for # creating MTI children instances without having to lookup their parent. # .. currentmodule:: lino.utils.dpy # In a Python dump we are in a special situation: All Place instances # are being generated first, and in another step we are going to create # all the Restaurant instances. So how can we create a Restaurant whose # Place already exists *without first having to do a lookup of the Place # record*? That's why :func:`create_mti_child` was written for. obj = Place(id=3, name="Third") obj.save() obj.owners.add(Person.objects.get(pk=2)) obj.save() self.assertEqual( str(obj), "Third (owners=Bert)") from lino.utils.dpy import create_mti_child obj = create_mti_child(Place, 3, Restaurant) # The return value is technically a normal model instance, # but whose `save` and `full_clean` methods have been # patched: `full_clean` is overridden to do nothing, # and `save` will call a "raw" save to avoid the # need of a proper Place instance for that Restaurant. # The only thing you can do with it is to save it: obj.save() # The `save` and `full_clean` methods are the only methods that # will be called by # :class:`lino.utils.dpy.Deserializer`. # To test whether :func:`create_mti_child` did her job, # we must re-read an instance: obj = Restaurant.objects.get(pk=3) self.assertEqual( str(obj), "Third (owners=Bert, cooks=)") # Note that :func:`create_mti_child` supports changing the # `name` although that field is defined in the Place model, # not in Restaurant. This feature was added 20170626 (#1926, # #1923). Before that date Lino raised an exception when you # specified a field of the parent model. And before *that* # (until 20120930) this case was silently ignored for # backwards compatibility (`/blog/2011/1210`). obj = Place(id=4, name="Fourth") obj.save() ow = create_mti_child(Place, 4, Restaurant, name="A new name") ow.full_clean() ow.save() obj = Restaurant.objects.get(id=4) self.assertEqual(obj.name, "A new name")
def test01(self): u = users.User(username='******', profile=UserTypes.admin, language="en") u.save() # be = countries.Country(name="Belgium", isocode="BE") # be.save() # kw = dict() # # kw.update(card_number="123456789") # # kw.update(national_id="680601 053-29") # kw.update(id=116) # kw.update(first_name="Jean") # kw.update(middle_name="Jacques") # kw.update(last_name="Jeffin") # obj = pcsw.Client(**kw) # obj.full_clean() # obj.save() from lino_welfare.modlib.debts.fixtures.minimal import objects for o in objects(): o.save() # from lino_xl.lib.households.fixtures.std import objects # for o in objects(): # o.save() # Reproduce ticket #521 ar = rt.login('root') # Member = rt.modules.households.Member Household = rt.modules.households.Household Person = rt.modules.contacts.Person Genders = rt.modules.system.Genders Budget = rt.modules.debts.Budget p1 = Person(first_name="A", last_name="A", gender=Genders.male) p1.save() p2 = Person(first_name="B", last_name="B", gender=Genders.female) p2.save() h = Household.create_household(ar, p1, p2, None) # The household has for whatever reason an empty member # entry. Lino should ignore this entry. h.add_member(None) b = Budget(partner=h, user=u) b.save() b.fill_defaults() # from django.utils.encoding import force_text # s = ' & '.join([force_text(a) for a in b.get_actors()]) # s = '{0} & {1}'.format(*b.get_actors()) # self.assertEqual(s, "Mr. & Mrs.") ## ## Reproduce ticket #159 ('NoneType' object is not iterable ## (after duplicating a budget)) and verify ticket #471 ## (Become the author after duplicating a budget). ## self.assertEqual(b.user.username, 'root') self.assertEqual(b.id, 1) ou = users.User(username='******', profile=UserTypes.admin, language="en") ou.save() ar = rt.login('other') new = b.duplicate.run_from_code(ar) self.assertEqual(new.user.username, 'other') self.assertEqual(new.id, 2) # new.save() # must save after on_duplicate new = rt.modules.debts.Budget.objects.get(pk=2) self.assertEqual(new.user.username, 'other') url = "/api/debts/Budgets/1?&an=duplicate&sr=1" res = test_client.get(url, REMOTE_USER='******') rv = json.loads(res.content) self.assertEqual( rv['message'], u'Duplicated Budget 1 for A-B to Budget 3 for A-B.') new = rt.modules.debts.Budget.objects.get(pk=3) self.assertEqual(new.user.username, 'other')
def test01(self): from lino.modlib.users.choicelists import UserTypes Ticket = rt.models.tickets.Ticket # Project = rt.models.tickets.Project # Line = rt.models.courses.Line # Activity = rt.models.courses.Course # Enrolment = rt.models.courses.Enrolment Meeting = rt.models.meetings.Meeting Change = rt.models.changes.Change User = rt.models.users.User Vote = rt.models.votes.Vote VoteStates = rt.models.votes.VoteStates VotesByVotable = rt.models.votes.VotesByVotable # ContentType = rt.models.contenttypes.ContentType # ct_Ticket = ContentType.objects.get_for_model(Ticket) # create(Project, name='project') robin = create(User, username='******', first_name="Robin", user_type=UserTypes.admin, language="en") anna = create(User, username='******', first_name="Anna", user_type=UserTypes.user, language="en") berta = create(User, username='******', first_name="Berta", user_type=UserTypes.user, language="en") meeting = create(Meeting, name="Test") # sprints = create(Line, name="Sprints") # sprint = create(Activity, line=sprints) # # Enrolment(course=sprint, pupil=robin) ses = rt.login('robin') ticket = create(Ticket, summary="First", user=robin) ticket.after_ui_save(ses, None) vote = Vote.objects.get(votable=ticket) self.assertEqual(vote.user, robin) self.assertEqual(vote.state, VoteStates.author) def check_success(ia, **kwargs): rv = ia.run_from_session(ses, **kwargs) self.assertEqual(rv, {'success': True, 'refresh': True}) check_success(ticket.mark_talk) check_success(ticket.mark_started) check_success(ticket.mark_refused) check_success(ticket.mark_closed) check_success(ticket.mark_refused) Vote.objects.all().delete() Ticket.objects.all().delete() self.assertEqual(Vote.objects.count(), 0) ticket = create( Ticket, summary="Second", user=robin, end_user=anna) ticket.after_ui_save(ses, None) self.assertEqual(Vote.objects.count(), 2) vote = Vote.objects.get(votable=ticket, user=anna) self.assertEqual(vote.state, VoteStates.author) # manually creating a vote will make the vote invited: vote = create( Vote, votable=ticket, user=berta) # vote.after_ui_save(ses, None) self.assertEqual(vote.state, VoteStates.invited)
def handle(self, *args, **options): ses = rt.login() ses.run(settings.SITE.site_config.check_all_summaries)
def objects(): Member = rt.models.households.Member MemberRoles = rt.models.households.MemberRoles Person = dd.plugins.households.person_model Type = rt.models.households.Type Household = rt.models.households.Household men = Person.objects.filter(gender=dd.Genders.male).order_by('-id') women = Person.objects.filter(gender=dd.Genders.female).order_by('-id') if dd.is_installed('humanlinks'): # avoid interference with persons created by humanlinks demo # because these have already their households: men = men.filter(household_members__isnull=True) men = men.filter(humanlinks_children__isnull=True) men = men.filter(humanlinks_parents__isnull=True) women = women.filter(humanlinks_children__isnull=True) women = women.filter(humanlinks_parents__isnull=True) women = women.filter(household_members__isnull=True) MEN = Cycler(men) WOMEN = Cycler(women) TYPES = Cycler(Type.objects.all()) if not len(MEN) or not len(WOMEN): raise Exception( "Not enough persons in {} and {} (all: {})".format( men, women, Person.objects.all())) # avoid automatic creation of children # loading_from_dump = settings.SITE.loading_from_dump # settings.SITE.loading_from_dump = True ses = rt.login() for i in range(5): pv = dict( head=MEN.pop(), partner=WOMEN.pop(), type=TYPES.pop()) ses.run( Person.create_household, action_param_values=pv) # yield ses.response['data_record'] # he = MEN.pop() # she = WOMEN.pop() # fam = Household(name=he.last_name + "-" + she.last_name, type_id=3) # yield fam # yield Member(household=fam, person=he, role=Role.objects.get(pk=1)) # yield Member(household=fam, person=she, role=Role.objects.get(pk=2)) i = 0 for m in Member.objects.filter(role=MemberRoles.head): i += 1 if i % 3 == 0: m.end_date = i2d(20020304) yield m pv = dict( head=m.person, partner=WOMEN.pop(), type=TYPES.pop()) ses.run( Person.create_household, action_param_values=pv) if False: # dd.is_installed('addresses'): Address = rt.models.addresses.Address children = set() for h in Household.objects.all(): for m in Member.objects.filter(household=h, primary=True): addr = Address.objects.get( partner=m.person, primary=True) if m.role == MemberRoles.head: addr.partner = h addr.full_clean() addr.save() else: addr.delete() children.add(m.person) h.sync_primary_address_() for p in children: p.sync_primary_address_()
def objects(): Line = rt.models.courses.Line Teacher = dd.plugins.courses.teacher_model Course = rt.models.courses.Course Topic = rt.models.courses.Topic Enrolment = rt.models.courses.Enrolment CourseStates = rt.models.courses.CourseStates User = rt.models.users.User EventType = rt.models.cal.EventType Guest = rt.models.cal.Guest GuestRole = rt.models.cal.GuestRole GuestStates = rt.models.cal.GuestStates EntryStates = rt.models.cal.EntryStates Event = rt.models.cal.Event Person = rt.models.contacts.Person CommentType = rt.models.comments.CommentType TrendStage = rt.models.trends.TrendStage TrendArea = rt.models.trends.TrendArea for area, stages in trends_config: ta = named(TrendArea, area) yield ta for stage in stages: kw = dict(trend_area=ta) if stage[0] == "!": stage = stage[1:] kw.update(subject_column=True) yield named(TrendStage, stage, **kw) yield EventType(**dd.str2kw('name', _("First contact"))) kw = dd.str2kw('name', _("Lesson")) kw.update(dd.str2kw('event_label', _("Lesson"))) event_type = EventType(**kw) yield event_type pupil = named(GuestRole, _("Pupil")) yield pupil yield named(GuestRole, _("Assistant")) topic_citizen = named(Topic, _("Citizen course")) yield topic_citizen topic_lang = named(Topic, _("Language courses")) yield topic_lang kw.update(topic=topic_citizen) kw = dict(event_type=event_type, guest_role=pupil) yield named(Line, _("Citizen course"), **kw) kw.update(topic=topic_lang) alpha = named(Line, _("Alphabetisation"), **kw) yield alpha yield named(Line, _("German for beginners"), **kw) yield named(Line, _("German A1+"), **kw) yield named(Line, _("German A2"), **kw) yield named(Line, _("German A2 (women)"), **kw) yield named(CommentType, _("Phone call")) yield named(CommentType, _("Visit")) yield named(CommentType, _("Individual consultation")) yield named(CommentType, _("Internal meeting")) yield named(CommentType, _("Meeting with partners")) laura = Teacher(first_name="Laura", last_name="Lieblig") yield laura yield User(username="******", user_type=UserTypes.teacher, partner=laura) yield User(username="******", user_type=UserTypes.user) yield User(username="******", user_type=UserTypes.user) yield User(username="******", user_type=UserTypes.auditor) yield User(username="******", user_type=UserTypes.coordinator) yield User(username="******", user_type=UserTypes.secretary) USERS = Cycler( User.objects.exclude(user_type__in=(UserTypes.auditor, UserTypes.admin))) kw = dict(monday=True, tuesday=True, thursday=True, friday=True) kw.update(line=alpha, start_date=dd.demo_date(-30), start_time="9:00", end_time="12:00", max_date=dd.demo_date(10), state=CourseStates.active, every_unit=Recurrencies.daily, user=USERS.pop(), teacher=laura, max_places=5) yield Course(**kw) kw.update(start_time="14:00", end_time="17:00", user=USERS.pop(), max_places=15) yield Course(**kw) kw.update(start_time="18:00", end_time="20:00", user=USERS.pop(), max_places=15) yield Course(**kw) PUPILS = Cycler(dd.plugins.courses.pupil_model.objects.all()) # print(20170302, dd.plugins.courses.pupil_model.objects.all()) COURSES = Cycler(Course.objects.all()) STATES = Cycler(EnrolmentStates.objects()) def fits(course, pupil): if course.max_places and course.get_free_places() == 0: return False if Enrolment.objects.filter(course=course, pupil=pupil).count(): return False return True def enrol(pupil): course = COURSES.pop() if fits(course, pupil): kw = dict(user=USERS.pop(), course=course, pupil=pupil) kw.update(request_date=dd.demo_date(-i)) kw.update(state=STATES.pop()) return Enrolment(**kw) for i, p in enumerate( dd.plugins.courses.pupil_model.objects.order_by('id')): yield enrol(p) if i % 2 == 0: yield enrol(p) if i % 3 == 0: yield enrol(p) ar = rt.login('robin') for obj in Course.objects.all(): obj.update_auto_events(ar) # Suggested calendar entries older than 7 days should be marked as # either took_place or cancelled. qs = Event.objects.filter(start_date__lte=dd.demo_date(-7), state=EntryStates.suggested) for i, obj in enumerate(qs): if i % 9: obj.state = EntryStates.took_place else: obj.state = EntryStates.cancelled obj.full_clean() obj.save() # participants of events which took place should be marked as # either absent or present or excused: qs = Guest.objects.filter( event__start_date__lte=dd.demo_date(-7), event__state=EntryStates.took_place).order_by('id') STATES = Cycler(GuestStates.get_list_items()) for i, obj in enumerate(qs): obj.state = STATES.pop() # if i % 8: # obj.state = GuestStates.present # elif i % 3: # obj.state = GuestStates.missing # else: # obj.state = GuestStates.excused obj.full_clean() obj.save()
def test_checkin_guest(self): """Test whether notifications are being emitted. - when a visitor checks in - when a client is modified - when a coaching is modified """ User = settings.SITE.user_model Message = rt.models.notify.Message Note = rt.models.notes.Note NoteType = rt.models.notes.EventType Guest = rt.models.cal.Guest Event = rt.models.cal.Event EventType = rt.models.cal.EventType Client = rt.models.pcsw.Client Coaching = rt.models.pcsw.Coaching ContentType = rt.models.contenttypes.ContentType self.create_obj( User, username='******', profile=UserTypes.admin) caroline = self.create_obj( User, username='******', profile='200') alicia = self.create_obj( User, username='******', first_name="Alicia", profile='100') roger = self.create_obj( User, username='******', profile='400') ses = rt.login('robin') first = self.create_obj( Client, first_name="First", last_name="Client") second = self.create_obj( Client, first_name="Second", last_name="Client") self.create_obj( Coaching, client=second, start_date=i2d(20130501), end_date=i2d(20140501), user=caroline) second_roger = self.create_obj( Coaching, client=second, start_date=i2d(20140501), user=roger) self.create_obj( Coaching, client=second, start_date=i2d(20140520), user=alicia) nt = self.create_obj(NoteType, name="System note") sc = settings.SITE.site_config sc.system_note_type = nt sc.save() consultation = self.create_obj(EventType, name="consultation") # gr = self.create_obj(GuestRole, name="client") event = self.create_obj( Event, event_type=consultation, user=caroline) guest = self.create_obj(Guest, event=event, partner=first) self.assertEqual(str(guest), 'Presence #1 (22.05.2014)') # Checkin a guest res = ses.run(guest.checkin) self.assertEqual(res, { 'message': '', 'success': True, 'refresh': True}) # it has caused a notification message: self.assertEqual(Message.objects.count(), 1) # id does *not* cause a system note: self.assertEqual(Note.objects.count(), 0) # When a client is modified, all active coaches get a # notification. # Note that Caroline doesn't get a notification because this # coaching is not active. # Alicia doesn't get a notification because she did it herself. data = dict(first_name="Seconda", an="submit_detail") kwargs = dict(data=urlencode(data)) kwargs['REMOTE_USER'] = '******' url = '/api/pcsw/Clients/{}'.format(second.pk) res = self.client.put(url, **kwargs) self.assertEqual(res.status_code, 200) self.assertEqual(Message.objects.count(), 2) # self.check_notifications() self.check_notifications(""" +------------------------------------------------------------------------+------------------------+-----------+ | Body | Controlled by | Recipient | +========================================================================+========================+===========+ | | | caroline | +------------------------------------------------------------------------+------------------------+-----------+ | [CLIENT Seconda (101)](javascript:Lino.pcsw.Clients.detail.run\(null,{ | *CLIENT Seconda (101)* | roger | | "record_id": 101 }\)) has been modified by Alicia: | | | | | | | | * **Name** : 'Client Second' --> 'Client Seconda' | | | | * **First name** : 'Second' --> 'Seconda' | | | +------------------------------------------------------------------------+------------------------+-----------+ """) # When a coaching is modified, all active coaches of that # client get a notification. Message.objects.all().delete() data = dict(start_date="02.05.2014", an="grid_put") data.update(mt=51) data.update(mk=second.pk) kwargs = dict(data=urlencode(data)) kwargs['REMOTE_USER'] = '******' url = '/api/pcsw/CoachingsByClient/{}'.format(second_roger.pk) res = self.client.put(url, **kwargs) self.assertEqual(res.status_code, 200) self.check_notifications(""" +-----------------------------------------------------+------------------------+-----------+ | Body | Controlled by | Recipient | +=====================================================+========================+===========+ | **roger / Client S** has been modified by Alicia: | *CLIENT Seconda (101)* | roger | | | | | | * **Coached from** : 2014-05-01 --> 2014-05-02 | | | +-----------------------------------------------------+------------------------+-----------+ """) # AssignCoach. we are going to Assign caroline as coach for # first client. # Request URL:http://127.0.0.1:8000/api/newcomers/AvailableCoachesByClient/5?_dc=1469707129689&fv=EVERS%20Eberhart%20(127)%20assigned%20to%20Hubert%20Huppertz%20&fv=EVERS%20Eberhart%20(127)%20is%20now%20coached%20by%20Hubert%20Huppertz%20for%20Laufende%20Beihilfe.&fv=false&mt=48&mk=127&an=assign_coach&sr=5 # Request Method:GET # fv:EVERS Eberhart (127) assigned to Hubert Huppertz # fv:EVERS Eberhart (127) is now coached by Hubert Huppertz for Laufende Beihilfe. # fv:false # mt:48 # mk:127 # an:assign_coach # sr:5 Message.objects.all().delete() # self.assertEqual(Coaching.objects.count(), 1) self.check_coachings(""" ==== ====================== ============== ============ ========== ========= ID Client Coached from until Coach Primary ---- ---------------------- -------------- ------------ ---------- --------- 1 CLIENT Seconda (101) 01/05/2013 01/05/2014 caroline No 2 CLIENT Seconda (101) 02/05/2014 roger No 3 CLIENT Seconda (101) 20/05/2014 Alicia No ==== ====================== ============== ============ ========== ========= """) self.assertEqual(Note.objects.count(), 0) data = dict( fv=["First CLIENT assigned to caroline", "Body", 'false'], an="assign_coach") data.update(mt=ContentType.objects.get_for_model(Client).pk) data.update(mk=first.pk) kwargs = dict(data=data) # kwargs = dict(data=urlencode(data)) kwargs['REMOTE_USER'] = '******' url = '/api/newcomers/AvailableCoachesByClient/{}'.format( caroline.pk) res = self.client.get(url, **kwargs) self.assertEqual(res.status_code, 200) # self.check_notifications() self.check_notifications(""" ======================================== =============== =========== Body Controlled by Recipient ---------------------------------------- --------------- ----------- First CLIENT assigned to caroline Body caroline ======================================== =============== =========== """) self.check_coachings(""" ==== ====================== ============== ============ ========== ========= ID Client Coached from until Coach Primary ---- ---------------------- -------------- ------------ ---------- --------- 1 CLIENT Seconda (101) 01/05/2013 01/05/2014 caroline No 2 CLIENT Seconda (101) 02/05/2014 roger No 3 CLIENT Seconda (101) 20/05/2014 Alicia No 4 CLIENT First (100) 22/05/2014 caroline No ==== ====================== ============== ============ ========== ========= """) self.check_notes(""" ==== ======== ==================== =================================== ID Author Client Subject ---- -------- -------------------- ----------------------------------- 1 Alicia CLIENT First (100) First CLIENT assigned to caroline ==== ======== ==================== =================================== """) # Mark client as former # Request URL:http://127.0.0.1:8000/api/pcsw/Clients/181?_dc=1469714189945&an=mark_former&sr=181 # Request Method:GET # an:mark_former Message.objects.all().delete() Note.objects.all().delete() data = dict(an="mark_former") kwargs = dict(data=data) # kwargs = dict(data=urlencode(data)) kwargs['REMOTE_USER'] = '******' url = '/api/pcsw/Clients/{}'.format(second.pk) res = self.client.get(url, **kwargs) self.assertEqual(res.status_code, 200) res = AttrDict(json.loads(res.content)) self.assertEqual( res.message, 'This will end 2 coachings of CLIENT Seconda (101).') self.assertEqual(res.xcallback['title'], "Confirmation") kwargs = dict() kwargs['REMOTE_USER'] = '******' url = '/callbacks/{}/yes'.format(res.xcallback['id']) res = self.client.get(url, **kwargs) self.assertEqual(res.status_code, 200) res = AttrDict(json.loads(res.content)) self.assertEqual( res.message, 'Alicia marked CLIENT Seconda (101) as <b>Former</b>.') self.assertTrue(res.success) self.check_notifications(""" =================================================== ======================== =========== Body Controlled by Recipient --------------------------------------------------- ------------------------ ----------- Alicia marked CLIENT Seconda (101) as **Former**. *CLIENT Seconda (101)* roger =================================================== ======================== =========== """) # check two coachings have now an end_date set: self.check_coachings(""" ==== ====================== ============== ============ ========== ========= ID Client Coached from until Coach Primary ---- ---------------------- -------------- ------------ ---------- --------- 1 CLIENT Seconda (101) 01/05/2013 01/05/2014 caroline No 2 CLIENT Seconda (101) 02/05/2014 22/05/2014 roger No 3 CLIENT Seconda (101) 20/05/2014 22/05/2014 Alicia No 4 CLIENT First (100) 22/05/2014 caroline No ==== ====================== ============== ============ ========== ========= """) self.check_notes(""" ==== ======== ====================== ====================================================== ID Author Client Subject ---- -------- ---------------------- ------------------------------------------------------ 2 Alicia CLIENT Seconda (101) Alicia marked CLIENT Seconda (101) as <b>Former</b>. ==== ======== ====================== ====================================================== """) # # RefuseClient # Message.objects.all().delete() Note.objects.all().delete() data = dict(fv=["20", ""], an="refuse_client") kwargs = dict(data=data) # kwargs = dict(data=urlencode(data)) kwargs['REMOTE_USER'] = '******' url = '/api/pcsw/Clients/{}'.format(first.pk) res = self.client.get(url, **kwargs) self.assertEqual(res.status_code, 200) self.check_notifications(""" ======================================================================== ====================== =========== Body Controlled by Recipient ------------------------------------------------------------------------ ---------------------- ----------- Alicia marked CLIENT First (100) as **Refused**. PCSW is not competent *CLIENT First (100)* caroline ======================================================================== ====================== =========== """) self.check_notes(""" ==== ======== ==================== ===================================================== ID Author Client Subject ---- -------- -------------------- ----------------------------------------------------- 3 Alicia CLIENT First (100) Alicia marked CLIENT First (100) as <b>Refused</b>. ==== ======== ==================== ===================================================== """)
def test_this(self): from lino.api import rt from lino.core.renderer import TestRenderer UserTypes = rt.models.users.UserTypes rt.models.users.User( username="******", user_type=UserTypes.admin).save() ses = rt.login('robin', renderer=TestRenderer()) s = ses.show('changes.Changes') self.assertEqual(s, "No data to display") rr = rt.models.contacts.Companies.required_roles self.assertTrue(ses.user.user_type.role.satisfies_requirement(rr)) # We create a new organization: url = '/api/contacts/Companies' data = dict(an='submit_insert', name='My pub') res = self.post_json_dict('robin', url, data) self.assertEqual( res.message, 'Organization "My pub" has been created.') s = ses.show('changes.Changes', column_names="id type master object diff") # print(s) expected = """\ ==== ============= ========== ===================== =============================================== ID Change Type Master Object Changes ---- ------------- ---------- --------------------- ----------------------------------------------- 1 Create *My pub* `My pub <Detail>`__ Company(id=100,name='My pub',partner_ptr=100) ==== ============= ========== ===================== =============================================== """ self.assertEqual(s, expected) url = '/api/contacts/Companies/100' data = "an=submit_detail&name=Our%20pub" res = self.put_json_dict('robin', url, data) self.assertEqual( res.message, 'Organization "Our pub" has been updated.') output = ses.show('changes.Changes', column_names="id type master object diff") # print(output) expected = """\ ==== ============= =========== ====================== =============================================== ID Change Type Master Object Changes ---- ------------- ----------- ---------------------- ----------------------------------------------- 2 Update *Our pub* `Our pub <Detail>`__ name : 'My pub' --> 'Our pub' 1 Create *Our pub* `Our pub <Detail>`__ Company(id=100,name='My pub',partner_ptr=100) ==== ============= =========== ====================== =============================================== """ self.assertEqual(output, expected) # We add an entry: url = '/api/entries/Entries' data = dict(an='submit_insert', subject='test', companyHidden=100) res = self.post_json_dict('robin', url, data) if six.PY2: self.assertEqual( res.message, 'Entry "Entry object" has been created.') expected = """\ ==== ============= =========== =========================== =============================================== ID Change Type Master Object Changes ---- ------------- ----------- --------------------------- ----------------------------------------------- 3 Create *Our pub* `Entry object <Detail>`__ Entry(id=1,user=1,subject='test',company=100) 2 Update *Our pub* `Our pub <Detail>`__ name : 'My pub' --> 'Our pub' 1 Create *Our pub* `Our pub <Detail>`__ Company(id=100,name='My pub',partner_ptr=100) ==== ============= =========== =========================== =============================================== """ else: self.assertEqual( res.message, 'Entry "Entry object (1)" has been created.') expected = """\ ==== ============= =========== =============================== =============================================== ID Change Type Master Object Changes ---- ------------- ----------- ------------------------------- ----------------------------------------------- 3 Create *Our pub* `Entry object (1) <Detail>`__ Entry(id=1,user=1,subject='test',company=100) 2 Update *Our pub* `Our pub <Detail>`__ name : 'My pub' --> 'Our pub' 1 Create *Our pub* `Our pub <Detail>`__ Company(id=100,name='My pub',partner_ptr=100) ==== ============= =========== =============================== =============================================== """ output = ses.show('changes.Changes', column_names="id type master object diff") # print(output) self.assertEqual(output, expected) # Now we delete the entry: url = '/api/entries/Entries/1' data = dict(an='delete_selected', sr=1) res = self.get_json_dict('robin', url, data) if six.PY2: self.assertEqual( res.message, """\ You are about to delete 1 Entry: Entry object Are you sure ?""") else: self.assertEqual( res.message, """\ You are about to delete 1 Entry: Entry object (1) Are you sure ?""") # We answer "yes": url = "/callbacks/{0}/yes".format(res['xcallback']['id']) res = self.get_json_dict('robin', url, {}) # r = test_client.get(url) self.assertEqual(res.success, True) self.assertEqual(res.record_deleted, True) expected = """\ ==== ============= =========== ====================== =============================================== ID Change Type Master Object Changes ---- ------------- ----------- ---------------------- ----------------------------------------------- 4 Delete *Our pub* Entry(id=1,user=1,subject='test',company=100) 3 Create *Our pub* Entry(id=1,user=1,subject='test',company=100) 2 Update *Our pub* `Our pub <Detail>`__ name : 'My pub' --> 'Our pub' 1 Create *Our pub* `Our pub <Detail>`__ Company(id=100,name='My pub',partner_ptr=100) ==== ============= =========== ====================== =============================================== """ output = ses.show('changes.Changes', column_names="id type master object diff") # print(output) self.assertEqual(output, expected) # Note how the `object` column of the first two rows in above # table is empty. That's because the entry object has been # deleted, so it does no longer exist in the database and Lino # cannot point to it. But note also that `object` is a # "nullable Generic ForeignKey", the underlying fields # `object_id` and `object_type` still contain their # values. Here is the same table with "Object" split into its # components: expected = """\ ==== ============= =========== ============== =========== =============================================== ID Change Type Master Object type object id Changes ---- ------------- ----------- -------------- ----------- ----------------------------------------------- 4 Delete *Our pub* Entry 1 Entry(id=1,user=1,subject='test',company=100) 3 Create *Our pub* Entry 1 Entry(id=1,user=1,subject='test',company=100) 2 Update *Our pub* Organization 100 name : 'My pub' --> 'Our pub' 1 Create *Our pub* Organization 100 Company(id=100,name='My pub',partner_ptr=100) ==== ============= =========== ============== =========== =============================================== """ output = ses.show('changes.Changes', column_names="id type master object_type object_id diff") # print(output) self.assertEqual(output, expected) # Until 20150626 only the # :attr:`object<lino.modlib.changes.models.Change.object>` was nullable, # not the :attr:`master<lino.modlib.changes.models.Change.master>`. But # now you can also delete the master, and all change records will still # remain: url = '/api/contacts/Companies/100' data = dict(an='delete_selected', sr=100) res = self.get_json_dict('robin', url, data) url = "/callbacks/{0}/yes".format(res.xcallback['id']) self.get_json_dict('robin', url, {}) expected = """\ ==== ============= ======== ======== ================================================ ID Change Type Master Object Changes ---- ------------- -------- -------- ------------------------------------------------ 5 Delete Company(id=100,name='Our pub',partner_ptr=100) 4 Delete Entry(id=1,user=1,subject='test',company=100) 3 Create Entry(id=1,user=1,subject='test',company=100) 2 Update name : 'My pub' --> 'Our pub' 1 Create Company(id=100,name='My pub',partner_ptr=100) ==== ============= ======== ======== ================================================ """ output = ses.show('changes.Changes', column_names="id type master object diff") # print(output) self.assertEqual(output, expected) # Of course these change records are now considered broken GFKs: expected = """\ ===================== ================= ============================================================= ======== Database model Database object Message Action --------------------- ----------------- ------------------------------------------------------------- -------- `Change <Detail>`__ `#1 <Detail>`__ Invalid primary key 100 for contacts.Partner in `master_id` clear `Change <Detail>`__ `#2 <Detail>`__ Invalid primary key 100 for contacts.Partner in `master_id` clear `Change <Detail>`__ `#3 <Detail>`__ Invalid primary key 100 for contacts.Partner in `master_id` clear `Change <Detail>`__ `#4 <Detail>`__ Invalid primary key 100 for contacts.Partner in `master_id` clear `Change <Detail>`__ `#5 <Detail>`__ Invalid primary key 100 for contacts.Partner in `master_id` clear `Change <Detail>`__ `#1 <Detail>`__ Invalid primary key 100 for contacts.Company in `object_id` clear `Change <Detail>`__ `#2 <Detail>`__ Invalid primary key 100 for contacts.Company in `object_id` clear `Change <Detail>`__ `#3 <Detail>`__ Invalid primary key 1 for entries.Entry in `object_id` clear `Change <Detail>`__ `#4 <Detail>`__ Invalid primary key 1 for entries.Entry in `object_id` clear `Change <Detail>`__ `#5 <Detail>`__ Invalid primary key 100 for contacts.Company in `object_id` clear ===================== ================= ============================================================= ======== """ output = ses.show('gfks.BrokenGFKs') # print(output) self.assertEqual(output, expected)