commit f1cfbea2e889e7459634690c405c20e4b2b0e7d8
parent 2e05d7d387b121c716cd51773878aa348f7341f0
Author: Christian Grothoff <christian@grothoff.org>
Date: Tue, 11 Nov 2025 21:09:21 +0100
do VQF 902.15 typst form
Diffstat:
1 file changed, 321 insertions(+), 0 deletions(-)
diff --git a/contrib/typst/VQF_902_15.typ b/contrib/typst/VQF_902_15.typ
@@ -0,0 +1,320 @@
+// VQF 902.15 Life Insurance Policies (I) Template
+// Pass JSON data as content dictionary
+
+#let form(data) = {
+ set page(
+ paper: "a4",
+ margin: (left: 2cm, right: 2cm, top: 2cm, bottom: 2.5cm),
+ footer: context [
+ #grid(
+ columns: (1fr, 1fr),
+ align: (left, right),
+ text(size: 8pt)[
+ VQF doc. Nr. 902.15#linebreak()
+ Version of 22 January 2021
+ ],
+ text(size: 8pt)[
+ Page #here().page() of #counter(page).final().first()
+ ]
+ )
+ ]
+ )
+
+ set text(font: "Liberation Sans", size: 10pt)
+ set par(justify: false, leading: 0.65em)
+
+ let get(key, default: "") = {
+ data.at(key, default: default)
+ }
+
+ let checkbox(checked) = {
+ box(
+ width: 3mm,
+ height: 3mm,
+ stroke: 0.5pt + black,
+ inset: 0.3mm,
+ if checked == true or checked == "true" {
+ place(center + horizon, text(size: 8pt, sym.checkmark))
+ }
+ )
+ }
+
+ // Header
+ align(center, text(size: 11pt, weight: "bold")[CONFIDENTIAL])
+
+ v(0.5em)
+
+ grid(
+ columns: (50%, 50%),
+ gutter: 1em,
+ image("vss_vqf_verein.png", width: 80%),
+ align(right)[
+ #table(
+ columns: (1fr, 1fr),
+ stroke: 0.5pt + black,
+ inset: 5pt,
+ align: (left, left),
+ [VQF member no.], [AMLA File No.],
+ [#get("VQF_MEMBER_NUMBER")], [#get("FILE_NUMBER")]
+ )
+ ]
+ )
+
+ v(1em)
+
+ align(left, text(size: 14pt, weight: "bold")[Information on life insurance policies with separately managed accounts/securities accounts (so-called insurance wrappers) (I)])
+
+ v(-1em)
+ line(length:100%)
+
+ v(1em)
+
+ text(weight: "bold")[Contracting partner:]
+
+ v(0.5em)
+
+ table(
+ columns: (1fr),
+ stroke: 0.5pt + black,
+ inset: 5pt,
+ [#get("IDENTITY_CONTRACTING_PARTNER")]
+ )
+
+ v(1em)
+
+ text(weight: "bold")[Name or number of the contractual relationship between the contracting party and the financial intermediary:]
+
+ v(0.5em)
+
+ table(
+ columns: (1fr),
+ stroke: 0.5pt + black,
+ inset: 5pt,
+ [#get("CONTRACTUAL_RELATIONSHIP_NAME")]
+ )
+
+ v(1em)
+
+ text(weight: "bold")[Insurance policy:]
+
+ v(0.5em)
+
+ table(
+ columns: (1fr),
+ stroke: 0.5pt + black,
+ inset: 5pt,
+ [#get("INSURANCE_POLICY_DETAILS")]
+ )
+
+ v(1em)
+
+ text()[The contracting partner confirms in accordance with Art. 41a SRO Regulations that it is a licensed and state-supervised insurance company and that it has entered into the above-mentioned contractual relationship the assets connected to the life insurance policy also mentioned above.]
+
+ v(0.5em)
+
+ text()[In relation with the above insurance policy, the contracting partner gives the following further details:]
+
+ v(1.5em)
+
+ // Section 1: Policy Holder
+[= 1. Policy holder]
+
+ v(0.5em)
+
+ let policy_holders = get("POLICY_HOLDER_LIST", default: ())
+ let has_holders = type(policy_holders) == array and policy_holders.len() > 0
+
+ for holder in (if has_holders {policy_holders} else {((:),)}) {
+ let get_holder(key) = {
+ if holder != (:) {
+ holder.at(key, default: "")
+ } else {
+ ""
+ }
+ }
+
+ text()[Full name/entity:]
+
+ v(0.3em)
+
+ table(
+ columns: (1fr),
+ stroke: 0.5pt + black,
+ inset: 5pt,
+ [#get_holder("PERSON_ENTITY_NAME")]
+ )
+
+ v(0.5em)
+
+ table(
+ columns: (40%, 10%, 50%),
+ stroke: 0.5pt + black,
+ inset: 5pt,
+ [Date of birth:],
+ [],
+ [Nationality:],
+ [#get_holder("PERSON_DATE_OF_BIRTH")],
+ [],
+ [#get_holder("PERSON_NATIONALITY")]
+ )
+
+ v(0.5em)
+
+ text()[Actual address of domicile/registered office (incl. country):]
+
+ v(0.3em)
+
+ table(
+ columns: (1fr),
+ stroke: 0.5pt + black,
+ inset: 5pt,
+ [#get_holder("PERSON_DOMICILE_REGISTERED_OFFICE")]
+ )
+
+ v(1em)
+ }
+
+ v(0.5em)
+
+ // Section 2: Premium Payer
+[= 2. Person actually (not in a fiduciary capacity) paying the premiums (to be filled in if not identical with point 1 above):]
+
+ v(0.5em)
+
+ let same_payer = get("PREMIUM_PAYER_SAME_AS_HOLDER")
+ let premium_payers = get("PREMIUM_PAYER_LIST", default: ())
+ let has_payers = not same_payer and type(premium_payers) == array and premium_payers.len() > 0
+
+ if has_payers {
+ for payer in premium_payers {
+ let get_payer(key) = {
+ payer.at(key, default: "")
+ }
+
+ text()[Full anme/entity:]
+
+ v(0.3em)
+
+ table(
+ columns: (1fr),
+ stroke: 0.5pt + black,
+ inset: 5pt,
+ [#get_payer("PERSON_ENTITY_NAME")]
+ )
+
+ v(0.5em)
+
+ table(
+ columns: (40%, 10%, 50%),
+ stroke: 0.5pt + black,
+ inset: 5pt,
+ [Date of birth:],
+ [],
+ [Nationality:],
+ [#get_payer("PERSON_DATE_OF_BIRTH")],
+ [],
+ [#get_payer("PERSON_NATIONALITY")]
+ )
+
+ v(0.5em)
+
+ text()[Actual address of domicile/registered office (incl. country):]
+
+ v(0.3em)
+
+ table(
+ columns: (1fr),
+ stroke: 0.5pt + black,
+ inset: 5pt,
+ [#get_payer("PERSON_DOMICILE_REGISTERED_OFFICE")]
+ )
+
+ v(1em)
+ }
+ } else {
+ text()[Full name/entity:]
+
+ v(0.3em)
+
+ table(
+ columns: (1fr),
+ stroke: 0.5pt + black,
+ inset: 5pt,
+ []
+ )
+
+ v(0.5em)
+
+ table(
+ columns: (40%, 10%, 50%),
+ stroke: 0.5pt + black,
+ inset: 5pt,
+ [Date of birth:],
+ [],
+ [Nationality:],
+ [],
+ [],
+ []
+ )
+
+ v(0.5em)
+
+ text()[Actual address of domicile/registered office (incl. country):]
+
+ v(0.3em)
+
+ table(
+ columns: (1fr),
+ stroke: 0.5pt + black,
+ inset: 5pt,
+ []
+ )
+
+ v(1em)
+ }
+
+ v(1em)
+
+ text()[The contracting partner hereby undertakes to automatically inform the financial intermediary of any changes. The contracting partner hereby also declares having been given permission by the above individuals and/or entities to transmit their data to the financial intermediary.]
+
+ v(1.5em)
+
+ // Signature
+ table(
+ columns: (40%, 10%, 50%),
+ stroke: 0.5pt + black,
+ inset: 5pt,
+ [Date:],
+ [],
+ [Signature(s):],
+ [#get("SIGN_DATE")],
+ [],
+ [#get("SIGNATURE")]
+ )
+
+ v(1em)
+
+ text(size: 9pt, style: "italic")[
+ It is a criminal offence to deliberately provide false information on this form (article 251 of the Swiss Criminal Code, document forgery).
+ ]
+}
+
+// Example usage:
+#form((
+ "VQF_MEMBER_NUMBER": "12345",
+ "FILE_NUMBER": "42",
+ "IDENTITY_CONTRACTING_PARTNER": "Insurance Company AG\nInsurance Street 1\n8001 Zurich\nSwitzerland",
+ "CONTRACTUAL_RELATIONSHIP_NAME": "Policy #12345-ABC",
+ "INSURANCE_POLICY_DETAILS": "Life insurance policy with separate account management\nPolicy Number: LI-2025-001\nIssued: 01.01.2025",
+ "POLICY_HOLDER_LIST": (
+ (
+ "PERSON_ENTITY_NAME": "John Doe",
+ "PERSON_DATE_OF_BIRTH": "01.01.1970",
+ "PERSON_NATIONALITY": "CH",
+ "PERSON_DOMICILE_REGISTERED_OFFICE": "Main Street 123\n8001 Zurich\nSwitzerland"
+ ),
+ ),
+ "PREMIUM_PAYER_SAME_AS_HOLDER": true,
+ "SIGNATURE": "Insurance Company Representative",
+ "SIGN_DATE": "10.11.2025",
+))
+\ No newline at end of file