import re
import sedate
from itertools import chain
from html import unescape
from onegov.core import mail
from onegov.feriennet import _
from onegov.feriennet.exports.const import ACTIVITY_STATES
from onegov.feriennet.exports.const import BOOKING_STATES
from onegov.feriennet.exports.const import FREQUENCIES
from onegov.feriennet.exports.const import GENDERS
from onegov.feriennet.exports.const import ROLES
from onegov.feriennet.exports.const import SALUTATIONS
from onegov.feriennet.exports.const import STATES
from onegov.feriennet.utils import decode_name
from onegov.org.models import Export
from typing import Any, TYPE_CHECKING
if TYPE_CHECKING:
from collections.abc import Iterable, Iterator
from onegov.activity.models import (
Activity, Attendee, Booking, InvoiceItem,
Occasion, OccasionNeed, Volunteer)
from onegov.user import User
[docs]
SPACES = re.compile(r'[ ]+')
[docs]
STREET = re.compile(r"""
# street name
(?P<street>[\D\-\.\s]+)
# punctuation between
[\s,]*
# street number
(?P<number>[0-9]{1}[0-9]*\s?[\w]?)?
""", re.UNICODE | re.VERBOSE)
[docs]
class Street:
[docs]
__slots__ = ('name', 'number')
def __init__(self, name: str | None, number: str | None) -> None:
[docs]
self.name = name and name.strip(' \n,').title()
[docs]
self.number = number and number.strip(' \n,').lower().replace(' ', '')
[docs]
def score_street_match(match: re.Match[str] | None) -> int:
score = 0
if match:
if match.group('street'):
score += 1
if match.group('street') and 'strasse' in match.group('street'):
score += 1
if match.group('number'):
score += 1
return score
[docs]
def remove_duplicate_spaces(text: str) -> str:
return SPACES.sub(' ', text)
[docs]
def html_to_text(html: str | None) -> str:
if not html:
return ''
return remove_duplicate_spaces(mail.html_to_text(
unescape(html),
ul_item_mark='•',
strong_mark='',
emphasis_mark=''
))
[docs]
class FeriennetExport(Export):
[docs]
def activity_fields(
self,
activity: 'Activity'
) -> 'Iterator[tuple[str, Any]]':
yield _('Activity Title'), activity.title
yield _('Activity Lead'), activity.lead
yield _('Activity Text'), html_to_text(activity.text)
yield _('Activity Text (HTML)'), activity.text
yield _('Activity Status'), ACTIVITY_STATES[activity.state]
yield _('Activity Location'), activity.location
yield _('Activity Tags'), '\n'.join(sorted(activity.tags or []))
[docs]
def booking_fields(
self,
booking: 'Booking'
) -> 'Iterator[tuple[str, Any]]':
yield _('Booking State'), BOOKING_STATES[booking.state]
yield _('Booking Priority'), booking.priority
yield _('Booking Cost'), booking.cost
local_booking_time = sedate.to_timezone(
booking.created, booking.period.timezone)
yield _('Booking Date'), local_booking_time.date()
[docs]
def attendee_fields(
self,
attendee: 'Attendee'
) -> 'Iterator[tuple[str, Any]]':
first_name, last_name = decode_name(attendee.name)
yield _('Attendee First Name'), first_name or ''
yield _('Attendee Last Name'), last_name or ''
yield _('Attendee Birth Date'), attendee.birth_date
yield _('Attendee Gender'), GENDERS.get(attendee.gender, '')
yield _('Attendee Notes'), attendee.notes
yield _('Attendee Booking-Limit'), attendee.limit or ''
[docs]
def occasion_fields(
self,
occasion: 'Occasion'
) -> 'Iterator[tuple[str, Any]]':
dates = [
(d.localized_start, d.localized_end)
for d in occasion.dates
]
yield _('Occasion Rescinded'), occasion.cancelled
yield _('Occasion Dates'), dates
yield _('Occasion Note'), occasion.note
yield _('Occasion Age'), '{} - {}'.format(
occasion.age.lower, occasion.age.upper - 1)
yield _('Occasion Spots'), '{} - {}'.format(
occasion.spots.lower, occasion.spots.upper - 1)
yield _('Occasion Cost'), occasion.cost or 0
yield _('Occasion Custom Booking Cost'), occasion.booking_cost or 0
yield _('Occasion Meeting Point'), occasion.meeting_point
yield _('Occasion May Overlap'), occasion.exclude_from_overlap_check
[docs]
def occasion_need_fields(
self,
need: 'OccasionNeed'
) -> 'Iterator[tuple[str, Any]]':
yield _('Need Number'), '{} - {}'.format(
need.number.lower, need.number.upper - 1)
yield _('Need Name'), need.name
yield _('Need Description'), need.description
[docs]
def user_fields(self, user: 'User') -> 'Iterator[tuple[str, Any]]':
user_data = user.data or {}
salutation = user_data.get('salutation')
first_name, last_name = decode_name(user.realname)
status_email = user_data.get('ticket_statistics', 'never')
street = extract_street(user_data.get('address', None))
yield _('User Login'), user.username
yield _('User Role'), ROLES[user.role]
yield _('User Active'), user.active
yield _('User Tags'), user_data.get('tags', ())
yield _('User Salutation'), SALUTATIONS.get(salutation, '')
yield _('User First Name'), first_name or ''
yield _('User Last Name'), last_name or ''
yield _('User Organisation'), user_data.get('organisation', '')
yield _('User Address'), user_data.get('address', '')
yield _('User Street'), street.name or ''
yield _('User Street Number'), street.number or ''
yield _('User Zipcode'), user_data.get('zip_code', '')
yield _('User Location'), user_data.get('place', '')
yield (
_('User Political Municipality'),
user_data.get('political_municipality', '')
)
yield _('User E-Mail'), user_data.get('email', '')
yield _('User Phone'), user_data.get('phone', '')
yield _('User Emergency'), user_data.get('emergency', '')
yield _('User Website'), user_data.get('website', '')
yield _('User Bank Account'), user_data.get('bank_account', '')
yield _('User Beneficiary'), user_data.get('bank_beneficiary', '')
yield _('User Status E-Mail'), FREQUENCIES.get(status_email, '')
yield _('User TOS Accepted'), user_data.get('tos_accepted', False)
[docs]
def invoice_item_fields(
self,
item: 'InvoiceItem'
) -> 'Iterator[tuple[str, Any]]':
yield _('Invoice Item Group'), item.group
yield _('Invoice Item Text'), item.text
yield _('Invoice Item Paid'), item.paid
yield _('Invoice Item Payment date'), item.payment_date
yield _('Invoice Item Transaction ID'), item.tid or ''
yield _('Invoice Item Source'), item.source or ''
yield _('Invoice Item Unit'), item.unit
yield _('Invoice Item Quantity'), item.quantity
yield _('Invoice Item Amount'), item.amount
yield _('Invoice Item References'), '\n'.join(
r.readable for r in item.invoice.references
)
[docs]
def invoice_attendee_fields(
self,
attendee: 'Attendee'
) -> 'Iterator[tuple[str, Any]]':
yield _('Attendee Address'), attendee.address if attendee else ''
yield _('Attendee Zipcode'), attendee.zip_code if attendee else ''
yield _('Attendee Place'), attendee.place if attendee else ''
yield _('Attendee Political Municipality'
), attendee.political_municipality if attendee else ''
[docs]
def organiser_fields(
self,
organiser: 'User'
) -> 'Iterator[tuple[str, Any]]':
user_data = organiser.data or {}
first_name, last_name = decode_name(organiser.realname)
street = extract_street(user_data.get('address', None))
yield _('Organiser Last Name'), last_name or ''
yield _('Organiser First Name'), first_name or ''
yield _('Organiser Organisation'), user_data.get('organisation', '')
yield _('Organiser Address'), user_data.get('address', '')
yield _('Organiser Street'), street.name or ''
yield _('Organiser Street Number'), street.number or ''
yield _('Organiser Zipcode'), user_data.get('zip_code', '')
yield _('Organiser Location'), user_data.get('place', '')
yield _('Organiser E-Mail'), user_data.get('email', '')
yield _('Organiser Phone'), user_data.get('phone', '')
yield _('Organiser Website'), user_data.get('website', '')
yield _('Organiser Bank Account'), user_data.get('bank_account', '')
yield _('Organiser Beneficiary'), user_data.get('bank_beneficiary', '')
[docs]
def volunteer_fields(
self,
volunteer: 'Volunteer'
) -> 'Iterator[tuple[str, Any]]':
need = volunteer.need
occasion = need.occasion
activity = occasion.activity
dates = [
(d.localized_start, d.localized_end)
for d in occasion.dates
]
yield _('Activity Title'), activity.title
yield _('Occasion Dates'), dates
yield _('Occasion Rescinded'), occasion.cancelled
yield _('Need Name'), need.name
yield _('Need Number'), '{} - {}'.format(
need.number.lower, need.number.upper - 1)
yield _('Confirmed Volunteers'), sum(
v.state == 'confirmed' for v in need.volunteers)
yield _('Volunteer State'), STATES[volunteer.state]
yield _('First Name'), volunteer.first_name
yield _('Last Name'), volunteer.last_name
yield _('Birth Date'), volunteer.birth_date
yield _('Organisation'), volunteer.organisation
yield _('Place'), volunteer.place
yield _('E-Mail'), volunteer.email
yield _('Phone'), volunteer.phone
yield _('Address'), volunteer.address