Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix-9127: Add the unique ticket code into the downlad CSV file #9130

Merged
merged 9 commits into from Mar 21, 2024
184 changes: 118 additions & 66 deletions app/api/helpers/csv_jobs_util.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,75 +82,127 @@ def export_orders_csv(orders):
return rows


def export_attendees_csv(attendees, custom_forms, attendee_form_dict):
return_dict_list = []
def get_order_ticket_data(order, ticket):
"""Get order ticket data"""
data = {}
if not order:
return {
'Order#': '',
'Order Date': '',
'Status': '',
'Payment Type': '',
'Payment Mode': '',
'Ticket ID': '',
'Ticket Name': '',
'Ticket Price': '0',
'Ticket Type': '',
'Tax ID': '',
'Address': '',
'Company': '',
'Country': '',
'State': '',
'City': '',
'Zipcode': '',
}

for attendee in attendees:
data = {
'Order#': str(attendee.order.get_invoice_number()) if attendee.order else '-',
'Order Date': str(attendee.order.created_at.strftime('%B %-d, %Y %H:%M %z'))
if attendee.order and attendee.order.created_at
else '-',
'Status': str(attendee.order.status)
if attendee.order and attendee.order.status
else '-',
'Payment Type': str(attendee.order.paid_via)
if attendee.order and attendee.order.paid_via
else '',
'Payment Mode': str(attendee.order.payment_mode)
if attendee.order and attendee.order.payment_mode
else '',
'Ticket Name': str(attendee.ticket.name)
if attendee.ticket and attendee.ticket.name
else '',
'Ticket Price': str(attendee.ticket.price)
if attendee.ticket and attendee.ticket.price
else '0',
'Ticket Type': str(attendee.ticket.type)
if attendee.ticket and attendee.ticket.type
else '',
'Tax ID': str(attendee.order.tax_business_info)
if attendee.order.tax_business_info
else '',
'Address': str(attendee.order.address) if attendee.order.address else '',
'Company': str(attendee.order.company) if attendee.order.company else '',
'Country': str(attendee.order.country) if attendee.order.country else '',
'State': str(attendee.order.state) if attendee.order.state else '',
'City': str(attendee.order.city) if attendee.order.city else '',
'Zipcode': str(attendee.order.zipcode) if attendee.order.zipcode else '',
'Email': '',
data = {
'Order#': str(order.get_invoice_number()),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

order number and not invoice number and line 58 too

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hello @mariobehling, can you share about this idea?

Copy link
Contributor

@cweitat cweitat Mar 20, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Every order has a relation to tickets and invoice. Each has different number.


{
    "data": {
        "type": "order",
        "attributes": {
            "order-notes": null,
            **"identifier": "ad2ad60f-33f1-456e-9fec-7d0c3151f217",**
            "created-at": "2024-03-20T03:09:04.041344+00:00",
            "tax-business-info": null,
            "exp-month": null,
            "address": null,
            "tickets-pdf-url": "https://api.eventyay.com/generated/tickets/orders/tickets/pdf/ad2ad60f-33f1-456e-9fec-7d0c3151f217/ad2ad60f-33f1-456e-9fec-7d0c3151f217/b1pBQ1dDQ0/ad2ad60f-33f1-456e-9fec-7d0c3151f217.pdf",
            "transaction-id": null,
            "paid-via": null,
            "state": null,
            "company": null,
            "city": null,
            "completed-at": "2024-03-20T03:10:41.185012+00:00",
            "discount-code-id": "71117",
            "amount": 0.0,
            "brand": null,
            "status": "completed",
            "country": null,
            "exp-year": null,
            "last4": null,
            "is-billing-enabled": false,
            "cancel-note": null,
            "zipcode": null,
            "payment-mode": "free"
        },
        "relationships": {
            "marketer": {
                "links": {
                    "self": "/v1/orders/ad2ad60f-33f1-456e-9fec-7d0c3151f217/relationships/marketer"
                }
            },
            "tickets": {
                "links": {
                    "self": "/v1/orders/ad2ad60f-33f1-456e-9fec-7d0c3151f217/relationships/ticket",
                    "related": "/v1/orders/ad2ad60f-33f1-456e-9fec-7d0c3151f217/tickets"
                },
                "data": [
                    {
                        "type": "ticket",
                        "id": "3458"
                    },
                    {
                        "type": "ticket",
                        "id": "3464"
                    }
                ]
            },
            "discount-code": {
                "links": {
                    "self": "/v1/orders/ad2ad60f-33f1-456e-9fec-7d0c3151f217/relationships/discount-code",
                    "related": "/v1/discount-codes/71117"
                }
            },
            "event": {
                "links": {
                    "self": "/v1/orders/ad2ad60f-33f1-456e-9fec-7d0c3151f217/relationships/event",
                    "related": "/v1/events/3284"
                },
                "data": {
                    "type": "event",
                    "id": "3284"
                }
            },
            "user": {
                "links": {
                    "self": "/v1/orders/ad2ad60f-33f1-456e-9fec-7d0c3151f217/relationships/user",
                    "related": "/v1/users/33522"
                }
            },
            "attendees": {
                "links": {
                    "self": "/v1/orders/ad2ad60f-33f1-456e-9fec-7d0c3151f217/relationships/attendee",
                    "related": "/v1/orders/ad2ad60f-33f1-456e-9fec-7d0c3151f217/attendees"
                },
                "data": [
                    {
                        "type": "attendee",
                        "id": "49414"
                    },
                    {
                        "type": "attendee",
                        "id": "49413"
                    }
                ]
            },
            "event-invoice": {
                "links": {
                    "self": "/v1/orders/ad2ad60f-33f1-456e-9fec-7d0c3151f217/relationships/event-invoice/",
                    **"related": "/v1/event-invoices/38205"**
                }
            }
        },

Copy link
Author

@ghost ghost Mar 20, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

image
It means.
The value of "Order#" will be the value of "identifier" in the JSON above, right?
So the value of "Ticket ID" will be the same as "Order#", right?

Based on Mario's comment, "ticket ID" will be the "identifier" of the JSON you provide
#9127 (comment)

'Order Date': str(order.created_at.strftime('%B %-d, %Y %H:%M %z'))
if order.created_at
else '-',
'Status': str(order.status) if order.status else '-',
'Payment Type': str(order.paid_via) if order.paid_via else '',
'Payment Mode': str(order.payment_mode) if order.payment_mode else '',
'Ticket ID': str(order.identifier) if order.identifier else '',
}

if ticket:
data.update(get_ticket_data(ticket))

data.update(get_order_data(order))

return data


def get_order_data(order):
"""Get order data from order object"""
if not order:
return {
'Tax ID': '',
'Address': '',
'Company': '',
'Country': '',
'State': '',
'City': '',
'Zipcode': '',
}

for field in custom_forms:
# keys don't match up, for keys like
# acceptVideoRecording vs accept_video_recording ..
key_mapping = {}

for k in attendee_form_dict.keys():
key_mapping[k.replace("_", "").lower()] = k

field_raw = field.identifier.replace("_", "").lower()
key = key_mapping.get(field_raw)
converted_header = attendee_form_dict.get(key)
if field.is_complex:
fields_dict = attendee.complex_field_values
converted_header = field.name
data[converted_header] = (
fields_dict.get(field.identifier, '') if fields_dict else ''
)
else:
dict_value = getattr(attendee, field.identifier, '')
dict_value = (
"Yes"
if str(dict_value) == "True"
else "No"
if str(dict_value) == "False"
else dict_value
)
converted_header = field.name
data[converted_header] = dict_value
data['virtual_event_checkin_times'] = get_virtual_checkin_times(attendee.id)
return_dict_list.append(data)
return {
'Tax ID': str(order.tax_business_info) if order.tax_business_info else '',
'Address': str(order.address) if order.address else '',
'Company': str(order.company) if order.company else '',
'Country': str(order.country) if order.country else '',
'State': str(order.state) if order.state else '',
'City': str(order.city) if order.city else '',
'Zipcode': str(order.zipcode) if order.zipcode else '',
}


def get_ticket_data(ticket):
"""Get ticket data from ticket object"""
if not ticket:
return {'Ticket Name': '', 'Ticket Price': '0', 'Ticket Type': ''}

return {
'Ticket Name': str(ticket.name) if ticket.name else '',
'Ticket Price': str(ticket.price) if ticket.price else '0',
'Ticket Type': str(ticket.type) if ticket.type else '',
}


def get_attendee_data(attendee, custom_forms, attendee_form_dict):
"""Get attendee data from attendee object"""
order_ticket_data = get_order_ticket_data(attendee.order, attendee.ticket)
data = {
**order_ticket_data,
'Email': '',
}

for field in custom_forms:
key_mapping = {k.replace("_", "").lower(): k for k in attendee_form_dict.keys()}
field_raw = field.identifier.replace("_", "").lower()
key = key_mapping.get(field_raw)
converted_header = attendee_form_dict.get(key)

if field.is_complex:
fields_dict = attendee.complex_field_values
converted_header = field.name
data[converted_header] = (
fields_dict.get(field.identifier, '') if fields_dict else ''
)
else:
dict_value = getattr(attendee, field.identifier, '')
dict_value = (
"Yes"
if str(dict_value) == "True"
else "No"
if str(dict_value) == "False"
else dict_value
)
converted_header = field.name
data[converted_header] = dict_value

data['virtual_event_checkin_times'] = get_virtual_checkin_times(attendee.id)
return data


def export_attendees_csv(attendees, custom_forms, attendee_form_dict):
"""Export attendees csv"""
return_dict_list = []
for attendee in attendees:
attendee_data = get_attendee_data(attendee, custom_forms, attendee_form_dict)
if attendee_data:
return_dict_list.append(attendee_data)

return return_dict_list

Expand Down
2 changes: 2 additions & 0 deletions app/templates/pdf/attendees_pdf.html
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ <h3 style="text-align:center;">{{ holders[0].event.name }} - {{ ("Attendees List
{{ field.name }} <br>
{% endfor %}
Amount:<br>
Ticket ID:<br>
Ticket Name:<br>
Status:<br>
</td>
Expand All @@ -127,6 +128,7 @@ <h3 style="text-align:center;">{{ holders[0].event.name }} - {{ ("Attendees List
{% else %}
{{ "Free Ticket" }} <br>
{% endif %}
{{ holder.order.identifier }}<br>
{{ holder.ticket.name }}<br>
{% if holder.is_checked_in %}
{{ ("Checked In") }}<br>
Expand Down
4 changes: 2 additions & 2 deletions migrations/versions/rev-2023-08-17-15:38:43-bce7acfe5a4f_.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
"""empty message

Revision ID: bce7acfe5a4f
Revises: 24271525a263
Revises: 1af4cc4f7cd5
Create Date: 2023-08-17 15:38:43.387065

"""
Expand All @@ -12,7 +12,7 @@

# revision identifiers, used by Alembic.
revision = 'bce7acfe5a4f'
down_revision = '24271525a263'
down_revision = '1af4cc4f7cd5'
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is a database migration necessary here? I don't see any changes to the database structure?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because we encountered the problem "Error: Multiple moving heads" when running "ci/circleci:test". So I checked and changed the version of this file

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indeed, previous changes introduce a split tree, how did that happen?
Thanks for fixing it

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I saw this problem happen 6 months ago and don't know why this problem happened



def upgrade():
Expand Down
17 changes: 14 additions & 3 deletions tests/all/integration/api/helpers/test_csv_jobs_util.py
Original file line number Diff line number Diff line change
@@ -1,25 +1,35 @@
import unittest
from datetime import datetime

from app.api.helpers.csv_jobs_util import *
import pytz

from app.api.helpers.csv_jobs_util import (
export_attendees_csv,
export_orders_csv,
export_sessions_csv,
export_speakers_csv,
)
from app.models import db
from app.models.custom_form import ATTENDEE_CUSTOM_FORM
from tests.all.integration.auth_helper import create_user
from tests.all.integration.utils import OpenEventTestCase
from tests.factories import common
from tests.factories.attendee import AttendeeFactory
from tests.factories.custom_form import CustomFormFactory
from tests.factories.event import EventFactoryBasic
from tests.factories.order import OrderFactory
from tests.factories.session import SessionSubFactory
from tests.factories.speaker import SpeakerFactory
from app.models.custom_form import ATTENDEE_CUSTOM_FORM


class TestExportCSV(OpenEventTestCase):
def test_export_orders_csv(self):
"""Method to check the orders data export"""

with self.app.test_request_context():
test_event = EventFactoryBasic()
test_order = OrderFactory(created_at=datetime.now())
test_order.event = test_event
test_order.amount = 2
field_data = export_orders_csv([test_order])
assert field_data[1][2] == 'initializing'
Expand All @@ -34,7 +44,8 @@ def test_export_attendees_csv(self):
test_attendee.order = test_order
custom_forms = CustomFormFactory()
field_data = export_attendees_csv(
[test_attendee], [custom_forms], ATTENDEE_CUSTOM_FORM)
[test_attendee], [custom_forms], ATTENDEE_CUSTOM_FORM
)
# new export_attendees_csv will return list of dictionary for csv_writer
assert field_data[0].get("Tax ID") == "tax id"

Expand Down