lambda-erp 1.1.8__tar.gz → 1.1.9__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {lambda_erp-1.1.8 → lambda_erp-1.1.9}/PKG-INFO +1 -1
- {lambda_erp-1.1.8 → lambda_erp-1.1.9}/api/pdf.py +7 -3
- {lambda_erp-1.1.8 → lambda_erp-1.1.9}/api/pdf_contract.py +29 -3
- {lambda_erp-1.1.8 → lambda_erp-1.1.9}/api/templates/_record_base.html +1 -1
- {lambda_erp-1.1.8 → lambda_erp-1.1.9}/api/templates/document.html +2 -1
- {lambda_erp-1.1.8 → lambda_erp-1.1.9}/api/templates/proposal.html +3 -2
- {lambda_erp-1.1.8 → lambda_erp-1.1.9}/pyproject.toml +1 -1
- {lambda_erp-1.1.8 → lambda_erp-1.1.9}/.gitignore +0 -0
- {lambda_erp-1.1.8 → lambda_erp-1.1.9}/LICENSE +0 -0
- {lambda_erp-1.1.8 → lambda_erp-1.1.9}/README.md +0 -0
- {lambda_erp-1.1.8 → lambda_erp-1.1.9}/api/__init__.py +0 -0
- {lambda_erp-1.1.8 → lambda_erp-1.1.9}/api/attachments.py +0 -0
- {lambda_erp-1.1.8 → lambda_erp-1.1.9}/api/auth.py +0 -0
- {lambda_erp-1.1.8 → lambda_erp-1.1.9}/api/bootstrap.py +0 -0
- {lambda_erp-1.1.8 → lambda_erp-1.1.9}/api/chat.py +0 -0
- {lambda_erp-1.1.8 → lambda_erp-1.1.9}/api/chat_links.py +0 -0
- {lambda_erp-1.1.8 → lambda_erp-1.1.9}/api/demo_limits.py +0 -0
- {lambda_erp-1.1.8 → lambda_erp-1.1.9}/api/deps.py +0 -0
- {lambda_erp-1.1.8 → lambda_erp-1.1.9}/api/erp_context.py +0 -0
- {lambda_erp-1.1.8 → lambda_erp-1.1.9}/api/errors.py +0 -0
- {lambda_erp-1.1.8 → lambda_erp-1.1.9}/api/list_values.py +0 -0
- {lambda_erp-1.1.8 → lambda_erp-1.1.9}/api/main.py +0 -0
- {lambda_erp-1.1.8 → lambda_erp-1.1.9}/api/mcp_oauth.py +0 -0
- {lambda_erp-1.1.8 → lambda_erp-1.1.9}/api/oauth.py +0 -0
- {lambda_erp-1.1.8 → lambda_erp-1.1.9}/api/pdf_exports.py +0 -0
- {lambda_erp-1.1.8 → lambda_erp-1.1.9}/api/pdf_profiles.py +0 -0
- {lambda_erp-1.1.8 → lambda_erp-1.1.9}/api/providers.py +0 -0
- {lambda_erp-1.1.8 → lambda_erp-1.1.9}/api/remarks_md.py +0 -0
- {lambda_erp-1.1.8 → lambda_erp-1.1.9}/api/routers/__init__.py +0 -0
- {lambda_erp-1.1.8 → lambda_erp-1.1.9}/api/routers/accounting.py +0 -0
- {lambda_erp-1.1.8 → lambda_erp-1.1.9}/api/routers/actions.py +0 -0
- {lambda_erp-1.1.8 → lambda_erp-1.1.9}/api/routers/admin.py +0 -0
- {lambda_erp-1.1.8 → lambda_erp-1.1.9}/api/routers/analytics.py +0 -0
- {lambda_erp-1.1.8 → lambda_erp-1.1.9}/api/routers/availability.py +0 -0
- {lambda_erp-1.1.8 → lambda_erp-1.1.9}/api/routers/bank_reconciliation.py +0 -0
- {lambda_erp-1.1.8 → lambda_erp-1.1.9}/api/routers/bank_statements.py +0 -0
- {lambda_erp-1.1.8 → lambda_erp-1.1.9}/api/routers/chat_api.py +0 -0
- {lambda_erp-1.1.8 → lambda_erp-1.1.9}/api/routers/documents.py +0 -0
- {lambda_erp-1.1.8 → lambda_erp-1.1.9}/api/routers/masters.py +0 -0
- {lambda_erp-1.1.8 → lambda_erp-1.1.9}/api/routers/mcp.py +0 -0
- {lambda_erp-1.1.8 → lambda_erp-1.1.9}/api/routers/proposals.py +0 -0
- {lambda_erp-1.1.8 → lambda_erp-1.1.9}/api/routers/reports.py +0 -0
- {lambda_erp-1.1.8 → lambda_erp-1.1.9}/api/routers/setup.py +0 -0
- {lambda_erp-1.1.8 → lambda_erp-1.1.9}/api/services.py +0 -0
- {lambda_erp-1.1.8 → lambda_erp-1.1.9}/api/templates/_proposal_totals.html +0 -0
- {lambda_erp-1.1.8 → lambda_erp-1.1.9}/api/templates/record.html +0 -0
- {lambda_erp-1.1.8 → lambda_erp-1.1.9}/api/time_filters.py +0 -0
- {lambda_erp-1.1.8 → lambda_erp-1.1.9}/api/tool_permissions.py +0 -0
- {lambda_erp-1.1.8 → lambda_erp-1.1.9}/docs/agents/README.md +0 -0
- {lambda_erp-1.1.8 → lambda_erp-1.1.9}/frontend/LICENSE +0 -0
- {lambda_erp-1.1.8 → lambda_erp-1.1.9}/frontend/README.md +0 -0
- {lambda_erp-1.1.8 → lambda_erp-1.1.9}/frontend/src/api/client.ts +0 -0
- {lambda_erp-1.1.8 → lambda_erp-1.1.9}/lambda_erp/__init__.py +0 -0
- {lambda_erp-1.1.8 → lambda_erp-1.1.9}/lambda_erp/accounting/__init__.py +0 -0
- {lambda_erp-1.1.8 → lambda_erp-1.1.9}/lambda_erp/accounting/bank_account.py +0 -0
- {lambda_erp-1.1.8 → lambda_erp-1.1.9}/lambda_erp/accounting/bank_reconciliation.py +0 -0
- {lambda_erp-1.1.8 → lambda_erp-1.1.9}/lambda_erp/accounting/bank_statement_import.py +0 -0
- {lambda_erp-1.1.8 → lambda_erp-1.1.9}/lambda_erp/accounting/bank_transaction.py +0 -0
- {lambda_erp-1.1.8 → lambda_erp-1.1.9}/lambda_erp/accounting/budget.py +0 -0
- {lambda_erp-1.1.8 → lambda_erp-1.1.9}/lambda_erp/accounting/camt.py +0 -0
- {lambda_erp-1.1.8 → lambda_erp-1.1.9}/lambda_erp/accounting/chart_of_accounts.py +0 -0
- {lambda_erp-1.1.8 → lambda_erp-1.1.9}/lambda_erp/accounting/general_ledger.py +0 -0
- {lambda_erp-1.1.8 → lambda_erp-1.1.9}/lambda_erp/accounting/journal_entry.py +0 -0
- {lambda_erp-1.1.8 → lambda_erp-1.1.9}/lambda_erp/accounting/payment_entry.py +0 -0
- {lambda_erp-1.1.8 → lambda_erp-1.1.9}/lambda_erp/accounting/pos_invoice.py +0 -0
- {lambda_erp-1.1.8 → lambda_erp-1.1.9}/lambda_erp/accounting/purchase_invoice.py +0 -0
- {lambda_erp-1.1.8 → lambda_erp-1.1.9}/lambda_erp/accounting/revaluation.py +0 -0
- {lambda_erp-1.1.8 → lambda_erp-1.1.9}/lambda_erp/accounting/sales_invoice.py +0 -0
- {lambda_erp-1.1.8 → lambda_erp-1.1.9}/lambda_erp/accounting/settlement.py +0 -0
- {lambda_erp-1.1.8 → lambda_erp-1.1.9}/lambda_erp/accounting/setup/__init__.py +0 -0
- {lambda_erp-1.1.8 → lambda_erp-1.1.9}/lambda_erp/accounting/setup/engine.py +0 -0
- {lambda_erp-1.1.8 → lambda_erp-1.1.9}/lambda_erp/accounting/setup/pack.py +0 -0
- {lambda_erp-1.1.8 → lambda_erp-1.1.9}/lambda_erp/accounting/setup/packs/__init__.py +0 -0
- {lambda_erp-1.1.8 → lambda_erp-1.1.9}/lambda_erp/accounting/setup/packs/ch.py +0 -0
- {lambda_erp-1.1.8 → lambda_erp-1.1.9}/lambda_erp/accounting/setup/packs/de_common.py +0 -0
- {lambda_erp-1.1.8 → lambda_erp-1.1.9}/lambda_erp/accounting/setup/packs/de_skr03.py +0 -0
- {lambda_erp-1.1.8 → lambda_erp-1.1.9}/lambda_erp/accounting/setup/packs/de_skr04.py +0 -0
- {lambda_erp-1.1.8 → lambda_erp-1.1.9}/lambda_erp/accounting/setup/packs/generic.py +0 -0
- {lambda_erp-1.1.8 → lambda_erp-1.1.9}/lambda_erp/accounting/setup/profiles.py +0 -0
- {lambda_erp-1.1.8 → lambda_erp-1.1.9}/lambda_erp/accounting/setup/spine.py +0 -0
- {lambda_erp-1.1.8 → lambda_erp-1.1.9}/lambda_erp/accounting/subscription.py +0 -0
- {lambda_erp-1.1.8 → lambda_erp-1.1.9}/lambda_erp/assets/__init__.py +0 -0
- {lambda_erp-1.1.8 → lambda_erp-1.1.9}/lambda_erp/assets/asset.py +0 -0
- {lambda_erp-1.1.8 → lambda_erp-1.1.9}/lambda_erp/assets/lifecycle.py +0 -0
- {lambda_erp-1.1.8 → lambda_erp-1.1.9}/lambda_erp/assets/reservation.py +0 -0
- {lambda_erp-1.1.8 → lambda_erp-1.1.9}/lambda_erp/buying/__init__.py +0 -0
- {lambda_erp-1.1.8 → lambda_erp-1.1.9}/lambda_erp/buying/purchase_order.py +0 -0
- {lambda_erp-1.1.8 → lambda_erp-1.1.9}/lambda_erp/controllers/__init__.py +0 -0
- {lambda_erp-1.1.8 → lambda_erp-1.1.9}/lambda_erp/controllers/currency.py +0 -0
- {lambda_erp-1.1.8 → lambda_erp-1.1.9}/lambda_erp/controllers/defaults.py +0 -0
- {lambda_erp-1.1.8 → lambda_erp-1.1.9}/lambda_erp/controllers/item_price.py +0 -0
- {lambda_erp-1.1.8 → lambda_erp-1.1.9}/lambda_erp/controllers/item_prices.py +0 -0
- {lambda_erp-1.1.8 → lambda_erp-1.1.9}/lambda_erp/controllers/pricing_rule.py +0 -0
- {lambda_erp-1.1.8 → lambda_erp-1.1.9}/lambda_erp/controllers/taxes_and_totals.py +0 -0
- {lambda_erp-1.1.8 → lambda_erp-1.1.9}/lambda_erp/database.py +0 -0
- {lambda_erp-1.1.8 → lambda_erp-1.1.9}/lambda_erp/exceptions.py +0 -0
- {lambda_erp-1.1.8 → lambda_erp-1.1.9}/lambda_erp/hooks.py +0 -0
- {lambda_erp-1.1.8 → lambda_erp-1.1.9}/lambda_erp/master_integrity.py +0 -0
- {lambda_erp-1.1.8 → lambda_erp-1.1.9}/lambda_erp/model.py +0 -0
- {lambda_erp-1.1.8 → lambda_erp-1.1.9}/lambda_erp/selling/__init__.py +0 -0
- {lambda_erp-1.1.8 → lambda_erp-1.1.9}/lambda_erp/selling/proposal.py +0 -0
- {lambda_erp-1.1.8 → lambda_erp-1.1.9}/lambda_erp/selling/quotation.py +0 -0
- {lambda_erp-1.1.8 → lambda_erp-1.1.9}/lambda_erp/selling/sales_order.py +0 -0
- {lambda_erp-1.1.8 → lambda_erp-1.1.9}/lambda_erp/simulation.py +0 -0
- {lambda_erp-1.1.8 → lambda_erp-1.1.9}/lambda_erp/stock/__init__.py +0 -0
- {lambda_erp-1.1.8 → lambda_erp-1.1.9}/lambda_erp/stock/delivery_note.py +0 -0
- {lambda_erp-1.1.8 → lambda_erp-1.1.9}/lambda_erp/stock/purchase_receipt.py +0 -0
- {lambda_erp-1.1.8 → lambda_erp-1.1.9}/lambda_erp/stock/stock_entry.py +0 -0
- {lambda_erp-1.1.8 → lambda_erp-1.1.9}/lambda_erp/stock/stock_ledger.py +0 -0
- {lambda_erp-1.1.8 → lambda_erp-1.1.9}/lambda_erp/timestamps.py +0 -0
- {lambda_erp-1.1.8 → lambda_erp-1.1.9}/lambda_erp/utils.py +0 -0
- {lambda_erp-1.1.8 → lambda_erp-1.1.9}/lambda_erp/validation.py +0 -0
- {lambda_erp-1.1.8 → lambda_erp-1.1.9}/lambda_erp/workflow.py +0 -0
- {lambda_erp-1.1.8 → lambda_erp-1.1.9}/terraform/README.md +0 -0
|
@@ -7,7 +7,7 @@ from jinja2 import Environment, FileSystemLoader, ChoiceLoader
|
|
|
7
7
|
from weasyprint import HTML
|
|
8
8
|
from lambda_erp.database import get_db
|
|
9
9
|
from api.services import load_document, get_document_class
|
|
10
|
-
from api.pdf_contract import prepare, validate_rendered_pdf, PDFError
|
|
10
|
+
from api.pdf_contract import prepare, validate_rendered_pdf, PDFError, register_pdf_state_labels # noqa: F401
|
|
11
11
|
from api.remarks_md import render_remarks
|
|
12
12
|
from lambda_erp.controllers.taxes_and_totals import split_by_frequency
|
|
13
13
|
|
|
@@ -229,6 +229,7 @@ def _render_commercial_pdf(doctype_slug, name, doc, contract):
|
|
|
229
229
|
context = dict(
|
|
230
230
|
doc=doc,
|
|
231
231
|
pdf_status=contract["status"],
|
|
232
|
+
pdf_state_notice=contract["notice"],
|
|
232
233
|
pdf_warnings=contract["warnings"],
|
|
233
234
|
title=title,
|
|
234
235
|
company_name=company_name,
|
|
@@ -334,8 +335,8 @@ def _render_proposal_pdf(name, proposal, contract):
|
|
|
334
335
|
if quote.get('company') != proposal.get('company') or quote.get('customer') != proposal.get('customer'):
|
|
335
336
|
raise PDFError('Proposal PDF: quotation company and customer must match')
|
|
336
337
|
quote_contract = prepare('Quotation', quote)
|
|
337
|
-
# Each included offer must be rendered completely.
|
|
338
|
-
#
|
|
338
|
+
# Each included offer must be rendered completely. A non-final state
|
|
339
|
+
# (draft, cancelled, discarded) is printed beside its number.
|
|
339
340
|
contract['tokens'].extend(quote_contract['tokens'])
|
|
340
341
|
contract['warnings'].extend(quote_contract['warnings'])
|
|
341
342
|
items = quote.get("items", []) or []
|
|
@@ -352,6 +353,7 @@ def _render_proposal_pdf(name, proposal, contract):
|
|
|
352
353
|
"letter": chr(ord("A") + i),
|
|
353
354
|
"quotation": qname,
|
|
354
355
|
"pdf_status": quote_contract["status"],
|
|
356
|
+
"pdf_state_notice": quote_contract["notice"],
|
|
355
357
|
"title": row.get("position_title") or default_title or qname,
|
|
356
358
|
"blurb": row.get("position_blurb") or quote.get("remarks") or "",
|
|
357
359
|
"is_recommended": bool(row.get("is_recommended")),
|
|
@@ -373,6 +375,7 @@ def _render_proposal_pdf(name, proposal, contract):
|
|
|
373
375
|
context = dict(
|
|
374
376
|
proposal=proposal,
|
|
375
377
|
pdf_status=contract["status"],
|
|
378
|
+
pdf_state_notice=contract["notice"],
|
|
376
379
|
pdf_warnings=contract["warnings"],
|
|
377
380
|
title=proposal.get("title") or "Offerte",
|
|
378
381
|
company_name=company_name,
|
|
@@ -416,6 +419,7 @@ def _render_record_pdf(doctype, name, doc, contract):
|
|
|
416
419
|
page_size_row = get_db().sql('SELECT value FROM "Settings" WHERE key = ?', ['pdf_page_size'])
|
|
417
420
|
context = dict(
|
|
418
421
|
title=contract['profile'].title, name=name, pdf_status=contract['status'],
|
|
422
|
+
pdf_state_notice=contract['notice'],
|
|
419
423
|
pdf_warnings=contract['warnings'], print_fields=contract['fields'],
|
|
420
424
|
print_tables=contract['tables'], print_labels={}, print_title=contract['profile'].title,
|
|
421
425
|
company_info=company, company_name=company.get('company_name') or doc.get('company') or '',
|
|
@@ -61,6 +61,31 @@ def resolve(table, name):
|
|
|
61
61
|
return (db.get_value(table, name, display) if display in fields else None) or name
|
|
62
62
|
|
|
63
63
|
|
|
64
|
+
# States a reader must not mistake for a final, issued document. Only these are
|
|
65
|
+
# printed as a notice and required in the rendered text; a submitted invoice or
|
|
66
|
+
# an ordinary record status carries no notice.
|
|
67
|
+
NOTICE_STATES = ('Draft', 'Cancelled', 'Discarded')
|
|
68
|
+
_state_labels = {}
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def register_pdf_state_labels(labels) -> None:
|
|
72
|
+
"""Override the printed notice for non-final states, e.g. {'Draft': 'Entwurf'}.
|
|
73
|
+
|
|
74
|
+
Keys must be in NOTICE_STATES. The label is what templates print as
|
|
75
|
+
`pdf_state_notice` and what the rendered-text check then requires.
|
|
76
|
+
"""
|
|
77
|
+
unknown = set(labels) - set(NOTICE_STATES)
|
|
78
|
+
if unknown:
|
|
79
|
+
raise ValueError(f'Unknown PDF notice states: {sorted(unknown)}')
|
|
80
|
+
if any(not str(label).strip() for label in labels.values()):
|
|
81
|
+
raise ValueError('PDF notice labels must not be empty')
|
|
82
|
+
_state_labels.update(labels)
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
def notice_for(state):
|
|
86
|
+
return _state_labels.get(state, state) if state in NOTICE_STATES else ''
|
|
87
|
+
|
|
88
|
+
|
|
64
89
|
def state_for(doctype, doc):
|
|
65
90
|
from api.services import DOCUMENT_CLASSES
|
|
66
91
|
if doc.get('discarded'):
|
|
@@ -87,9 +112,10 @@ def prepare(doctype, doc):
|
|
|
87
112
|
if not any(not missing(doc.get(key)) for key in group):
|
|
88
113
|
raise PDFError('PDF requires at least one of: ' + ', '.join(group), fields=group)
|
|
89
114
|
state = state_for(doctype, doc)
|
|
90
|
-
|
|
115
|
+
notice = notice_for(state)
|
|
116
|
+
tokens = [str(doc['name'])] + ([notice] if notice else [])
|
|
91
117
|
warnings = []
|
|
92
|
-
if
|
|
118
|
+
if notice:
|
|
93
119
|
warnings.append({'code': 'pdf_document_state', 'message': f'{doctype} {doc["name"]}: {state}'})
|
|
94
120
|
company = {}
|
|
95
121
|
if doc.get('company'):
|
|
@@ -213,7 +239,7 @@ def prepare(doctype, doc):
|
|
|
213
239
|
if doctype == 'Subscription':
|
|
214
240
|
party_currency = get_db().get_value(party_type, party_id, 'default_currency') if party_id else None
|
|
215
241
|
fields.append({'key': 'currency', 'value': party_currency or company_currency})
|
|
216
|
-
return {'profile': profile, 'status': state, 'warnings': warnings, 'tokens': tokens,
|
|
242
|
+
return {'profile': profile, 'status': state, 'notice': notice, 'warnings': warnings, 'tokens': tokens,
|
|
217
243
|
'fields': fields, 'tables': tables, 'party_name': party_name,
|
|
218
244
|
'company': company, 'company_currency': company_currency}
|
|
219
245
|
|
|
@@ -16,7 +16,7 @@ tr { break-inside: avoid; } .brand { font-weight: bold; letter-spacing: .8pt; }
|
|
|
16
16
|
{% macro label(key) %}{{ print_labels.get(key, key.replace('_',' ').capitalize()) }}{% endmacro %}
|
|
17
17
|
{% block letterhead %}<div class="header"><div class="brand">{{ company_name }}</div>{% if company_info.get('address') %}<div class="muted">{{ company_info.get('address') }}</div>{% endif %}</div>{% endblock %}
|
|
18
18
|
<h1>{{ print_title }}</h1>
|
|
19
|
-
<div class="state">{{ name }} · {{ pdf_status }}</div>
|
|
19
|
+
<div class="state">{{ name }} · {{ pdf_state_notice or pdf_status }}</div>
|
|
20
20
|
{% for warning in pdf_warnings %}<div class="warning">{{ warning.message }}</div>{% endfor %}
|
|
21
21
|
{% if party_name %}<p><strong>{{ party_name }}</strong></p>{% endif %}
|
|
22
22
|
{% if company_currency %}<div class="muted">{{ label('company_currency') }}: {{ company_currency }}</div>{% endif %}
|
|
@@ -58,10 +58,11 @@
|
|
|
58
58
|
.remarks .rm-hr { border-top: 1px solid #d1d5db; margin: 6px 0; }
|
|
59
59
|
.remarks em { font-style: italic; }
|
|
60
60
|
.remarks strong { font-weight: 700; }
|
|
61
|
+
.state-notice { display: inline-block; margin-bottom: 8pt; padding: 3px 10px; border: 1.5px solid #b91c1c; border-radius: 4px; color: #b91c1c; font-size: 10pt; font-weight: 700; letter-spacing: 1px; text-transform: uppercase; }
|
|
61
62
|
</style>
|
|
62
63
|
</head>
|
|
63
64
|
<body>
|
|
64
|
-
<div
|
|
65
|
+
{% if pdf_state_notice %}<div class="state-notice">{{ pdf_state_notice }}</div>{% endif %}
|
|
65
66
|
|
|
66
67
|
{# ---- Header ---- #}
|
|
67
68
|
<div class="header">
|
|
@@ -34,10 +34,11 @@
|
|
|
34
34
|
table.lines td.desc { color: #333; }
|
|
35
35
|
|
|
36
36
|
.footer { margin-top: 28px; padding-top: 10px; border-top: 1px solid #e5e7eb; font-size: 7.5pt; color: #999; text-align: center; }
|
|
37
|
+
.state-notice { display: inline-block; margin-bottom: 8pt; padding: 3px 10px; border: 1.5px solid #b91c1c; border-radius: 4px; color: #b91c1c; font-size: 10pt; font-weight: 700; letter-spacing: 1px; text-transform: uppercase; }
|
|
37
38
|
</style>
|
|
38
39
|
</head>
|
|
39
40
|
<body>
|
|
40
|
-
<div
|
|
41
|
+
{% if pdf_state_notice %}<div class="state-notice">{{ pdf_state_notice }}</div>{% endif %}
|
|
41
42
|
|
|
42
43
|
<div class="header">
|
|
43
44
|
<div><div class="company">{{ company_name or proposal.company or "" }}</div></div>
|
|
@@ -69,7 +70,7 @@
|
|
|
69
70
|
{% if proposal.cover_letter %}<div class="cover">{{ proposal.cover_letter }}</div>{% endif %}
|
|
70
71
|
|
|
71
72
|
{% for p in positions %}
|
|
72
|
-
<div style="font-size:8pt">{{ p.quotation }} · {{ p.
|
|
73
|
+
{% if p.pdf_state_notice %}<div style="font-size:8pt">{{ p.quotation }} · <span class="state-notice" style="font-size:8pt; padding:1px 6px; margin:0">{{ p.pdf_state_notice }}</span></div>{% endif %}
|
|
73
74
|
<div class="position">
|
|
74
75
|
<div class="pos-head">
|
|
75
76
|
<span class="letter">{{ p.letter }}</span>
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|