From 8df2e67c320d40efd27fbf3d50bbe9d6f734c4f7 Mon Sep 17 00:00:00 2001 From: Chuck Scott Date: Tue, 9 Jul 2019 10:57:03 -0400 Subject: [PATCH] initial commit --- Notes/GaslightPages/SiteSample.html | 20 + Notes/GaslightPages/TicketCart.html | 322 +++ Notes/GaslightPages/TicketCheckout.html | 489 +++++ Notes/GaslightPages/TicketSelection.html | 327 +++ Notes/GaslightPages/css/main.css | 695 +++++++ Notes/Sites_Using.txt | 13 + classes/EasyPassword.php | 42 + classes/EasyPassword.words | 828 ++++++++ classes/GeoCalculations.php | 253 +++ classes/data/Reports/dataEventReport.php | 290 +++ .../data/Reports/dataReservationReport.php | 357 ++++ classes/data/Reports/dataRoomBlockReport.php | 391 ++++ .../data/Reports/dataRoomRequestReport.php | 392 ++++ classes/data/dataAccoms.php | 468 +++++ classes/data/dataAddonSold.php | 290 +++ classes/data/dataAddons.php | 416 ++++ classes/data/dataAmenities.php | 486 +++++ classes/data/dataAttendance.php | 218 ++ classes/data/dataBookings.php | 252 +++ classes/data/dataContacts.php | 862 ++++++++ classes/data/dataDivisions.php | 353 ++++ classes/data/dataEntrances.php | 523 +++++ classes/data/dataEvents.php | 841 ++++++++ classes/data/dataFees.php | 662 +++++++ classes/data/dataInventory.php | 1141 +++++++++++ classes/data/dataMemberScansFor.php | 234 +++ classes/data/dataMembers.php | 1219 ++++++++++++ classes/data/dataMisc.php | 283 +++ classes/data/dataOrders.php | 714 +++++++ classes/data/dataPerformances.php | 956 +++++++++ classes/data/dataPromoSold.php | 268 +++ classes/data/dataPromoTickets.php | 505 +++++ classes/data/dataPromos.php | 376 ++++ classes/data/dataReservations.php | 830 ++++++++ classes/data/dataRooms.php | 457 +++++ classes/data/dataSections.php | 450 +++++ classes/data/dataSold.php | 804 ++++++++ classes/data/dataStates.php | 363 ++++ classes/data/dataTeams.php | 735 +++++++ classes/data/dataTicketClaimTracking.php | 216 ++ classes/data/dataTicketInventory.php | 683 +++++++ classes/data/dataTicketPackages.php | 347 ++++ classes/data/dataTickets.php | 923 +++++++++ classes/data/dataVoucherCoupons.php | 472 +++++ configs/common.ini | 807 ++++++++ controllers/AdminController.php | 1051 ++++++++++ controllers/FrontController.php | 909 +++++++++ data/DatabaseModificationsForTicketing.sql | 2 + data/EventManagement.sql | 1183 +++++++++++ docs/Current_Deployment_Notes.txt | 638 ++++++ docs/Delete_Event.sql | 21 + docs/Development_Notes.txt | 513 +++++ docs/Field Specifications | 271 +++ docs/Install.txt | 226 +++ docs/ProgramFlow.txt | 83 + docs/Sites_Using.txt | 6 + docs/Streamlined Ticketing for Star Line.odg | Bin 0 -> 16904 bytes docs/Testing Notes.txt | 12 + .../EventManagement/EventManagement.php | 19 + .../MembersEventManagement.php | 57 + ...OT_SURE_ABOUT_THIS_STUFF_MIGHT_NOT_BE_USED | 0 docs/VenueAdminGuide.odt | Bin 0 -> 311096 bytes .../admin/EventManagement/EventManagement.php | 19 + docs/barcode/FRE3OF9X.TTF | Bin 0 -> 7220 bytes docs/barcode/FREE3OF9.TTF | Bin 0 -> 5116 bytes docs/barcode/FREE3OF9.TXT | 71 + docs/config.ini.SAMPLE | 664 +++++++ docs/config/applications/EventManagement.ini | 227 +++ help.html | 96 + index.html | 17 + models/admin/actions/Accommodation/add.inc | 30 + .../admin/actions/Accommodation/addRoom.inc | 30 + models/admin/actions/Accommodation/detail.inc | 31 + models/admin/actions/Accommodation/edit.inc | 31 + .../admin/actions/Accommodation/editRoom.inc | 29 + models/admin/actions/Accommodation/insert.inc | 40 + .../actions/Accommodation/insertRoom.inc | 50 + models/admin/actions/Accommodation/list.inc | 31 + models/admin/actions/Accommodation/update.inc | 44 + .../actions/Accommodation/updateRoom.inc | 52 + models/admin/actions/Addon/add.inc | 30 + models/admin/actions/Addon/confirmDelete.inc | 26 + models/admin/actions/Addon/delete.inc | 26 + models/admin/actions/Addon/detail.inc | 26 + models/admin/actions/Addon/edit.inc | 30 + models/admin/actions/Addon/insert.inc | 43 + models/admin/actions/Addon/list.inc | 30 + models/admin/actions/Addon/selected.inc | 25 + models/admin/actions/Addon/update.inc | 43 + models/admin/actions/Attendance/add.inc | 36 + .../actions/Attendance/confirmDelete.inc | 26 + models/admin/actions/Attendance/delete.inc | 26 + models/admin/actions/Attendance/detail.inc | 26 + models/admin/actions/Attendance/edit.inc | 30 + models/admin/actions/Attendance/insert.inc | 45 + models/admin/actions/Attendance/list.inc | 30 + models/admin/actions/Attendance/selected.inc | 25 + models/admin/actions/Attendance/update.inc | 43 + models/admin/actions/Block/detail.inc | 27 + models/admin/actions/Block/show.inc | 30 + models/admin/actions/Block/summary.inc | 26 + models/admin/actions/Block/updateBlocks.inc | 24 + models/admin/actions/Block/updateDetail.inc | 25 + models/admin/actions/Booking/add.inc | 92 + models/admin/actions/Booking/detail.inc | 25 + models/admin/actions/Booking/insert.inc | 146 ++ models/admin/actions/Booking/list.inc | 43 + models/admin/actions/Contact/add.inc | 31 + .../admin/actions/Contact/confirmDelete.inc | 26 + models/admin/actions/Contact/delete.inc | 27 + models/admin/actions/Contact/detail.inc | 26 + models/admin/actions/Contact/edit.inc | 30 + models/admin/actions/Contact/insert.inc | 40 + models/admin/actions/Contact/list.inc | 30 + models/admin/actions/Contact/update.inc | 42 + models/admin/actions/Debug/start.inc | 19 + models/admin/actions/Debug/update.inc | 29 + models/admin/actions/Division/add.inc | 28 + models/admin/actions/Division/detail.inc | 24 + models/admin/actions/Division/edit.inc | 29 + models/admin/actions/Division/insert.inc | 38 + models/admin/actions/Division/list.inc | 29 + models/admin/actions/Division/update.inc | 42 + models/admin/actions/Entrance/add.inc | 31 + .../admin/actions/Entrance/confirmDelete.inc | 26 + models/admin/actions/Entrance/delete.inc | 27 + models/admin/actions/Entrance/detail.inc | 26 + models/admin/actions/Entrance/edit.inc | 30 + models/admin/actions/Entrance/insert.inc | 40 + models/admin/actions/Entrance/list.inc | 27 + models/admin/actions/Entrance/update.inc | 42 + models/admin/actions/Event/add.inc | 30 + models/admin/actions/Event/detail.inc | 32 + models/admin/actions/Event/edit.inc | 32 + models/admin/actions/Event/insert.inc | 39 + models/admin/actions/Event/list.inc | 30 + models/admin/actions/Event/stats.inc | 26 + models/admin/actions/Event/update.inc | 42 + models/admin/actions/EventFee/add.inc | 28 + .../admin/actions/EventFee/confirmDelete.inc | 24 + models/admin/actions/EventFee/delete.inc | 24 + models/admin/actions/EventFee/detail.inc | 26 + models/admin/actions/EventFee/edit.inc | 32 + models/admin/actions/EventFee/insert.inc | 38 + models/admin/actions/EventFee/list.inc | 31 + models/admin/actions/EventFee/update.inc | 42 + models/admin/actions/Help/index.inc | 18 + models/admin/actions/Index/index.inc | 27 + models/admin/actions/Index/welcome.inc | 18 + models/admin/actions/Member/add.inc | 30 + models/admin/actions/Member/confirmDelete.inc | 27 + models/admin/actions/Member/delete.inc | 32 + models/admin/actions/Member/detail.inc | 48 + models/admin/actions/Member/edit.inc | 59 + models/admin/actions/Member/index.inc | 17 + models/admin/actions/Member/insert.inc | 41 + models/admin/actions/Member/list.inc | 35 + models/admin/actions/Member/selected.inc | 100 + models/admin/actions/Member/stats.inc | 32 + models/admin/actions/Member/update.inc | 56 + models/admin/actions/MemberAmenities/add.inc | 28 + .../admin/actions/MemberAmenities/detail.inc | 25 + models/admin/actions/MemberAmenities/edit.inc | 30 + .../admin/actions/MemberAmenities/insert.inc | 38 + models/admin/actions/MemberAmenities/list.inc | 29 + .../admin/actions/MemberAmenities/update.inc | 42 + models/admin/actions/MemberFee/add.inc | 34 + .../admin/actions/MemberFee/confirmDelete.inc | 24 + models/admin/actions/MemberFee/delete.inc | 24 + models/admin/actions/MemberFee/detail.inc | 25 + models/admin/actions/MemberFee/edit.inc | 37 + models/admin/actions/MemberFee/insert.inc | 38 + models/admin/actions/MemberFee/list.inc | 29 + models/admin/actions/MemberFee/update.inc | 42 + models/admin/actions/Misc/blank.inc | 18 + models/admin/actions/Misc/configDetail.inc | 28 + models/admin/actions/Misc/configEdit.inc | 25 + models/admin/actions/Misc/configUpdate.inc | 40 + models/admin/actions/Misc/index.inc | 18 + models/admin/actions/Misc/upload.inc | 26 + models/admin/actions/Misc/uploadIndex.inc | 80 + .../admin/actions/Misc/uploadStylesheet.inc | 69 + models/admin/actions/Order/delete.inc | 49 + models/admin/actions/Order/detail.inc | 43 + models/admin/actions/Order/edit.inc | 30 + models/admin/actions/Order/list.inc | 35 + models/admin/actions/Order/printVoucher.inc | 50 + .../actions/Order/printVoucherMobile.inc | 48 + models/admin/actions/Order/selected.inc | 25 + models/admin/actions/Order/update.inc | 46 + models/admin/actions/Performance/add.inc | 31 + .../actions/Performance/confirmDelete.inc | 26 + models/admin/actions/Performance/delete.inc | 27 + models/admin/actions/Performance/detail.inc | 26 + models/admin/actions/Performance/edit.inc | 30 + models/admin/actions/Performance/insert.inc | 42 + models/admin/actions/Performance/list.inc | 45 + models/admin/actions/Performance/selected.inc | 26 + models/admin/actions/Performance/summary.inc | 51 + models/admin/actions/Performance/update.inc | 41 + models/admin/actions/Promo/add.inc | 30 + models/admin/actions/Promo/confirmDelete.inc | 26 + models/admin/actions/Promo/delete.inc | 26 + models/admin/actions/Promo/detail.inc | 80 + models/admin/actions/Promo/edit.inc | 30 + models/admin/actions/Promo/insert.inc | 43 + models/admin/actions/Promo/list.inc | 30 + models/admin/actions/Promo/selected.inc | 25 + models/admin/actions/Promo/update.inc | 43 + models/admin/actions/Report/custom.inc | 575 ++++++ .../admin/actions/Report/customManifest.inc | 176 ++ models/admin/actions/Report/index.inc | 18 + models/admin/actions/Report/member.inc | 176 ++ models/admin/actions/Report/orders.inc | 280 +++ models/admin/actions/Report/promo.inc | 293 +++ models/admin/actions/Report/sales.inc | 791 ++++++++ models/admin/actions/Reservation/detail.inc | 24 + models/admin/actions/Reservation/edit.inc | 20 + models/admin/actions/Reservation/list.inc | 53 + models/admin/actions/Reservation/update.inc | 20 + models/admin/actions/Section/add.inc | 31 + .../admin/actions/Section/confirmDelete.inc | 26 + models/admin/actions/Section/delete.inc | 27 + models/admin/actions/Section/detail.inc | 26 + models/admin/actions/Section/edit.inc | 30 + models/admin/actions/Section/insert.inc | 40 + models/admin/actions/Section/list.inc | 27 + models/admin/actions/Section/update.inc | 42 + models/admin/actions/Sold/claim.inc | 24 + models/admin/actions/Sold/claimVoucher.inc | 44 + models/admin/actions/Sold/detail.inc | 315 +++ models/admin/actions/Sold/fixPackages.inc | 170 ++ models/admin/actions/Sold/list.inc | 35 + models/admin/actions/Sold/resetVoucher.inc | 45 + models/admin/actions/Sold/selected.inc | 25 + models/admin/actions/State/add.inc | 36 + models/admin/actions/State/detail.inc | 36 + models/admin/actions/State/edit.inc | 44 + models/admin/actions/State/insert.inc | 40 + models/admin/actions/State/list.inc | 31 + models/admin/actions/State/update.inc | 44 + models/admin/actions/Team/add.inc | 35 + models/admin/actions/Team/detail.inc | 31 + models/admin/actions/Team/edit.inc | 31 + models/admin/actions/Team/editRoster.inc | 26 + models/admin/actions/Team/insert.inc | 40 + models/admin/actions/Team/list.inc | 54 + models/admin/actions/Team/update.inc | 45 + models/admin/actions/Team/updateRoster.inc | 32 + models/admin/actions/Ticket/add.inc | 58 + models/admin/actions/Ticket/confirmDelete.inc | 26 + models/admin/actions/Ticket/delete.inc | 27 + models/admin/actions/Ticket/detail.inc | 47 + models/admin/actions/Ticket/edit.inc | 46 + models/admin/actions/Ticket/insert.inc | 63 + models/admin/actions/Ticket/inventory.inc | 59 + .../admin/actions/Ticket/inventoryUpdate.inc | 36 + models/admin/actions/Ticket/list.inc | 46 + .../actions/Ticket/printSampleVoucher.inc | 145 ++ models/admin/actions/Ticket/selected.inc | 50 + models/admin/actions/Ticket/setActive.inc | 28 + models/admin/actions/Ticket/update.inc | 56 + models/admin/actions/User/login.inc | 17 + models/admin/actions/VoucherCoupon/add.inc | 30 + .../actions/VoucherCoupon/confirmDelete.inc | 26 + models/admin/actions/VoucherCoupon/delete.inc | 26 + models/admin/actions/VoucherCoupon/detail.inc | 26 + models/admin/actions/VoucherCoupon/edit.inc | 27 + models/admin/actions/VoucherCoupon/insert.inc | 43 + models/admin/actions/VoucherCoupon/list.inc | 30 + .../admin/actions/VoucherCoupon/selected.inc | 25 + models/admin/actions/VoucherCoupon/test.inc | 25 + models/admin/actions/VoucherCoupon/update.inc | 38 + models/admin/actions/inventory/add.inc | 40 + models/admin/actions/inventory/detail.inc | 27 + models/admin/actions/inventory/edit.inc | 31 + models/admin/actions/inventory/insert.inc | 48 + models/admin/actions/inventory/list.inc | 68 + models/admin/actions/inventory/selected.inc | 49 + models/admin/actions/inventory/update.inc | 50 + models/admin/classes/accommodations.php | 80 + models/admin/classes/addons.php | 81 + models/admin/classes/addonsSold.php | 57 + models/admin/classes/attendance.php | 70 + models/admin/classes/blocks.php | 1025 ++++++++++ models/admin/classes/bookings.php | 102 + models/admin/classes/contacts.php | 122 ++ models/admin/classes/dataList.php | 188 ++ models/admin/classes/divisions.php | 87 + models/admin/classes/entrances.php | 81 + models/admin/classes/eventFees.php | 86 + models/admin/classes/eventReport.php | 206 ++ models/admin/classes/events.php | 153 ++ models/admin/classes/inventory.php | 124 ++ models/admin/classes/memberAmenities.php | 86 + models/admin/classes/memberFees.php | 86 + models/admin/classes/members.php | 198 ++ models/admin/classes/misc.php | 58 + models/admin/classes/orders.php | 58 + models/admin/classes/performances.php | 79 + models/admin/classes/promoTickets.php | 126 ++ models/admin/classes/promos.php | 68 + models/admin/classes/promosSold.php | 57 + models/admin/classes/reservationReport.php | 343 ++++ models/admin/classes/reservations.php | 103 + models/admin/classes/roomBlockReport.php | 240 +++ models/admin/classes/roomRequestReport.php | 383 ++++ models/admin/classes/rooms.php | 68 + models/admin/classes/sections.php | 81 + models/admin/classes/sold.php | 58 + models/admin/classes/states.php | 86 + models/admin/classes/teams.php | 98 + models/admin/classes/ticketInventory.php | 231 +++ models/admin/classes/tickets.php | 82 + models/admin/classes/voucherCoupons.php | 68 + models/front/actions/Debug/start.inc | 19 + models/front/actions/Debug/update.inc | 29 + models/front/actions/Index/index.inc | 21 + models/front/actions/Shop/PayPal.inc | 110 ++ models/front/actions/Shop/PayPalApproved.inc | 96 + models/front/actions/Shop/additionalInfo.inc | 177 ++ models/front/actions/Shop/cart.inc | 203 ++ models/front/actions/Shop/checkout.inc | 224 +++ models/front/actions/Shop/checkoutSubmit.inc | 323 +++ models/front/actions/Shop/printVoucher.inc | 60 + models/front/actions/Shop/sectionSelect.inc | 83 + models/front/actions/Shop/start.inc | 127 ++ models/front/actions/Shop/ticketOpt.inc | 265 +++ models/front/actions/Shop/ticketSelect.inc | 77 + models/front/classes/checkoutSupport.php | 1750 +++++++++++++++++ models/front/classes/support.php | 1602 +++++++++++++++ models/vouchers/Gaslight/voucher.php | 614 ++++++ models/vouchers/Generic/voucher.php | 607 ++++++ models/vouchers/MMM/voucher.php | 1146 +++++++++++ models/vouchers/MMM/voucher.php.SAVE | 614 ++++++ models/vouchers/MackinacFerry/voucher.php | 1133 +++++++++++ .../vouchers/MackinacFerry/voucherMobile.php | 711 +++++++ models/vouchers/PointerBoat/voucher.php | 1183 +++++++++++ models/vouchers/PointerBoat/voucher.php.SAVE | 614 ++++++ models/vouchers/SaultSteMarie/voucher.php | 610 ++++++ views/NOTE.txt | 2 + views/admin/tickets/Accommodation/list.html | 28 + views/admin/tickets/Addon/delete.html | 63 + views/admin/tickets/Addon/detail.html | 74 + views/admin/tickets/Addon/edit.html | 200 ++ views/admin/tickets/Addon/list.html | 124 ++ views/admin/tickets/Addon/selected.html | 32 + views/admin/tickets/Attendance/added.html | 16 + views/admin/tickets/Attendance/delete.html | 90 + views/admin/tickets/Attendance/detail.html | 115 ++ views/admin/tickets/Attendance/edit.html | 185 ++ views/admin/tickets/Attendance/list.html | 125 ++ views/admin/tickets/Contact/added.html | 16 + views/admin/tickets/Contact/delete.html | 90 + views/admin/tickets/Contact/detail.html | 115 ++ views/admin/tickets/Contact/edit.html | 341 ++++ views/admin/tickets/Contact/list.html | 125 ++ views/admin/tickets/Debug/index.html | 62 + views/admin/tickets/Debug/start.html | 56 + views/admin/tickets/Entrance/delete.html | 55 + views/admin/tickets/Entrance/detail.html | 104 + views/admin/tickets/Entrance/edit.html | 299 +++ views/admin/tickets/Entrance/list.html | 129 ++ views/admin/tickets/Event/index.html | 17 + views/admin/tickets/Help/index.html | 43 + views/admin/tickets/Member/added.html | 16 + views/admin/tickets/Member/delete.html | 228 +++ views/admin/tickets/Member/detail.html | 411 ++++ views/admin/tickets/Member/detail.html.SAVE | 290 +++ views/admin/tickets/Member/edit.html | 874 ++++++++ views/admin/tickets/Member/edit.html.SAVE | 762 +++++++ views/admin/tickets/Member/index.html | 38 + views/admin/tickets/Member/list.html | 131 ++ views/admin/tickets/Member/redisplayList.html | 19 + views/admin/tickets/Member/selected.html | 139 ++ views/admin/tickets/Member/stats.html | 69 + views/admin/tickets/Misc/blank.html | 2 + views/admin/tickets/Misc/configDetail.html | 81 + views/admin/tickets/Misc/configEdit.html | 222 +++ views/admin/tickets/Misc/index.html | 47 + views/admin/tickets/Misc/upload.html | 191 ++ views/admin/tickets/Order/detail.html | 135 ++ views/admin/tickets/Order/edit.html | 243 +++ views/admin/tickets/Order/list.html | 132 ++ views/admin/tickets/Order/selected.html | 45 + views/admin/tickets/Performance/delete.html | 63 + views/admin/tickets/Performance/detail.html | 100 + views/admin/tickets/Performance/edit.html | 314 +++ views/admin/tickets/Performance/list.html | 144 ++ .../tickets/Performance/redisplayList.html | 18 + views/admin/tickets/Performance/selected.html | 53 + views/admin/tickets/Performance/summary.html | 113 ++ views/admin/tickets/Promo/delete.html | 57 + views/admin/tickets/Promo/detail.html | 168 ++ views/admin/tickets/Promo/edit.html | 207 ++ views/admin/tickets/Promo/list.html | 124 ++ views/admin/tickets/Promo/selected.html | 32 + views/admin/tickets/Report/customClaimed.html | 152 ++ .../tickets/Report/customClaimedCSV.html | 7 + .../tickets/Report/customClaimedDetail.html | 149 ++ .../Report/customClaimedDetailCSV.html | 11 + .../admin/tickets/Report/customManifest.html | 106 + .../tickets/Report/customManifestCSV.html | 6 + .../tickets/Report/customReportSelection.html | 233 +++ views/admin/tickets/Report/error.html | 14 + views/admin/tickets/Report/index.html | 56 + views/admin/tickets/Report/member.html | 119 ++ views/admin/tickets/Report/memberCSV.html | 9 + .../tickets/Report/memberReportSelection.html | 187 ++ views/admin/tickets/Report/orders.html | 169 ++ views/admin/tickets/Report/ordersCSV.html | 9 + .../tickets/Report/ordersReportSelection.html | 309 +++ views/admin/tickets/Report/promoCSV.html | 10 + views/admin/tickets/Report/promoDetail.html | 221 +++ .../tickets/Report/promoReportSelection.html | 220 +++ views/admin/tickets/Report/promoSummary.html | 129 ++ views/admin/tickets/Report/sales.html | 171 ++ views/admin/tickets/Report/salesCSV.html | 10 + views/admin/tickets/Report/salesDetail.html | 240 +++ .../admin/tickets/Report/salesDetailCSV.html | 11 + .../tickets/Report/salesPackageTickets.html | 141 ++ .../Report/salesPackageTicketsCSV.html | 11 + .../tickets/Report/salesReportSelection.html | 259 +++ views/admin/tickets/Section/delete.html | 55 + views/admin/tickets/Section/detail.html | 75 + views/admin/tickets/Section/edit.html | 186 ++ views/admin/tickets/Section/list.html | 127 ++ views/admin/tickets/Sold/claim.html | 87 + views/admin/tickets/Sold/detail.html | 278 +++ views/admin/tickets/Sold/list.html | 113 ++ views/admin/tickets/Sold/selected.html | 56 + views/admin/tickets/Ticket/addGetMember.html | 90 + views/admin/tickets/Ticket/delete.html | 140 ++ views/admin/tickets/Ticket/detail.html | 200 ++ views/admin/tickets/Ticket/edit.html | 663 +++++++ views/admin/tickets/Ticket/inventory.html | 262 +++ .../tickets/Ticket/inventoryNoCalendar.html | 80 + views/admin/tickets/Ticket/list.html | 166 ++ views/admin/tickets/Ticket/selected.html | 74 + views/admin/tickets/User/index.html | 85 + views/admin/tickets/User/loginForm.html | 105 + views/admin/tickets/VoucherCoupon/delete.html | 66 + views/admin/tickets/VoucherCoupon/detail.html | 76 + views/admin/tickets/VoucherCoupon/edit.html | 283 +++ views/admin/tickets/VoucherCoupon/list.html | 131 ++ .../admin/tickets/VoucherCoupon/selected.html | 32 + views/admin/tickets/VoucherCoupon/test.html | 142 ++ views/admin/tickets/Welcome/index.html | 60 + views/admin/tickets/index.html | 158 ++ views/admin/tickets/index.html.SAVE | 155 ++ .../FoundationStandAlone/Debug/index.html | 44 + .../FoundationStandAlone/Debug/start.html | 27 + .../Shop/PayPalApproved.html | 41 + .../FoundationStandAlone/Shop/PayPalFail.html | 49 + .../Shop/additionalInfo.html | 246 +++ .../front/FoundationStandAlone/Shop/cart.html | 670 +++++++ .../FoundationStandAlone/Shop/checkout.html | 1159 +++++++++++ .../Shop/checkoutSuccess.html | 638 ++++++ .../Shop/paymentSummary.html | 103 + .../Shop/sectionSelect.html | 96 + .../FoundationStandAlone/Shop/start-COPY.html | 162 ++ .../FoundationStandAlone/Shop/start.html | 882 +++++++++ .../FoundationStandAlone/Shop/ticketOpt.html | 286 +++ .../Shop/ticketSelect.html | 491 +++++ views/front/FoundationStandAlone/foot.html | 27 + views/front/FoundationStandAlone/head.html | 71 + views/front/FoundationStandAlone/index.html | 34 + views/front/Gaslight/Debug/index.html | 42 + views/front/Gaslight/Debug/start.html | 27 + views/front/Gaslight/Shop/PayPalApproved.html | 41 + views/front/Gaslight/Shop/PayPalFail.html | 49 + views/front/Gaslight/Shop/additionalInfo.html | 246 +++ views/front/Gaslight/Shop/cart.html | 422 ++++ views/front/Gaslight/Shop/checkout.html | 892 +++++++++ .../front/Gaslight/Shop/checkoutSuccess.html | 374 ++++ views/front/Gaslight/Shop/paymentSummary.html | 125 ++ views/front/Gaslight/Shop/sectionSelect.html | 96 + views/front/Gaslight/Shop/start-COPY.html | 162 ++ views/front/Gaslight/Shop/start.html | 398 ++++ views/front/Gaslight/Shop/svn-commit.tmp | 4 + views/front/Gaslight/Shop/ticketOpt.html | 273 +++ views/front/Gaslight/Shop/ticketSelect.html | 314 +++ views/front/Gaslight/foot.html | 9 + views/front/Gaslight/head.html | 38 + views/front/Gaslight/index.html | 34 + views/front/MMM/Debug/index.html | 42 + views/front/MMM/Debug/start.html | 27 + views/front/MMM/Shop/PayPalApproved.html | 41 + views/front/MMM/Shop/PayPalFail.html | 49 + views/front/MMM/Shop/additionalInfo.html | 246 +++ views/front/MMM/Shop/cart.html | 429 ++++ views/front/MMM/Shop/checkout.html | 926 +++++++++ views/front/MMM/Shop/checkoutSuccess.html | 380 ++++ views/front/MMM/Shop/paymentSummary.html | 131 ++ views/front/MMM/Shop/sectionSelect.html | 96 + views/front/MMM/Shop/start-COPY.html | 162 ++ views/front/MMM/Shop/start.html | 406 ++++ views/front/MMM/Shop/svn-commit.tmp | 4 + views/front/MMM/Shop/ticketOpt.html | 273 +++ views/front/MMM/Shop/ticketSelect.html | 326 +++ views/front/MMM/foot.html | 9 + views/front/MMM/head.html | 38 + views/front/MMM/index.html | 34 + views/front/PointerBoat/Debug/index.html | 42 + views/front/PointerBoat/Debug/start.html | 27 + .../PointerBoat/Shop/PayPalApproved.html | 41 + views/front/PointerBoat/Shop/PayPalFail.html | 49 + .../PointerBoat/Shop/additionalInfo.html | 246 +++ views/front/PointerBoat/Shop/cart.html | 431 ++++ views/front/PointerBoat/Shop/checkout.html | 939 +++++++++ .../PointerBoat/Shop/checkoutSuccess.html | 378 ++++ .../PointerBoat/Shop/paymentSummary.html | 135 ++ .../front/PointerBoat/Shop/sectionSelect.html | 96 + views/front/PointerBoat/Shop/start-COPY.html | 162 ++ views/front/PointerBoat/Shop/start.html | 387 ++++ views/front/PointerBoat/Shop/svn-commit.tmp | 4 + views/front/PointerBoat/Shop/ticketOpt.html | 273 +++ .../front/PointerBoat/Shop/ticketSelect.html | 327 +++ .../Shop_Backup/PayPalApproved.html | 41 + .../PointerBoat/Shop_Backup/PayPalFail.html | 49 + .../Shop_Backup/additionalInfo.html | 246 +++ views/front/PointerBoat/Shop_Backup/cart.html | 429 ++++ .../PointerBoat/Shop_Backup/checkout.html | 926 +++++++++ .../Shop_Backup/checkoutSuccess.html | 380 ++++ .../Shop_Backup/paymentSummary.html | 131 ++ .../Shop_Backup/sectionSelect.html | 96 + .../PointerBoat/Shop_Backup/start-COPY.html | 162 ++ .../front/PointerBoat/Shop_Backup/start.html | 407 ++++ .../PointerBoat/Shop_Backup/svn-commit.tmp | 4 + .../PointerBoat/Shop_Backup/ticketOpt.html | 273 +++ .../PointerBoat/Shop_Backup/ticketSelect.html | 326 +++ views/front/PointerBoat/foot.html | 9 + views/front/PointerBoat/head.html | 38 + views/front/PointerBoat/index.html | 34 + views/front/SaultSteMarie/Debug/index.html | 42 + views/front/SaultSteMarie/Debug/start.html | 27 + .../SaultSteMarie/Shop/PayPalApproved.html | 41 + .../front/SaultSteMarie/Shop/PayPalFail.html | 49 + .../SaultSteMarie/Shop/additionalInfo.html | 246 +++ views/front/SaultSteMarie/Shop/cart.html | 415 ++++ views/front/SaultSteMarie/Shop/checkout.html | 885 +++++++++ .../SaultSteMarie/Shop/checkoutSuccess.html | 367 ++++ .../SaultSteMarie/Shop/paymentSummary.html | 118 ++ .../SaultSteMarie/Shop/sectionSelect.html | 96 + .../front/SaultSteMarie/Shop/start-COPY.html | 162 ++ views/front/SaultSteMarie/Shop/start.html | 398 ++++ views/front/SaultSteMarie/Shop/ticketOpt.html | 273 +++ .../SaultSteMarie/Shop/ticketSelect.html | 314 +++ views/front/SaultSteMarie/foot.html | 9 + views/front/SaultSteMarie/head.html | 38 + views/front/SaultSteMarie/index.html | 34 + .../front/TicketsFoundation/Debug/index.html | 44 + .../front/TicketsFoundation/Debug/start.html | 27 + .../TicketsFoundation/Shop/Copy of cart.html | 404 ++++ .../Shop/PayPalApproved.html | 41 + .../TicketsFoundation/Shop/PayPalFail.html | 49 + views/front/TicketsFoundation/Shop/cart.html | 534 +++++ .../TicketsFoundation/Shop/checkout.html | 927 +++++++++ .../Shop/checkoutSuccess.html | 489 +++++ .../Shop/paymentSummary.html | 112 ++ .../TicketsFoundation/Shop/sectionSelect.html | 96 + views/front/TicketsFoundation/Shop/start.html | 396 ++++ .../TicketsFoundation/Shop/ticketOpt.html | 286 +++ .../TicketsFoundation/Shop/ticketSelect.html | 425 ++++ views/front/TicketsFoundation/foot.html | 19 + views/front/TicketsFoundation/head.html | 66 + views/front/TicketsFoundation/index.html | 34 + views/front/tickets/Debug/index.html | 42 + views/front/tickets/Debug/start.html | 27 + views/front/tickets/Shop/PayPalApproved.html | 41 + views/front/tickets/Shop/PayPalFail.html | 49 + views/front/tickets/Shop/cart.html | 410 ++++ views/front/tickets/Shop/checkout.html | 717 +++++++ views/front/tickets/Shop/checkoutSuccess.html | 367 ++++ views/front/tickets/Shop/paymentSummary.html | 103 + views/front/tickets/Shop/sectionSelect.html | 96 + views/front/tickets/Shop/start.html | 398 ++++ views/front/tickets/Shop/ticketOpt.html | 273 +++ views/front/tickets/Shop/ticketSelect.html | 310 +++ views/front/tickets/foot.html | 9 + views/front/tickets/head.html | 38 + views/front/tickets/index.html | 34 + web/admin/icons/calendar.png | Bin 0 -> 675 bytes web/admin/icons/information.png | Bin 0 -> 778 bytes web/admin/icons/page_edit.png | Bin 0 -> 807 bytes .../tickets/documentation/VenueAdminGuide.pdf | Bin 0 -> 395350 bytes web/admin/tickets/tickets.css | 549 ++++++ web/admin/tickets/tickets.js | 248 +++ .../FoundationStandAlone/EventManagement.css | 594 ++++++ .../FoundationStandAlone/EventManagement.js | 94 + .../assets/get_adobe_reader.png | Bin 0 -> 2597 bytes .../assets/paypal_but6.gif | Bin 0 -> 4774 bytes .../assets/pdficon_large.png | Bin 0 -> 1397 bytes web/front/Gaslight/EventManagement.css | 916 +++++++++ web/front/Gaslight/EventManagement.js | 107 + web/front/Gaslight/assets/paypal_but6.gif | Bin 0 -> 4774 bytes web/front/MMM/EventManagement.css | 916 +++++++++ web/front/MMM/EventManagement.js | 107 + web/front/MMM/assets/paypal_but6.gif | Bin 0 -> 4774 bytes web/front/PointerBoat/EventManagement.css | 916 +++++++++ web/front/PointerBoat/EventManagement.js | 107 + web/front/PointerBoat/assets/paypal_but6.gif | Bin 0 -> 4774 bytes web/front/SaultSteMarie/EventManagement.css | 916 +++++++++ web/front/SaultSteMarie/EventManagement.js | 107 + .../SaultSteMarie/assets/paypal_but6.gif | Bin 0 -> 4774 bytes .../TicketsFoundation/EventManagement.css | 772 ++++++++ .../TicketsFoundation/EventManagement.js | 94 + .../assets/get_adobe_reader.png | Bin 0 -> 2597 bytes .../TicketsFoundation/assets/paypal_but6.gif | Bin 0 -> 4774 bytes .../assets/pdficon_large.png | Bin 0 -> 1397 bytes web/front/tickets/EventManagement.css | 773 ++++++++ web/front/tickets/EventManagement.js | 94 + web/front/tickets/assets/paypal_but6.gif | Bin 0 -> 4774 bytes 613 files changed, 108070 insertions(+) create mode 100644 Notes/GaslightPages/SiteSample.html create mode 100644 Notes/GaslightPages/TicketCart.html create mode 100644 Notes/GaslightPages/TicketCheckout.html create mode 100644 Notes/GaslightPages/TicketSelection.html create mode 100644 Notes/GaslightPages/css/main.css create mode 100644 Notes/Sites_Using.txt create mode 100644 classes/EasyPassword.php create mode 100644 classes/EasyPassword.words create mode 100644 classes/GeoCalculations.php create mode 100644 classes/data/Reports/dataEventReport.php create mode 100644 classes/data/Reports/dataReservationReport.php create mode 100644 classes/data/Reports/dataRoomBlockReport.php create mode 100644 classes/data/Reports/dataRoomRequestReport.php create mode 100644 classes/data/dataAccoms.php create mode 100644 classes/data/dataAddonSold.php create mode 100644 classes/data/dataAddons.php create mode 100644 classes/data/dataAmenities.php create mode 100644 classes/data/dataAttendance.php create mode 100644 classes/data/dataBookings.php create mode 100644 classes/data/dataContacts.php create mode 100644 classes/data/dataDivisions.php create mode 100644 classes/data/dataEntrances.php create mode 100644 classes/data/dataEvents.php create mode 100644 classes/data/dataFees.php create mode 100644 classes/data/dataInventory.php create mode 100644 classes/data/dataMemberScansFor.php create mode 100644 classes/data/dataMembers.php create mode 100644 classes/data/dataMisc.php create mode 100644 classes/data/dataOrders.php create mode 100644 classes/data/dataPerformances.php create mode 100644 classes/data/dataPromoSold.php create mode 100644 classes/data/dataPromoTickets.php create mode 100644 classes/data/dataPromos.php create mode 100644 classes/data/dataReservations.php create mode 100644 classes/data/dataRooms.php create mode 100644 classes/data/dataSections.php create mode 100644 classes/data/dataSold.php create mode 100644 classes/data/dataStates.php create mode 100644 classes/data/dataTeams.php create mode 100644 classes/data/dataTicketClaimTracking.php create mode 100644 classes/data/dataTicketInventory.php create mode 100644 classes/data/dataTicketPackages.php create mode 100644 classes/data/dataTickets.php create mode 100644 classes/data/dataVoucherCoupons.php create mode 100644 configs/common.ini create mode 100644 controllers/AdminController.php create mode 100644 controllers/FrontController.php create mode 100644 data/DatabaseModificationsForTicketing.sql create mode 100644 data/EventManagement.sql create mode 100644 docs/Current_Deployment_Notes.txt create mode 100644 docs/Delete_Event.sql create mode 100644 docs/Development_Notes.txt create mode 100644 docs/Field Specifications create mode 100644 docs/Install.txt create mode 100644 docs/ProgramFlow.txt create mode 100644 docs/Sites_Using.txt create mode 100644 docs/Streamlined Ticketing for Star Line.odg create mode 100644 docs/Testing Notes.txt create mode 100644 docs/Toolkit/EventManagement/EventManagement.php create mode 100644 docs/Toolkit/EventManagement/MembersEventManagement.php create mode 100644 docs/Toolkit/EventManagement/NOT_SURE_ABOUT_THIS_STUFF_MIGHT_NOT_BE_USED create mode 100644 docs/VenueAdminGuide.odt create mode 100644 docs/admin/EventManagement/EventManagement.php create mode 100644 docs/barcode/FRE3OF9X.TTF create mode 100644 docs/barcode/FREE3OF9.TTF create mode 100644 docs/barcode/FREE3OF9.TXT create mode 100644 docs/config.ini.SAMPLE create mode 100644 docs/config/applications/EventManagement.ini create mode 100644 help.html create mode 100644 index.html create mode 100644 models/admin/actions/Accommodation/add.inc create mode 100644 models/admin/actions/Accommodation/addRoom.inc create mode 100644 models/admin/actions/Accommodation/detail.inc create mode 100644 models/admin/actions/Accommodation/edit.inc create mode 100644 models/admin/actions/Accommodation/editRoom.inc create mode 100644 models/admin/actions/Accommodation/insert.inc create mode 100644 models/admin/actions/Accommodation/insertRoom.inc create mode 100644 models/admin/actions/Accommodation/list.inc create mode 100644 models/admin/actions/Accommodation/update.inc create mode 100644 models/admin/actions/Accommodation/updateRoom.inc create mode 100644 models/admin/actions/Addon/add.inc create mode 100644 models/admin/actions/Addon/confirmDelete.inc create mode 100644 models/admin/actions/Addon/delete.inc create mode 100644 models/admin/actions/Addon/detail.inc create mode 100644 models/admin/actions/Addon/edit.inc create mode 100644 models/admin/actions/Addon/insert.inc create mode 100644 models/admin/actions/Addon/list.inc create mode 100644 models/admin/actions/Addon/selected.inc create mode 100644 models/admin/actions/Addon/update.inc create mode 100755 models/admin/actions/Attendance/add.inc create mode 100755 models/admin/actions/Attendance/confirmDelete.inc create mode 100755 models/admin/actions/Attendance/delete.inc create mode 100644 models/admin/actions/Attendance/detail.inc create mode 100755 models/admin/actions/Attendance/edit.inc create mode 100755 models/admin/actions/Attendance/insert.inc create mode 100755 models/admin/actions/Attendance/list.inc create mode 100755 models/admin/actions/Attendance/selected.inc create mode 100755 models/admin/actions/Attendance/update.inc create mode 100644 models/admin/actions/Block/detail.inc create mode 100644 models/admin/actions/Block/show.inc create mode 100644 models/admin/actions/Block/summary.inc create mode 100644 models/admin/actions/Block/updateBlocks.inc create mode 100644 models/admin/actions/Block/updateDetail.inc create mode 100644 models/admin/actions/Booking/add.inc create mode 100644 models/admin/actions/Booking/detail.inc create mode 100644 models/admin/actions/Booking/insert.inc create mode 100644 models/admin/actions/Booking/list.inc create mode 100644 models/admin/actions/Contact/add.inc create mode 100644 models/admin/actions/Contact/confirmDelete.inc create mode 100644 models/admin/actions/Contact/delete.inc create mode 100644 models/admin/actions/Contact/detail.inc create mode 100644 models/admin/actions/Contact/edit.inc create mode 100644 models/admin/actions/Contact/insert.inc create mode 100644 models/admin/actions/Contact/list.inc create mode 100644 models/admin/actions/Contact/update.inc create mode 100644 models/admin/actions/Debug/start.inc create mode 100644 models/admin/actions/Debug/update.inc create mode 100644 models/admin/actions/Division/add.inc create mode 100644 models/admin/actions/Division/detail.inc create mode 100644 models/admin/actions/Division/edit.inc create mode 100644 models/admin/actions/Division/insert.inc create mode 100644 models/admin/actions/Division/list.inc create mode 100644 models/admin/actions/Division/update.inc create mode 100644 models/admin/actions/Entrance/add.inc create mode 100644 models/admin/actions/Entrance/confirmDelete.inc create mode 100644 models/admin/actions/Entrance/delete.inc create mode 100644 models/admin/actions/Entrance/detail.inc create mode 100644 models/admin/actions/Entrance/edit.inc create mode 100644 models/admin/actions/Entrance/insert.inc create mode 100644 models/admin/actions/Entrance/list.inc create mode 100644 models/admin/actions/Entrance/update.inc create mode 100644 models/admin/actions/Event/add.inc create mode 100644 models/admin/actions/Event/detail.inc create mode 100644 models/admin/actions/Event/edit.inc create mode 100644 models/admin/actions/Event/insert.inc create mode 100644 models/admin/actions/Event/list.inc create mode 100644 models/admin/actions/Event/stats.inc create mode 100644 models/admin/actions/Event/update.inc create mode 100644 models/admin/actions/EventFee/add.inc create mode 100644 models/admin/actions/EventFee/confirmDelete.inc create mode 100644 models/admin/actions/EventFee/delete.inc create mode 100644 models/admin/actions/EventFee/detail.inc create mode 100644 models/admin/actions/EventFee/edit.inc create mode 100644 models/admin/actions/EventFee/insert.inc create mode 100644 models/admin/actions/EventFee/list.inc create mode 100644 models/admin/actions/EventFee/update.inc create mode 100644 models/admin/actions/Help/index.inc create mode 100644 models/admin/actions/Index/index.inc create mode 100644 models/admin/actions/Index/welcome.inc create mode 100644 models/admin/actions/Member/add.inc create mode 100644 models/admin/actions/Member/confirmDelete.inc create mode 100644 models/admin/actions/Member/delete.inc create mode 100644 models/admin/actions/Member/detail.inc create mode 100644 models/admin/actions/Member/edit.inc create mode 100644 models/admin/actions/Member/index.inc create mode 100644 models/admin/actions/Member/insert.inc create mode 100644 models/admin/actions/Member/list.inc create mode 100644 models/admin/actions/Member/selected.inc create mode 100644 models/admin/actions/Member/stats.inc create mode 100644 models/admin/actions/Member/update.inc create mode 100644 models/admin/actions/MemberAmenities/add.inc create mode 100644 models/admin/actions/MemberAmenities/detail.inc create mode 100644 models/admin/actions/MemberAmenities/edit.inc create mode 100644 models/admin/actions/MemberAmenities/insert.inc create mode 100644 models/admin/actions/MemberAmenities/list.inc create mode 100644 models/admin/actions/MemberAmenities/update.inc create mode 100644 models/admin/actions/MemberFee/add.inc create mode 100644 models/admin/actions/MemberFee/confirmDelete.inc create mode 100644 models/admin/actions/MemberFee/delete.inc create mode 100644 models/admin/actions/MemberFee/detail.inc create mode 100644 models/admin/actions/MemberFee/edit.inc create mode 100644 models/admin/actions/MemberFee/insert.inc create mode 100644 models/admin/actions/MemberFee/list.inc create mode 100644 models/admin/actions/MemberFee/update.inc create mode 100644 models/admin/actions/Misc/blank.inc create mode 100644 models/admin/actions/Misc/configDetail.inc create mode 100644 models/admin/actions/Misc/configEdit.inc create mode 100644 models/admin/actions/Misc/configUpdate.inc create mode 100644 models/admin/actions/Misc/index.inc create mode 100644 models/admin/actions/Misc/upload.inc create mode 100644 models/admin/actions/Misc/uploadIndex.inc create mode 100644 models/admin/actions/Misc/uploadStylesheet.inc create mode 100644 models/admin/actions/Order/delete.inc create mode 100644 models/admin/actions/Order/detail.inc create mode 100644 models/admin/actions/Order/edit.inc create mode 100644 models/admin/actions/Order/list.inc create mode 100644 models/admin/actions/Order/printVoucher.inc create mode 100755 models/admin/actions/Order/printVoucherMobile.inc create mode 100644 models/admin/actions/Order/selected.inc create mode 100644 models/admin/actions/Order/update.inc create mode 100644 models/admin/actions/Performance/add.inc create mode 100644 models/admin/actions/Performance/confirmDelete.inc create mode 100644 models/admin/actions/Performance/delete.inc create mode 100644 models/admin/actions/Performance/detail.inc create mode 100644 models/admin/actions/Performance/edit.inc create mode 100644 models/admin/actions/Performance/insert.inc create mode 100644 models/admin/actions/Performance/list.inc create mode 100644 models/admin/actions/Performance/selected.inc create mode 100644 models/admin/actions/Performance/summary.inc create mode 100644 models/admin/actions/Performance/update.inc create mode 100644 models/admin/actions/Promo/add.inc create mode 100644 models/admin/actions/Promo/confirmDelete.inc create mode 100644 models/admin/actions/Promo/delete.inc create mode 100644 models/admin/actions/Promo/detail.inc create mode 100644 models/admin/actions/Promo/edit.inc create mode 100644 models/admin/actions/Promo/insert.inc create mode 100644 models/admin/actions/Promo/list.inc create mode 100644 models/admin/actions/Promo/selected.inc create mode 100644 models/admin/actions/Promo/update.inc create mode 100644 models/admin/actions/Report/custom.inc create mode 100644 models/admin/actions/Report/customManifest.inc create mode 100644 models/admin/actions/Report/index.inc create mode 100644 models/admin/actions/Report/member.inc create mode 100644 models/admin/actions/Report/orders.inc create mode 100644 models/admin/actions/Report/promo.inc create mode 100644 models/admin/actions/Report/sales.inc create mode 100644 models/admin/actions/Reservation/detail.inc create mode 100644 models/admin/actions/Reservation/edit.inc create mode 100644 models/admin/actions/Reservation/list.inc create mode 100644 models/admin/actions/Reservation/update.inc create mode 100644 models/admin/actions/Section/add.inc create mode 100644 models/admin/actions/Section/confirmDelete.inc create mode 100644 models/admin/actions/Section/delete.inc create mode 100644 models/admin/actions/Section/detail.inc create mode 100644 models/admin/actions/Section/edit.inc create mode 100644 models/admin/actions/Section/insert.inc create mode 100644 models/admin/actions/Section/list.inc create mode 100644 models/admin/actions/Section/update.inc create mode 100644 models/admin/actions/Sold/claim.inc create mode 100644 models/admin/actions/Sold/claimVoucher.inc create mode 100644 models/admin/actions/Sold/detail.inc create mode 100755 models/admin/actions/Sold/fixPackages.inc create mode 100644 models/admin/actions/Sold/list.inc create mode 100644 models/admin/actions/Sold/resetVoucher.inc create mode 100644 models/admin/actions/Sold/selected.inc create mode 100644 models/admin/actions/State/add.inc create mode 100644 models/admin/actions/State/detail.inc create mode 100644 models/admin/actions/State/edit.inc create mode 100644 models/admin/actions/State/insert.inc create mode 100644 models/admin/actions/State/list.inc create mode 100644 models/admin/actions/State/update.inc create mode 100644 models/admin/actions/Team/add.inc create mode 100644 models/admin/actions/Team/detail.inc create mode 100644 models/admin/actions/Team/edit.inc create mode 100644 models/admin/actions/Team/editRoster.inc create mode 100644 models/admin/actions/Team/insert.inc create mode 100644 models/admin/actions/Team/list.inc create mode 100644 models/admin/actions/Team/update.inc create mode 100644 models/admin/actions/Team/updateRoster.inc create mode 100644 models/admin/actions/Ticket/add.inc create mode 100644 models/admin/actions/Ticket/confirmDelete.inc create mode 100644 models/admin/actions/Ticket/delete.inc create mode 100644 models/admin/actions/Ticket/detail.inc create mode 100644 models/admin/actions/Ticket/edit.inc create mode 100644 models/admin/actions/Ticket/insert.inc create mode 100644 models/admin/actions/Ticket/inventory.inc create mode 100644 models/admin/actions/Ticket/inventoryUpdate.inc create mode 100644 models/admin/actions/Ticket/list.inc create mode 100644 models/admin/actions/Ticket/printSampleVoucher.inc create mode 100644 models/admin/actions/Ticket/selected.inc create mode 100644 models/admin/actions/Ticket/setActive.inc create mode 100644 models/admin/actions/Ticket/update.inc create mode 100644 models/admin/actions/User/login.inc create mode 100755 models/admin/actions/VoucherCoupon/add.inc create mode 100755 models/admin/actions/VoucherCoupon/confirmDelete.inc create mode 100755 models/admin/actions/VoucherCoupon/delete.inc create mode 100644 models/admin/actions/VoucherCoupon/detail.inc create mode 100755 models/admin/actions/VoucherCoupon/edit.inc create mode 100755 models/admin/actions/VoucherCoupon/insert.inc create mode 100755 models/admin/actions/VoucherCoupon/list.inc create mode 100755 models/admin/actions/VoucherCoupon/selected.inc create mode 100755 models/admin/actions/VoucherCoupon/test.inc create mode 100755 models/admin/actions/VoucherCoupon/update.inc create mode 100644 models/admin/actions/inventory/add.inc create mode 100644 models/admin/actions/inventory/detail.inc create mode 100644 models/admin/actions/inventory/edit.inc create mode 100644 models/admin/actions/inventory/insert.inc create mode 100644 models/admin/actions/inventory/list.inc create mode 100644 models/admin/actions/inventory/selected.inc create mode 100644 models/admin/actions/inventory/update.inc create mode 100644 models/admin/classes/accommodations.php create mode 100644 models/admin/classes/addons.php create mode 100644 models/admin/classes/addonsSold.php create mode 100755 models/admin/classes/attendance.php create mode 100644 models/admin/classes/blocks.php create mode 100644 models/admin/classes/bookings.php create mode 100644 models/admin/classes/contacts.php create mode 100644 models/admin/classes/dataList.php create mode 100644 models/admin/classes/divisions.php create mode 100644 models/admin/classes/entrances.php create mode 100644 models/admin/classes/eventFees.php create mode 100644 models/admin/classes/eventReport.php create mode 100644 models/admin/classes/events.php create mode 100644 models/admin/classes/inventory.php create mode 100644 models/admin/classes/memberAmenities.php create mode 100644 models/admin/classes/memberFees.php create mode 100644 models/admin/classes/members.php create mode 100644 models/admin/classes/misc.php create mode 100644 models/admin/classes/orders.php create mode 100644 models/admin/classes/performances.php create mode 100644 models/admin/classes/promoTickets.php create mode 100644 models/admin/classes/promos.php create mode 100644 models/admin/classes/promosSold.php create mode 100644 models/admin/classes/reservationReport.php create mode 100644 models/admin/classes/reservations.php create mode 100644 models/admin/classes/roomBlockReport.php create mode 100644 models/admin/classes/roomRequestReport.php create mode 100644 models/admin/classes/rooms.php create mode 100644 models/admin/classes/sections.php create mode 100644 models/admin/classes/sold.php create mode 100644 models/admin/classes/states.php create mode 100644 models/admin/classes/teams.php create mode 100644 models/admin/classes/ticketInventory.php create mode 100644 models/admin/classes/tickets.php create mode 100755 models/admin/classes/voucherCoupons.php create mode 100644 models/front/actions/Debug/start.inc create mode 100644 models/front/actions/Debug/update.inc create mode 100644 models/front/actions/Index/index.inc create mode 100644 models/front/actions/Shop/PayPal.inc create mode 100644 models/front/actions/Shop/PayPalApproved.inc create mode 100755 models/front/actions/Shop/additionalInfo.inc create mode 100644 models/front/actions/Shop/cart.inc create mode 100644 models/front/actions/Shop/checkout.inc create mode 100644 models/front/actions/Shop/checkoutSubmit.inc create mode 100644 models/front/actions/Shop/printVoucher.inc create mode 100644 models/front/actions/Shop/sectionSelect.inc create mode 100644 models/front/actions/Shop/start.inc create mode 100644 models/front/actions/Shop/ticketOpt.inc create mode 100644 models/front/actions/Shop/ticketSelect.inc create mode 100644 models/front/classes/checkoutSupport.php create mode 100644 models/front/classes/support.php create mode 100644 models/vouchers/Gaslight/voucher.php create mode 100644 models/vouchers/Generic/voucher.php create mode 100644 models/vouchers/MMM/voucher.php create mode 100644 models/vouchers/MMM/voucher.php.SAVE create mode 100644 models/vouchers/MackinacFerry/voucher.php create mode 100644 models/vouchers/MackinacFerry/voucherMobile.php create mode 100644 models/vouchers/PointerBoat/voucher.php create mode 100644 models/vouchers/PointerBoat/voucher.php.SAVE create mode 100644 models/vouchers/SaultSteMarie/voucher.php create mode 100755 views/NOTE.txt create mode 100644 views/admin/tickets/Accommodation/list.html create mode 100644 views/admin/tickets/Addon/delete.html create mode 100644 views/admin/tickets/Addon/detail.html create mode 100644 views/admin/tickets/Addon/edit.html create mode 100644 views/admin/tickets/Addon/list.html create mode 100644 views/admin/tickets/Addon/selected.html create mode 100755 views/admin/tickets/Attendance/added.html create mode 100755 views/admin/tickets/Attendance/delete.html create mode 100644 views/admin/tickets/Attendance/detail.html create mode 100755 views/admin/tickets/Attendance/edit.html create mode 100644 views/admin/tickets/Attendance/list.html create mode 100644 views/admin/tickets/Contact/added.html create mode 100644 views/admin/tickets/Contact/delete.html create mode 100644 views/admin/tickets/Contact/detail.html create mode 100644 views/admin/tickets/Contact/edit.html create mode 100644 views/admin/tickets/Contact/list.html create mode 100644 views/admin/tickets/Debug/index.html create mode 100644 views/admin/tickets/Debug/start.html create mode 100644 views/admin/tickets/Entrance/delete.html create mode 100644 views/admin/tickets/Entrance/detail.html create mode 100644 views/admin/tickets/Entrance/edit.html create mode 100644 views/admin/tickets/Entrance/list.html create mode 100644 views/admin/tickets/Event/index.html create mode 100644 views/admin/tickets/Help/index.html create mode 100644 views/admin/tickets/Member/added.html create mode 100644 views/admin/tickets/Member/delete.html create mode 100644 views/admin/tickets/Member/detail.html create mode 100644 views/admin/tickets/Member/detail.html.SAVE create mode 100644 views/admin/tickets/Member/edit.html create mode 100644 views/admin/tickets/Member/edit.html.SAVE create mode 100644 views/admin/tickets/Member/index.html create mode 100644 views/admin/tickets/Member/list.html create mode 100644 views/admin/tickets/Member/redisplayList.html create mode 100644 views/admin/tickets/Member/selected.html create mode 100644 views/admin/tickets/Member/stats.html create mode 100644 views/admin/tickets/Misc/blank.html create mode 100644 views/admin/tickets/Misc/configDetail.html create mode 100644 views/admin/tickets/Misc/configEdit.html create mode 100644 views/admin/tickets/Misc/index.html create mode 100644 views/admin/tickets/Misc/upload.html create mode 100644 views/admin/tickets/Order/detail.html create mode 100644 views/admin/tickets/Order/edit.html create mode 100644 views/admin/tickets/Order/list.html create mode 100644 views/admin/tickets/Order/selected.html create mode 100644 views/admin/tickets/Performance/delete.html create mode 100644 views/admin/tickets/Performance/detail.html create mode 100644 views/admin/tickets/Performance/edit.html create mode 100644 views/admin/tickets/Performance/list.html create mode 100644 views/admin/tickets/Performance/redisplayList.html create mode 100644 views/admin/tickets/Performance/selected.html create mode 100644 views/admin/tickets/Performance/summary.html create mode 100644 views/admin/tickets/Promo/delete.html create mode 100644 views/admin/tickets/Promo/detail.html create mode 100644 views/admin/tickets/Promo/edit.html create mode 100644 views/admin/tickets/Promo/list.html create mode 100644 views/admin/tickets/Promo/selected.html create mode 100644 views/admin/tickets/Report/customClaimed.html create mode 100755 views/admin/tickets/Report/customClaimedCSV.html create mode 100644 views/admin/tickets/Report/customClaimedDetail.html create mode 100755 views/admin/tickets/Report/customClaimedDetailCSV.html create mode 100644 views/admin/tickets/Report/customManifest.html create mode 100755 views/admin/tickets/Report/customManifestCSV.html create mode 100644 views/admin/tickets/Report/customReportSelection.html create mode 100755 views/admin/tickets/Report/error.html create mode 100644 views/admin/tickets/Report/index.html create mode 100644 views/admin/tickets/Report/member.html create mode 100644 views/admin/tickets/Report/memberCSV.html create mode 100644 views/admin/tickets/Report/memberReportSelection.html create mode 100644 views/admin/tickets/Report/orders.html create mode 100644 views/admin/tickets/Report/ordersCSV.html create mode 100644 views/admin/tickets/Report/ordersReportSelection.html create mode 100755 views/admin/tickets/Report/promoCSV.html create mode 100644 views/admin/tickets/Report/promoDetail.html create mode 100644 views/admin/tickets/Report/promoReportSelection.html create mode 100644 views/admin/tickets/Report/promoSummary.html create mode 100644 views/admin/tickets/Report/sales.html create mode 100644 views/admin/tickets/Report/salesCSV.html create mode 100644 views/admin/tickets/Report/salesDetail.html create mode 100644 views/admin/tickets/Report/salesDetailCSV.html create mode 100644 views/admin/tickets/Report/salesPackageTickets.html create mode 100755 views/admin/tickets/Report/salesPackageTicketsCSV.html create mode 100644 views/admin/tickets/Report/salesReportSelection.html create mode 100644 views/admin/tickets/Section/delete.html create mode 100644 views/admin/tickets/Section/detail.html create mode 100644 views/admin/tickets/Section/edit.html create mode 100644 views/admin/tickets/Section/list.html create mode 100644 views/admin/tickets/Sold/claim.html create mode 100644 views/admin/tickets/Sold/detail.html create mode 100644 views/admin/tickets/Sold/list.html create mode 100644 views/admin/tickets/Sold/selected.html create mode 100644 views/admin/tickets/Ticket/addGetMember.html create mode 100644 views/admin/tickets/Ticket/delete.html create mode 100644 views/admin/tickets/Ticket/detail.html create mode 100644 views/admin/tickets/Ticket/edit.html create mode 100644 views/admin/tickets/Ticket/inventory.html create mode 100644 views/admin/tickets/Ticket/inventoryNoCalendar.html create mode 100644 views/admin/tickets/Ticket/list.html create mode 100644 views/admin/tickets/Ticket/selected.html create mode 100644 views/admin/tickets/User/index.html create mode 100644 views/admin/tickets/User/loginForm.html create mode 100755 views/admin/tickets/VoucherCoupon/delete.html create mode 100644 views/admin/tickets/VoucherCoupon/detail.html create mode 100755 views/admin/tickets/VoucherCoupon/edit.html create mode 100644 views/admin/tickets/VoucherCoupon/list.html create mode 100755 views/admin/tickets/VoucherCoupon/selected.html create mode 100755 views/admin/tickets/VoucherCoupon/test.html create mode 100644 views/admin/tickets/Welcome/index.html create mode 100644 views/admin/tickets/index.html create mode 100644 views/admin/tickets/index.html.SAVE create mode 100755 views/front/FoundationStandAlone/Debug/index.html create mode 100755 views/front/FoundationStandAlone/Debug/start.html create mode 100755 views/front/FoundationStandAlone/Shop/PayPalApproved.html create mode 100755 views/front/FoundationStandAlone/Shop/PayPalFail.html create mode 100644 views/front/FoundationStandAlone/Shop/additionalInfo.html create mode 100755 views/front/FoundationStandAlone/Shop/cart.html create mode 100755 views/front/FoundationStandAlone/Shop/checkout.html create mode 100755 views/front/FoundationStandAlone/Shop/checkoutSuccess.html create mode 100755 views/front/FoundationStandAlone/Shop/paymentSummary.html create mode 100755 views/front/FoundationStandAlone/Shop/sectionSelect.html create mode 100644 views/front/FoundationStandAlone/Shop/start-COPY.html create mode 100755 views/front/FoundationStandAlone/Shop/start.html create mode 100755 views/front/FoundationStandAlone/Shop/ticketOpt.html create mode 100755 views/front/FoundationStandAlone/Shop/ticketSelect.html create mode 100755 views/front/FoundationStandAlone/foot.html create mode 100755 views/front/FoundationStandAlone/head.html create mode 100755 views/front/FoundationStandAlone/index.html create mode 100755 views/front/Gaslight/Debug/index.html create mode 100755 views/front/Gaslight/Debug/start.html create mode 100755 views/front/Gaslight/Shop/PayPalApproved.html create mode 100755 views/front/Gaslight/Shop/PayPalFail.html create mode 100644 views/front/Gaslight/Shop/additionalInfo.html create mode 100755 views/front/Gaslight/Shop/cart.html create mode 100755 views/front/Gaslight/Shop/checkout.html create mode 100755 views/front/Gaslight/Shop/checkoutSuccess.html create mode 100755 views/front/Gaslight/Shop/paymentSummary.html create mode 100755 views/front/Gaslight/Shop/sectionSelect.html create mode 100644 views/front/Gaslight/Shop/start-COPY.html create mode 100755 views/front/Gaslight/Shop/start.html create mode 100644 views/front/Gaslight/Shop/svn-commit.tmp create mode 100755 views/front/Gaslight/Shop/ticketOpt.html create mode 100755 views/front/Gaslight/Shop/ticketSelect.html create mode 100755 views/front/Gaslight/foot.html create mode 100755 views/front/Gaslight/head.html create mode 100755 views/front/Gaslight/index.html create mode 100755 views/front/MMM/Debug/index.html create mode 100755 views/front/MMM/Debug/start.html create mode 100755 views/front/MMM/Shop/PayPalApproved.html create mode 100755 views/front/MMM/Shop/PayPalFail.html create mode 100644 views/front/MMM/Shop/additionalInfo.html create mode 100755 views/front/MMM/Shop/cart.html create mode 100755 views/front/MMM/Shop/checkout.html create mode 100755 views/front/MMM/Shop/checkoutSuccess.html create mode 100755 views/front/MMM/Shop/paymentSummary.html create mode 100755 views/front/MMM/Shop/sectionSelect.html create mode 100644 views/front/MMM/Shop/start-COPY.html create mode 100755 views/front/MMM/Shop/start.html create mode 100644 views/front/MMM/Shop/svn-commit.tmp create mode 100755 views/front/MMM/Shop/ticketOpt.html create mode 100755 views/front/MMM/Shop/ticketSelect.html create mode 100755 views/front/MMM/foot.html create mode 100755 views/front/MMM/head.html create mode 100755 views/front/MMM/index.html create mode 100755 views/front/PointerBoat/Debug/index.html create mode 100755 views/front/PointerBoat/Debug/start.html create mode 100755 views/front/PointerBoat/Shop/PayPalApproved.html create mode 100755 views/front/PointerBoat/Shop/PayPalFail.html create mode 100644 views/front/PointerBoat/Shop/additionalInfo.html create mode 100755 views/front/PointerBoat/Shop/cart.html create mode 100755 views/front/PointerBoat/Shop/checkout.html create mode 100755 views/front/PointerBoat/Shop/checkoutSuccess.html create mode 100755 views/front/PointerBoat/Shop/paymentSummary.html create mode 100755 views/front/PointerBoat/Shop/sectionSelect.html create mode 100644 views/front/PointerBoat/Shop/start-COPY.html create mode 100755 views/front/PointerBoat/Shop/start.html create mode 100644 views/front/PointerBoat/Shop/svn-commit.tmp create mode 100755 views/front/PointerBoat/Shop/ticketOpt.html create mode 100755 views/front/PointerBoat/Shop/ticketSelect.html create mode 100755 views/front/PointerBoat/Shop_Backup/PayPalApproved.html create mode 100755 views/front/PointerBoat/Shop_Backup/PayPalFail.html create mode 100644 views/front/PointerBoat/Shop_Backup/additionalInfo.html create mode 100755 views/front/PointerBoat/Shop_Backup/cart.html create mode 100755 views/front/PointerBoat/Shop_Backup/checkout.html create mode 100755 views/front/PointerBoat/Shop_Backup/checkoutSuccess.html create mode 100755 views/front/PointerBoat/Shop_Backup/paymentSummary.html create mode 100755 views/front/PointerBoat/Shop_Backup/sectionSelect.html create mode 100644 views/front/PointerBoat/Shop_Backup/start-COPY.html create mode 100755 views/front/PointerBoat/Shop_Backup/start.html create mode 100644 views/front/PointerBoat/Shop_Backup/svn-commit.tmp create mode 100755 views/front/PointerBoat/Shop_Backup/ticketOpt.html create mode 100755 views/front/PointerBoat/Shop_Backup/ticketSelect.html create mode 100755 views/front/PointerBoat/foot.html create mode 100755 views/front/PointerBoat/head.html create mode 100755 views/front/PointerBoat/index.html create mode 100755 views/front/SaultSteMarie/Debug/index.html create mode 100755 views/front/SaultSteMarie/Debug/start.html create mode 100755 views/front/SaultSteMarie/Shop/PayPalApproved.html create mode 100755 views/front/SaultSteMarie/Shop/PayPalFail.html create mode 100644 views/front/SaultSteMarie/Shop/additionalInfo.html create mode 100755 views/front/SaultSteMarie/Shop/cart.html create mode 100755 views/front/SaultSteMarie/Shop/checkout.html create mode 100755 views/front/SaultSteMarie/Shop/checkoutSuccess.html create mode 100755 views/front/SaultSteMarie/Shop/paymentSummary.html create mode 100755 views/front/SaultSteMarie/Shop/sectionSelect.html create mode 100644 views/front/SaultSteMarie/Shop/start-COPY.html create mode 100755 views/front/SaultSteMarie/Shop/start.html create mode 100755 views/front/SaultSteMarie/Shop/ticketOpt.html create mode 100755 views/front/SaultSteMarie/Shop/ticketSelect.html create mode 100755 views/front/SaultSteMarie/foot.html create mode 100755 views/front/SaultSteMarie/head.html create mode 100755 views/front/SaultSteMarie/index.html create mode 100644 views/front/TicketsFoundation/Debug/index.html create mode 100644 views/front/TicketsFoundation/Debug/start.html create mode 100644 views/front/TicketsFoundation/Shop/Copy of cart.html create mode 100644 views/front/TicketsFoundation/Shop/PayPalApproved.html create mode 100644 views/front/TicketsFoundation/Shop/PayPalFail.html create mode 100644 views/front/TicketsFoundation/Shop/cart.html create mode 100644 views/front/TicketsFoundation/Shop/checkout.html create mode 100644 views/front/TicketsFoundation/Shop/checkoutSuccess.html create mode 100644 views/front/TicketsFoundation/Shop/paymentSummary.html create mode 100644 views/front/TicketsFoundation/Shop/sectionSelect.html create mode 100644 views/front/TicketsFoundation/Shop/start.html create mode 100644 views/front/TicketsFoundation/Shop/ticketOpt.html create mode 100644 views/front/TicketsFoundation/Shop/ticketSelect.html create mode 100644 views/front/TicketsFoundation/foot.html create mode 100644 views/front/TicketsFoundation/head.html create mode 100644 views/front/TicketsFoundation/index.html create mode 100644 views/front/tickets/Debug/index.html create mode 100644 views/front/tickets/Debug/start.html create mode 100644 views/front/tickets/Shop/PayPalApproved.html create mode 100644 views/front/tickets/Shop/PayPalFail.html create mode 100644 views/front/tickets/Shop/cart.html create mode 100644 views/front/tickets/Shop/checkout.html create mode 100644 views/front/tickets/Shop/checkoutSuccess.html create mode 100644 views/front/tickets/Shop/paymentSummary.html create mode 100644 views/front/tickets/Shop/sectionSelect.html create mode 100644 views/front/tickets/Shop/start.html create mode 100644 views/front/tickets/Shop/ticketOpt.html create mode 100644 views/front/tickets/Shop/ticketSelect.html create mode 100644 views/front/tickets/foot.html create mode 100644 views/front/tickets/head.html create mode 100644 views/front/tickets/index.html create mode 100644 web/admin/icons/calendar.png create mode 100644 web/admin/icons/information.png create mode 100644 web/admin/icons/page_edit.png create mode 100644 web/admin/tickets/documentation/VenueAdminGuide.pdf create mode 100644 web/admin/tickets/tickets.css create mode 100644 web/admin/tickets/tickets.js create mode 100755 web/front/FoundationStandAlone/EventManagement.css create mode 100755 web/front/FoundationStandAlone/EventManagement.js create mode 100755 web/front/FoundationStandAlone/assets/get_adobe_reader.png create mode 100755 web/front/FoundationStandAlone/assets/paypal_but6.gif create mode 100755 web/front/FoundationStandAlone/assets/pdficon_large.png create mode 100644 web/front/Gaslight/EventManagement.css create mode 100644 web/front/Gaslight/EventManagement.js create mode 100644 web/front/Gaslight/assets/paypal_but6.gif create mode 100644 web/front/MMM/EventManagement.css create mode 100644 web/front/MMM/EventManagement.js create mode 100644 web/front/MMM/assets/paypal_but6.gif create mode 100644 web/front/PointerBoat/EventManagement.css create mode 100644 web/front/PointerBoat/EventManagement.js create mode 100644 web/front/PointerBoat/assets/paypal_but6.gif create mode 100644 web/front/SaultSteMarie/EventManagement.css create mode 100644 web/front/SaultSteMarie/EventManagement.js create mode 100644 web/front/SaultSteMarie/assets/paypal_but6.gif create mode 100644 web/front/TicketsFoundation/EventManagement.css create mode 100644 web/front/TicketsFoundation/EventManagement.js create mode 100644 web/front/TicketsFoundation/assets/get_adobe_reader.png create mode 100644 web/front/TicketsFoundation/assets/paypal_but6.gif create mode 100644 web/front/TicketsFoundation/assets/pdficon_large.png create mode 100644 web/front/tickets/EventManagement.css create mode 100644 web/front/tickets/EventManagement.js create mode 100644 web/front/tickets/assets/paypal_but6.gif diff --git a/Notes/GaslightPages/SiteSample.html b/Notes/GaslightPages/SiteSample.html new file mode 100644 index 0000000..87f74c9 --- /dev/null +++ b/Notes/GaslightPages/SiteSample.html @@ -0,0 +1,20 @@ + + + + ticketing - Sample Site HTML wrapper for upload to Gaslight Media Systems + + + + {GLM} + + + + diff --git a/Notes/GaslightPages/TicketCart.html b/Notes/GaslightPages/TicketCart.html new file mode 100644 index 0000000..195291f --- /dev/null +++ b/Notes/GaslightPages/TicketCart.html @@ -0,0 +1,322 @@ + + + + + + + + +
+
+ +
+ +
+
Select another event
+
More tickets for this event
+
Purchase selected tickets
+
+ + +
Selected Events and Tickets
+ + +
(page intro goes here)
+ + +
+ +
Venue #1 Name
+ + +
+
(venue description text goes here)
+ +
+ + +
+ + +
+ +
Event #1 Name
+
+
(venue description text goes here)
+
+ + +
+
+
Quant
+
Section
+
Ticket
+
Price Each
+
Total
+
+
+
+
Section 1
+
Type 1
+
$25.00/each
+
$125.00
+
+
+
+
Section 2
+
Type 2
+
$25.00
+
$50.00
+
+
+
7
+
$175.00
+
+
+ +
+ + +
+ +
Event #2 Name
+
+
(venue description text goes here)
+
+ + +
+
+
Quant
+
Section
+
Ticket
+
Price Each
+
Total
+
+
+
+
Section 1
+
Type 1
+
$25.00/each
+
$125.00
+
+
+
+
Section 2
+
Type 2
+
$25.00
+
$50.00
+
+
+
7
+
$175.00
+
+
+ +
+ +
+ + +
+ +
+
+
Tickets
+
Venue Total
+
+
+
19
+
$250.00
+
+
+ +
+ +
+ + +
+ +
Venue #2 Name
+ + +
+
(venue description text goes here)
+ +
+ + +
+ + +
+ +
Event #1 Name
+
+
(venue description text goes here)
+
+ + +
+
+
Quant
+
Section
+
Ticket
+
Price Each
+
Total
+
+
+
+
Section 1
+
Type 1
+
$25.00/each
+
$125.00
+
+
+
+
Section 2
+
Type 2
+
$25.00
+
$50.00
+
+
+
7
+
$175.00
+
+
+ +
+ + +
+ +
Event #2 Name
+
+
(venue description text goes here)
+
+ + +
+
+
Quant
+
Section
+
Ticket
+
Price Each
+
Total
+
+
+
+
Section 1
+
Type 1
+
$25.00/each
+
$125.00
+
+
+
+
Section 2
+
Type 2
+
$25.00
+
$50.00
+
+
+
7
+
$175.00
+
+
+ +
+ +
+ + +
+ +
+
+
Tickets
+
Venue Total
+
+
+
19
+
$250.00
+
+
+ +
+ +
+ + +
+ +
Cart Summary
+ +
+
+
Venues
+
Tickets
+
Grand Total
+
+
+
2
+
19
+
$250.00
+
+
+ +
+ + +
+
+ (purchase and return policies go here) +
+
Proceed to Checkout
+
+ +
+ +
+
+ + + + diff --git a/Notes/GaslightPages/TicketCheckout.html b/Notes/GaslightPages/TicketCheckout.html new file mode 100644 index 0000000..f82d8b1 --- /dev/null +++ b/Notes/GaslightPages/TicketCheckout.html @@ -0,0 +1,489 @@ + + + + + + + + +
+
+ + +
+
Select another event
+
More tickets for this event
+
Return to selcted tickets
+
+ + +
+
Contact Information
+ + +
+
First Name
+
Last Name
+
Address
+
 
+
City
+
+
State
+
+ +
+
+
+
Country
+
+ +
+
+
ZIP/Postal code
+
Phone
+
E-Mail
+
Verify E-Mail
+
+
OK to Sent E-Mail?
+
+ + +
+
+
+ +
+ + +
+ +
Venue #1 Name
+ + +
+
(venue description text goes here)
+ +
+ + +
+ + +
+ +
Event #1 Name
+
+
(venue description text goes here)
+
+ + +
+
+
Quant
+
Section
+
Ticket
+
Price Each
+
Total
+
+
+
5
+
Section 1
+
Type 1
+
$25.00/each
+
$125.00
+
+
+
2
+
Section 2
+
Type 2
+
$25.00
+
$50.00
+
+
+
7
+
$175.00
+
+
+ +
+ + +
+ +
Event #2 Name
+
+
(venue description text goes here)
+
+ + +
+
+
Quant
+
Section
+
Ticket
+
Price Each
+
Total
+
+
+
5
+
Section 1
+
Type 1
+
$25.00/each
+
$125.00
+
+
+
2
+
Section 2
+
Type 2
+
$25.00
+
$50.00
+
+
+
7
+
$175.00
+
+
+ +
+ +
+ + +
+ +
+
+
Tickets
+
Venue Total
+
+
+
19
+
$250.00
+
+
+ +
+ + +
+ +
Payment for Venue #1 Name
+ + +
+
+
Card Type
+
+ +
+
+
Name on Card
+
Card #
+
+
Expiration
+
+ Month + Year +
+
+ +
Security #
+
+
+ The Security # is the three or four digit number on the signature side of your credit card. + American Express cards may have this number on the front of the card. +
+
+
+ +
+ +
+ + +
+
Contact Information
+ + +
+
First Name
+
Last Name
+
Address
+
 
+
City
+
+
State
+
+ +
+
+
+
Country
+
+ +
+
+
ZIP/Postal code
+
Phone
+
E-Mail
+
Verify E-Mail
+
+
OK to Sent E-Mail?
+
Please send information on activities and offers.
+
+
+ +
+ + +
+ +
Venue #2 Name
+ + +
+
(venue description text goes here)
+ +
+ + +
+ + +
+ +
Event #1 Name
+
+
(venue description text goes here)
+
+ + +
+
+
Quant
+
Section
+
Ticket
+
Price Each
+
Total
+
+
+
5
+
Section 1
+
Type 1
+
$25.00/each
+
$125.00
+
+
+
2
+
Section 2
+
Type 2
+
$25.00
+
$50.00
+
+
+
7
+
$175.00
+
+
+ +
+ + +
+ +
Event #2 Name
+
+
(venue description text goes here)
+
+ + +
+
+
Quant
+
Section
+
Ticket
+
Price Each
+
Total
+
+
+
5
+
Section 1
+
Type 1
+
$25.00/each
+
$125.00
+
+
+
2
+
Section 2
+
Type 2
+
$25.00
+
$50.00
+
+
+
7
+
$175.00
+
+
+ +
+ + +
+ +
+
+
Tickets
+
Venue Total
+
+
+
19
+
$250.00
+
+
+ +
+ +
+ + +
+ +
Payment for Venue #2 Name
+ + +
+
+
Card Type
+
+ +
+
+
Name on Card
+
Card #
+
+
Expiration
+
+ Month + Year +
+
+ +
Security #
+
+
+ The Security # is the three or four digit number on the signature side of your credit card. + American Express cards may have this number on the front of the card. +
+
+
+ +
+ +
+ + +
+ +
Purchase Summary
+ +
+
+
Venues
+
Tickets
+
Grand Total
+
+
+
2
+
19
+
$250.00
+
+
+ +
+ + +
+
Complete Purchase
+
+ (purchase and return policies go here) +
+
Purchase Selected Tickets
+
+ +
+
+ + + + diff --git a/Notes/GaslightPages/TicketSelection.html b/Notes/GaslightPages/TicketSelection.html new file mode 100644 index 0000000..951c615 --- /dev/null +++ b/Notes/GaslightPages/TicketSelection.html @@ -0,0 +1,327 @@ + + + + + + + + + + + + + +
+
+ + +
+
Select another event
+
Review selected tickets
+
+ + +
+ +
+
Event Name
+
+ (event description text goes here - this might include some formatting from the ckeditor input) +
+
+ +
+
Select desired date:
+
+
+ +
+ + +
+ +
+
Venue Name
+
(venue description text goes here)
+ + + + +
+ (This area will contain address and optionally a Google map, parking information, etc.) + +
+ +
+ (other detail might go here - things like credit cards accepted) +
+ +
+ + + +
+ + +
+ + + + +
+ +
Section #1 Name
+
+ (section information goes here) +
+ + +
Select
+ + +
+ + + + +
+ + +
Ticket Type #1 Name
+
+ (ticket description and other info goes here) +
+ +
+
50 seats available
+
$25.00/each
+
+
+ +
+ + +
+ + +
Ticket Type #2 Name
+
+ (ticket description and other info goes here) +
+ +
+
50 seats available
+
$25.00/each
+
+
+ +
+ + +
+ + +
Ticket Type #3 Name
+
+ (ticket description and other info goes here) +
+ +
+
50 seats available
+
$25.00/each
+
+
+ +
+ +
+ +
+ + +
+ +
Section #2 Name
+
+ (section information goes here) +
+ + +
Select
+ + +
+ + + + +
+ + +
Ticket Type #1 Name
+
+ (ticket description and other info goes here) +
+ +
+
50 seats available
+
$25.00/each
+
+
+ +
+ + +
+ + +
Ticket Type #2 Name
+
+ (ticket description and other info goes here) +
+ +
+
50 seats available
+
$25.00/each
+
+
+ +
+ + +
+ + +
Ticket Type #3 Name
+
+ (ticket description and other info goes here) +
+ +
+
50 seats available
+
$25.00/each
+
+
+ +
+ +
+ +
+ + +
(total number of tickets and total costs go here)
+ + + +
+ +
(purchase and return policies go here)
+ +
Add to Cart
+ + +
+
+ + + + diff --git a/Notes/GaslightPages/css/main.css b/Notes/GaslightPages/css/main.css new file mode 100644 index 0000000..eaabeaa --- /dev/null +++ b/Notes/GaslightPages/css/main.css @@ -0,0 +1,695 @@ +@import + url(http://fonts.googleapis.com/css?family=Source+Sans+Pro:200,400,600,900,400italic) + ; /* normalize.css v1.1.1 | MIT License | git.io/normalize */ +article,aside,details,figcaption,figure,footer,header,hgroup,main,nav,section,summary + { + display: block +} + +audio,canvas,video { + display: inline-block; + *display: inline; + *zoom: 1 +} + +audio:not ([controls] ){ + display: none; + height: 0 +} + +[hidden] { + display: none +} + +html { + background: #fff; + color: #000; + font-size: 100%; + -webkit-text-size-adjust: 100%; + -ms-text-size-adjust: 100% +} + +html,button,input,select,textarea { + font-family: sans-serif +} + +body { + margin: 0 +} + +a:focus { + outline: thin dotted +} + +a:active,a:hover { + outline: 0 +} + +h1 { + font-size: 2em; + margin: 0.67em 0 +} + +h2 { + font-size: 1.5em; + margin: 0.83em 0 +} + +h3 { + font-size: 1.17em; + margin: 1em 0 +} + +h4 { + font-size: 1em; + margin: 1.33em 0 +} + +h5 { + font-size: 0.83em; + margin: 1.67em 0 +} + +h6 { + font-size: 0.67em; + margin: 2.33em 0 +} + +abbr[title] { + border-bottom: 1px dotted +} + +b,strong { + font-weight: bold +} + +blockquote { + margin: 1em 40px +} + +dfn { + font-style: italic +} + +hr { + -moz-box-sizing: content-box; + box-sizing: content-box; + height: 0 +} + +mark { + background: #ff0; + color: #000 +} + +p,pre { + margin: 1em 0 +} + +code,kbd,pre,samp { + font-family: monospace, serif; + _font-family: "courier new", monospace; + font-size: 1em +} + +pre { + white-space: pre; + white-space: pre-wrap; + word-wrap: break-word +} + +q { + quotes: none +} + +q:before,q:after { + content: ''; + content: none +} + +small { + font-size: 80% +} + +sub,sup { + font-size: 75%; + line-height: 0; + position: relative; + vertical-align: baseline +} + +sup { + top: -0.5em +} + +sub { + bottom: -0.25em +} + +dl,menu,ol,ul { + margin: 1em 0 +} + +dd { + margin: 0 0 0 40px +} + +menu,ol,ul { + padding: 0 0 0 40px +} + +nav ul,nav ol { + list-style: none; + list-style-image: none +} + +img { + border: 0; + -ms-interpolation-mode: bicubic +} + +svg:not (:root ){ + overflow: hidden +} + +figure { + margin: 0 +} + +form { + margin: 0 +} + +fieldset { + border: 1px solid silver; + margin: 0 2px; + padding: 0.35em 0.625em 0.75em +} + +legend { + border: 0; + padding: 0; + white-space: normal; + *margin-left: -7px +} + +button,input,select,textarea { + font-size: 100%; + margin: 0; + vertical-align: baseline; + *vertical-align: middle +} + +button,input { + line-height: normal +} + +button,select { + text-transform: none +} + +button,html input[type="button"],input[type="reset"],input[type="submit"] + { + -webkit-appearance: button; + cursor: pointer; + *overflow: visible +} + +button[disabled],html input[disabled] { + cursor: default +} + +input[type="checkbox"],input[type="radio"] { + box-sizing: border-box; + padding: 0; + *height: 13px; + *width: 13px +} + +input[type="search"] { + -webkit-appearance: textfield; + -moz-box-sizing: content-box; + -webkit-box-sizing: content-box; + box-sizing: content-box +} + +input[type="search"]::-webkit-search-cancel-button,input[type="search"]::-webkit-search-decoration + { + -webkit-appearance: none +} + +button::-moz-focus-inner,input::-moz-focus-inner { + border: 0; + padding: 0 +} + +textarea { + overflow: auto; + vertical-align: top +} + +table { + border-collapse: collapse; + border-spacing: 0 +} + +html { + -webkit-font-smoothing: antialiased +} + +body { + font-family: "Source Sans Pro", sans-serif; + color: #3d3d3d; + font-style: normal; + line-height: 120% +} + +#GLMpageTitle { + font-size: 1.2em; + font-weight: 600; + line-height: 125% +} + +#GLMpageIntro { + font-size: 0.8em; + margin: 0 0 0.6em 0 +} + +.glmSection .glmsectionName { + margin: 0 +} + +#GLMeventName,#GLMvenueName,.glmCartBlockTitle,.glmCartEventName,.glmCartPaymentTitle + { + font-size: 1.6em; + font-weight: 600; + line-height: 125% +} + +.glmsectionName { + font-size: 1.45em; + font-weight: 600; + margin: 30px 0 0 0 +} + +#GLMeventDescr,#GLMvenueDescr,.glmCartVenueDescr,.glmCartEventDescr { + font-size: 0.8em; + margin: 0 0 0.75em 0 +} + +.glmCartVenueDescr,.glmCartEventDescr { + margin: 0 0 15px 0 +} + +.glmCartHeader:after,.glmCartTicket:after,.glmCartTotal:after { + content: ""; + display: table; + clear: both +} + +.glmCartHeader>* { + float: left; + width: 20%; + font-weight: 600 +} + +.glmCartHeader>*:last-child { + text-align: right +} + +.glmCartTicket>* { + width: 20%; + float: left +} + +.glmCartTicket>*:last-child { + text-align: right +} + +.glmCartTotal>* { + width: 50%; + float: left +} + +.glmCartTotal>*:last-child { + text-align: right +} + +.summary .glmCartTotal>*,.summary .glmCartHeader>* { + width: 33.3333% +} + +.glmCartFormInput label { + display: inline-block +} + +.glmCartEvent .glmCartTotal { + background: #f5f5f5; + margin-top: 7px; + padding: 7px 0; + border-top: 1px solid #e3e3e3 +} + +.glmCartVenueTotal .glmCartHeader>*,.glmCartVenueTotal .glmCartTotal>* { + width: 50%; + font-size: 1.25em; + text-align: center +} + +.glmCartVenueTotal .glmCartTotal>* { + float: left +} + +.glmCartTotal { + margin: 8px 0 0 0; + font-weight: 200; + font-size: 1.75em +} + +.glmCartBlock>.glmCartBlockTitle { + margin: 0 +} + +@media screen and (max-width: 480px) { + .glmCartTable { + font-size: 80% + } +} + +* { + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box +} + +img { + max-width: 100%; + height: auto; + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + -ms-border-radius: 6px; + -o-border-radius: 6px; + border-radius: 6px +} + +#GLMcontent { + padding: 0; + max-width: 500px; + margin: 0 auto +} + +#GLMcontent>* { + padding: 0 15px +} + +#GLMcontent>*.glmCartBlock { + padding: 0 15px 15px 15px +} + +#GLMevent,#GLMvenue { + max-width: 500px; + margin: 0 auto 1em auto +} + +#GLMnavigation,#GLMaddToCart { + margin: 0 0 15px 0; + padding: 0; + border: 1px solid #e3e3e3; + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + -ms-border-radius: 6px; + -o-border-radius: 6px; + border-radius: 6px; + text-align: center; + font-weight: 600; + font-shadow: 0 1px #fff; + font-size: 0.85em; + background: #fcfcfc; + -webkit-background-clip: padding; + -moz-background-clip: padding; + background-clip: padding-box +} + +#GLMnavigation:after,#GLMaddToCart:after { + content: ""; + display: table; + clear: both +} + +.glmNavItem { + float: left; + padding: 10px; + margin: 0; + width: 50%; + border-left: 1px solid #e3e3e3 +} + +.glmNavItem:first-of-type { + border-left: none +} + +#GLMcheckout .glmNavItem,#GLMticketCart .glmNavItem { + width: 33.3333% +} + +.glmCartTable input[type="number"] { + width: 80% +} + +#GLMeventDates,#GLMvenueLocation,#GLMvenueDetail,#GLMvenueSectionMap { + margin: 0 0 15px 0 +} + +.glmPrompt { + font-weight: 600; + font-size: 1.1em +} + +.glmCartFormLine { + margin: 0 0 10px 0 +} + +.glmCartFormLine input { + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + -ms-border-radius: 3px; + -o-border-radius: 3px; + border-radius: 3px +} + +.glmCartFormPrompt { + font-weight: 600; + font-size: 1.1em +} + +.glmTicketType,.glmCartForm,.glmCartEvent,.glmCartBlock,#GLMvenue,.glmSection,#GLMevent,#GLMvenueLocation + { + margin: 0 0 15px 0; + padding: 15px; + border: 1px solid #e3e3e3; + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + -ms-border-radius: 6px; + -o-border-radius: 6px; + border-radius: 6px; + -webkit-box-shadow: 0 2px #f2f2f2; + -moz-box-shadow: 0 2px #f2f2f2; + box-shadow: 0 2px #f2f2f2 +} + +.glmTicketType img,.glmCartForm img,.glmCartEvent img,.glmCartBlock img,#GLMvenue img,.glmSection img,#GLMevent img,#GLMvenueLocation img + { + width: 100%; + margin: 0 0 15px 0 +} + +.glmTicketDescr { + font-size: 0.85em +} + +.glmTicketAvailable { + margin: 5px 0; + font-weight: 600 +} + +.glmSectionTickets { + margin: 15px 0 +} + +.glmTicketName { + font-size: 1.35em; + font-weight: 600 +} + +.glmSectionSelector { + border: 1px solid #e3e3e3; + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + -ms-border-radius: 6px; + -o-border-radius: 6px; + border-radius: 6px; + cursor: pointer; + background-color: #f8f8f8; + padding: 8px 15px; + margin: 5px 0; + font-size: 1.15em; + font-weight: 600; + display: inline-block; + font-shadow: 0 1px #fff +} + +.glmSectionSelector:active { + -webkit-box-shadow: inset 0 0 8px #dbdbdb; + -moz-box-shadow: inset 0 0 8px #dbdbdb; + box-shadow: inset 0 0 8px #dbdbdb +} + +#GLMticketsSummary { + font-weight: 600; + font-size: 1.35em; + margin-top: 30px +} + +#GLMpolicy { + font-size: 0.85em; + font-style: italic +} + +.glmTicketPrice { + font-weight: 600; + margin: 15px 0 5px 0; + font-size: 1.25em +} + +.glmCartForm { + margin: 10px 0 0 +} + +.glmCartPayment { + margin: 45px 0 0 0 +} + +input { + width: 100%; + padding: 5px 7px; + outline: none; + font-weight: 600; + font-size: 1em; + font-family: "Source Sans Pro", sans-serif; + color: #3d3d3d; + background: #fafafa; + border: 1px solid #d4d4d4; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + -ms-border-radius: 3px; + -o-border-radius: 3px; + border-radius: 3px +} + +#GLMaddToCart,#GLMpurchase,#GLMcheckoutBtn { + padding: 15px; + margin: 15px 0 0 0; + color: white; + font-size: 1.5em; + text-shadow: 0 1px #4cae3c; + text-align: center; + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + -ms-border-radius: 6px; + -o-border-radius: 6px; + border-radius: 6px; + border: 1px solid #4cae3c; + -webkit-background-clip: padding; + -moz-background-clip: padding; + background-clip: padding-box; + background-color: #6ace3a; + -webkit-box-shadow: 0 1px 4px rgba(16, 16, 17, 0.08), inset 0 1px 0 + rgba(255, 255, 255, 0.45); + -moz-box-shadow: 0 1px 4px rgba(16, 16, 17, 0.08), inset 0 1px 0 + rgba(255, 255, 255, 0.45); + box-shadow: 0 1px 4px rgba(16, 16, 17, 0.08), inset 0 1px 0 + rgba(255, 255, 255, 0.45); + cursor: pointer +} + +#GLMaddToCart:active,#GLMpurchase:active,#GLMcheckoutBtn:active { + border: 1px solid #39942a; + background-color: #4eb61b; + -webkit-box-shadow: 0 1px 4px rgba(16, 16, 17, 0.08), inset 0 0 15px + rgba(0, 0, 0, 0.3); + -moz-box-shadow: 0 1px 4px rgba(16, 16, 17, 0.08), inset 0 0 15px + rgba(0, 0, 0, 0.3); + box-shadow: 0 1px 4px rgba(16, 16, 17, 0.08), inset 0 0 15px + rgba(0, 0, 0, 0.3) +} + +body { + -webkit-animation-fill-mode: both; + -moz-animation-fill-mode: both; + -ms-animation-fill-mode: both; + -o-animation-fill-mode: both; + animation-fill-mode: both; + -webkit-animation-duration: 1s; + -moz-animation-duration: 1s; + -ms-animation-duration: 1s; + -o-animation-duration: 1s; + animation-duration: 1s +} + +@ +-webkit-keyframes fadeIn { 0%{ + opacity: 0 +} + +100%{ +opacity +: +1 +} +} +@ +-moz-keyframes fadeIn { 0%{ + opacity: 0 +} + +100%{ +opacity +: +1 +} +} +@ +-o-keyframes fadeIn { 0%{ + opacity: 0 +} + +100%{ +opacity +: +1 +} +} +@ +keyframes fadeIn { 0%{ + opacity: 0 +} + +100%{ +opacity +: +1 +} +} +body { + -webkit-animation-name: fadeIn; + -moz-animation-name: fadeIn; + -o-animation-name: fadeIn; + animation-name: fadeIn +} + +@media screen and (max-width: 480px) { + #GLMcontent { + height: 300px; + overflow: auto + } +} \ No newline at end of file diff --git a/Notes/Sites_Using.txt b/Notes/Sites_Using.txt new file mode 100644 index 0000000..1ff585a --- /dev/null +++ b/Notes/Sites_Using.txt @@ -0,0 +1,13 @@ +Sites using this common application +----------------------------------- + +Last updated: 06/12/18 + +Site Version Server Database DB Server web/custom directory +--------------------------------------- ------- ------- ----------------------- ----------- -------------------------- +tickets.gaslightmedia.com V3 WS6 gaslight_tickets DS4 +tickets.michiganmaritimemuseum.org V3 WS6 mmm_tickets DS4 +www.mackinacferry.com V3 WS6 mackinacferry DS4 +www.saultstemarie.com V3 WS6 saultstemarie DS4 +www.soolocks.com V3 WS6 soolocks DS4 + diff --git a/classes/EasyPassword.php b/classes/EasyPassword.php new file mode 100644 index 0000000..7194dcc --- /dev/null +++ b/classes/EasyPassword.php @@ -0,0 +1,42 @@ + + * Released under the terms of the GNU General Public License + * Based in part on Script released by: Jochen Kupperschmidt + * + * This is a highly modified version of this password generator for this application only. + * For original code please refer to original author. + */ + + +class EasyPassword +{ + + // Get a random dictionary word from a text file + function dictionaryWord() { + $path = 'EasyPassword.words'; + $fileload = @file($path); + $i = count($fileload)-1; + $random = rtrim($fileload[rand(0,$i)]); + return $random; + } + + // This is the function to produce the password + function generateEasyPassword() + { + $word1 = $this->dictionaryWord(); + $numb = rand(1, 9); // Generate specified amount of numbers + $word2 = $this->dictionaryWord(); + + $keys = array ($word1,$numb,$word2); // Place password components in an array + $rand_keys = array_rand($keys,3); // Randomize the 3 password components + return $keys[$rand_keys[0]].$keys[$rand_keys[1]].$keys[$rand_keys[2]]; // Return the resulting password + } + + +} + + +?> \ No newline at end of file diff --git a/classes/EasyPassword.words b/classes/EasyPassword.words new file mode 100644 index 0000000..ed13097 --- /dev/null +++ b/classes/EasyPassword.words @@ -0,0 +1,828 @@ +able +ABLE +about +account +acid +across +act +addition +after +again +against +agreement +air +all +almost +among +amount +amusement +and +angle +angry +animal +answer +ant +any +apparatus +apple +approval +arch +argument +arm +army +art +as +at +attack +attempt +attention +authority +automatic +awake +baby +back +bad +bag +balance +ball +band +base +basin +basket +bath +be +beautiful +because +bed +bee +before +behaviour +belief +bell +bent +berry +between +bird +birth +bit +black +blade +blood +blow +blue +board +boat +body +boiling +book +boot +bottle +box +boy +brain +brake +branch +brass +bread +breath +brick +bridge +bright +broken +brother +brown +brush +bucket +building +bulb +burn +burst +business +butter +button +by +cake +camera +canvas +card +care +carriage +cart +cat +cause +certain +chain +chalk +chance +change +cheap +cheese +chemical +chest +chief +chin +church +circle +clean +clear +clock +cloth +cloud +coal +coat +cold +collar +colour +comb +come +comfort +committee +common +company +comparison +complete +complex +condition +connection +conscious +control +cook +copper +copy +cord +cork +cotton +cough +country +cover +cow +crack +credit +crime +cruel +crush +cry +cup +cup +current +curtain +curve +cushion +damage +danger +dark +daughter +day +dead +dear +death +debt +decision +deep +degree +delicate +dependent +design +desire +destruction +detail +development +different +digestion +direction +dirty +discovery +discussion +disease +disgust +distance +division +do +dog +door +doubt +down +drain +drawer +dress +drink +driving +drop +dry +dust +ear +early +earth +east +edge +education +effect +egg +elastic +electric +end +engine +enough +equal +error +even +event +ever +every +example +exchange +existence +expansion +experience +expert +eye +face +fact +fall +false +family +far +farm +fat +father +fear +feather +feeble +feeling +female +fertile +fiction +field +fight +finger +fire +first +fish +fixed +flag +flame +flat +flight +floor +flower +fly +fold +food +foolish +foot +for +force +fork +form +forward +fowl +frame +free +frequent +friend +from +front +fruit +full +future +garden +general +get +girl +give +glass +glove +go +goat +gold +good +government +grain +grass +great +green +grey +grip +group +growth +guide +gun +hair +hammer +hand +hanging +happy +harbour +hard +harmony +hat +hate +have +he +healthy +hear +hearing +heart +heat +help +high +history +hole +hollow +hook +hope +horn +horse +hospital +hour +house +how +humour +ice +idea +if +ill +important +impulse +in +increase +industry +ink +insect +instrument +insurance +interest +invention +iron +island +jelly +jewel +join +journey +judge +jump +keep +kettle +key +kick +kind +kiss +knee +knife +knot +knowledge +land +language +last +late +laugh +law +lead +leaf +learning +left +leg +let +letter +level +library +lift +light +like +limit +line +linen +lip +liquid +list +little +living +lock +long +look +loose +loss +loud +love +low +machine +make +male +man +manager +map +mark +market +married +mass +match +material +may +meal +measure +meat +medical +meeting +memory +metal +middle +military +milk +mind +mine +minute +mist +mixed +money +monkey +month +moon +morning +mother +motion +mountain +mouth +move +much +muscle +music +nail +name +narrow +nation +natural +near +necessary +neck +need +needle +nerve +net +new +news +night +no +noise +normal +north +nose +not +note +now +number +nut +of +off +offer +office +oil +old +on +only +open +operation +opinion +opposite +or +orange +order +ornament +other +out +oven +over +owner +page +pain +paint +paper +parallel +parcel +part +past +paste +payment +peace +pen +pencil +person +physical +picture +pig +pin +pipe +place +plane +plant +plate +play +please +pleasure +plough +pocket +point +poison +polish +political +poor +porter +position +possible +pot +potato +powder +power +present +price +print +prison +private +probable +process +produce +profit +property +prose +protest +public +pull +pump +purpose +push +put +quality +question +quick +quiet +quite +rail +rain +range +rat +rate +ray +reaction +reading +ready +reason +receipt +record +red +regret +regular +relation +request +respect +rest +reward +rhythm +rice +right +ring +river +road +rod +roll +roof +room +root +rough +round +rub +rule +run +safe +sail +salt +same +sand +say +scale +school +science +scissors +screw +sea +seat +second +secret +see +seed +seem +self +send +sense +separate +serious +servant +sex +shade +shake +shame +sharp +sheep +shelf +ship +shirt +shock +shoe +short +shut +side +sign +silk +silver +simple +sister +size +skin +skirt +sky +sleep +slip +slope +slow +small +smash +smell +smile +smoke +smooth +snake +sneeze +snow +so +soap +society +sock +soft +solid +some + +son +song +sort +sound +soup +south +space +spade +special +sponge +spoon +spring +square +stage +stamp +star +start +statement +station +steam +steel +stem +step +stick +sticky +stiff +still +stitch +stocking +stomach +stone +stop +store +story +straight +strange +street +stretch +strong +structure +such +sudden +sugar +summer +sun +support +surprise +sweet +swim +system +table +tail +take +talk +tall +taste +tax +teaching +tendency +test +than +that +the +then +theory +there +thick +thin +thing +this +thought +thread +throat +through +through +thumb +thunder +ticket +tight +till +time +tin +tired +to +toe +together +tomorrow +tongue +tooth +top +touch +town +trade +train +transport +tray +tree +trick +trouble +trousers +true +turn +twist +umbrella +under +unit +up +use +value +verse +very +vessel +view +violent +voice +waiting +walk +wall +war +warm +wash +waste +watch +water +wave +wax +way +weather +week +weight +well +west +wet +wheel +when +where +while +whip +whistle +white +who +why +wide +will +wind +window +wine +wing +winter +wire +wise +with +woman +wood +wool +word +work +worm +wound +writing +wrong +year +yellow +yes +yesterday +you +young diff --git a/classes/GeoCalculations.php b/classes/GeoCalculations.php new file mode 100644 index 0000000..bd43265 --- /dev/null +++ b/classes/GeoCalculations.php @@ -0,0 +1,253 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: GeoCalculations.php,v 1.0 2011/01/25 19:31:47 cscott Exp $ + * @link http://housing.gaslightmedia.com/admin/ + */ + +/** + * Geographic Calculations Support + * + * PHP version 5 + * + * @category Support_Services + * @package EventManagement + * @author Chuck Scott + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: GeoCalculations.php,v 1.0 2011/01/25 19:31:47 cscott Exp $ + * @link http://housing.gaslightmedia.com/admin/ + */ +class EventManagementGeoCalculations +{ + /** + * Database Object + * @var $dbh + * @access public + */ + protected $dbh; + + /** + * Constructor + * + * @param object $d database connection + * + * @return void + * @access public + */ + public function __construct($dbh) + { + $this->dbh = $dbh; + } + + + /* + * Get distance from event for an array of member locations - $sort = true to sort by distance + * + * This method caches the results in the event_prop_dist table and will refer first to that table. + * If there's no entry in that table, the method will get the distance information from Google + * and add it to the cache. + * + */ + function getMemberEventDistance( + $eventID, $members, + $member_lat_field = 'lat', $member_lon_field = 'lon', + $distance_field = 'distance', + $duration_field = 'duration', + $member_id_field = 'id', + $sort = false + ) + { + + // Check for valid Event ID and members table + if (($eventID-0) == 0 || !is_array($members) || count($members) == 0) { + return false; + } + + // Get Event location + $sql = "SELECT name, event_code, lat, lon + FROM eventmgt.event + WHERE id = $eventID;"; + $stmt = $this->dbh->prepare($sql); + $stmt->execute(); + $event_data = $stmt->fetch(PDO::FETCH_ASSOC); + + // Did we get event data + if (!event_data) { + return false; + } + + // Get numeric lat and lon and check if they exist (assume no 0 valuse) + $event_lat = ($event_data['lat'] - 0); + $event_lon = ($event_data['lon'] - 0); + if ($event_lat == 0 || $event_lon == 0) { + return false; + } + + $distances = array(); + $over_query_limit = false; + + while (list($k, $m) = each($members)) { + + $members[$k][$distance_field] = false; + $members[$k][$duration_field] = false; + $members[$k]['member_id_sort_field'] = $m[$member_id_field]; + + // Initialize distance response array entry for this member + $distances[$m[$member_id_field]] = array( + 'id' => $m[$member_id_field], + 'distance' => false + ); + + // If we have lat/lon for this member + $have_latlon = false; + if ($event_lat != 0 && $event_lon != 0 && $m[$member_lat_field] != 0 && $m[$member_lon_field] != 0) { + + $have_latlon = 'YES'; + $have_distance = 'NO'; + $distance = false; + $duration = false; + + // Check for entry in distance cache table + $sql = " + SELECT * + FROM eventmgt.event_prop_dist + WHERE event = $eventID + AND event_lat = $event_lat + AND event_lon = $event_lon + AND member = ".$m[$member_id_field]." + AND memb_lat = ".$m[$member_lat_field]." + AND memb_lon = ".$m[$member_lon_field]." + "; + $stmt = $this->dbh->prepare($sql); + $stmt->execute(); + $dist_data = $stmt->fetch(PDO::FETCH_ASSOC); + if ($dist_data != false && count($dist_data) > 0) { + $distance = $dist_data['distance']; + $duration = $dist_data['duration']; + $have_distance = 'YES'; + } + + // If we don't have distance from the cache and we're not over limit + if ($have_distance == 'NO' && !$over_query_limit) { + + // Request distance from event from Google + $map_request = 'http://maps.googleapis.com/maps/api/directions/xml?' + .'origin='.$m[$member_lat_field].','.$m[$member_lon_field] + .'&destination='.$event_lat + .','.$event_lon + .'&sensor=false&mode=driving'; + + $ch = curl_init(); + $curlOptions = array( + CURLOPT_URL => $map_request, + CURLOPT_HEADER => 0, + CURLOPT_RETURNTRANSFER => 1, + CURLOPT_FAILONERROR => 1 + ); + curl_setopt_array($ch, $curlOptions); + $response = curl_exec($ch); + curl_close($ch); + + if (strstr($response, 'OVER_QUERY_LIMIT')) { + $over_query_limit = true; + } else { + + // if we got a distance and time, then use that + if ($response) { + + $xml = new SimpleXMLElement($response); + if ($xml) { + $summary = addslashes((string) $xml->route[0]->summary); + $distance = (string) $xml->route[0]->leg[0]->distance->text; + $duration = (string) $xml->route[0]->leg[0]->duration->text; + $start_addr = addslashes((string) $xml->route[0]->leg[0]->start_address); + $end_addr = addslashes((string) $xml->route[0]->leg[0]->end_address); + $have_distance = 'YES'; + + // Delete any previous entry for this member/event + $sql = " + DELETE FROM eventmgt.event_prop_dist + WHERE event = $eventID + AND member = ".$m[$member_id_field]." + ;"; + $stmt = $this->dbh->prepare($sql); + $stmt->execute(); + + // Add this result to the event_prop_dist table + $sql = " + INSERT INTO eventmgt.event_prop_dist + ( + event, event_lat, event_lon, + member, memb_lat, memb_lon, + summary, start_addr, end_addr, + distance, duration + ) + VALUES + ( + $eventID, $event_lat, $event_lon, + ".$m[$member_id_field].", ".$m[$member_lat_field].", ".$m[$member_lon_field].", + '$summary', '$start_addr', '$end_addr', + '$distance', '$duration' + ); + "; + $stmt = $this->dbh->prepare($sql); + $stmt->execute(); + + } // If the response contained XML + } // If we got a response from Google + } // If we're not over limit + + } // If we don't have chached distance + } // If we have lat/lon + + $members[$k][$distance_field] = $distance; + $members[$k]['geo_distance_value'] = (0.0 + $distance); + $members[$k][$duration_field] = $duration; + $members[$k]['geo_duration_value'] = (0.0 + $duration); + + } // For each member + + if ($sort) { + + + uasort($members, 'distCmp'); + + } + + return $members; + } +} + + +// Comparison function to sort by distance - Needs to be declared outside of the class (Yuck!) +function distCmp($a, $b) { + + $adist = $a['geo_distance_value']; + $bdist = $b['geo_distance_value']; + + if ($adist == $bdist) { + + // distance is the same, so sub-sort by member_id to keep things consistent + $amemb = $a['member_id_sort_field']; + $bmemb = $b['member_id_sort_field']; + + if ($amemb == $bmemb) { + return 0; + } + + return ($amemb < $bmemb) ? -1 : 1; + } + return ($adist < $bdist) ? -1 : 1; +} + + + +?> \ No newline at end of file diff --git a/classes/data/Reports/dataEventReport.php b/classes/data/Reports/dataEventReport.php new file mode 100644 index 0000000..4eb627f --- /dev/null +++ b/classes/data/Reports/dataEventReport.php @@ -0,0 +1,290 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: Reports/dataEventReport.php,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +/**** + * + * NOTE: This is a data class for form input validation only. + * There is no database table assoicated with this class! + * + ****/ + + +require_once DATA_ABSTRACT; + +/** + * EventManagementDataStates class + * + * PHP version 5 + * + * @category Data + * @package EventManagement + * @author Chuck Scott + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: dataStates.php,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ +class EventManagementDataEventReport extends DataAbstract +{ + /** + * Field definitions + * + * @var $ini + * @access public + */ + public $table = ''; + + /** + * Field definitions + * + * 'type' is type of field as defined by the application + * text Regular text field + * pointer Pointer to an entry in another table + * 'filters' is the filter name for a particular filter ID in PHP filter functions + * See PHP filter_id() + * + * 'use' is when to use the field + * l = List + * g = Get + * n = New + * i = Insert + * e = Edit + * u = Update + * d = Delete + * a = All + * + * @var $ini + * @access public + */ + public $fields = false; + + /** + * Constructor + * + * @param object $d database connection + * + * @return void + * @access public + */ + function __construct($dbh, $config) + { + + parent::__construct($dbh, $config); + + $this->fields = array( + + // Event selection + 'conv' => array( + 'field' => 'conv', + 'as' => 'event_name', + 'type' => 'pointer', + 'p_table' => 'event', + 'p_field' => 'name', + 'p_id' => 'id', + 'required' => true, + 'unique' => false, + 'default' => false, + 'use' => 'a', + 'quicktip' => array( + 'title' => 'Event Name', + 'tip' => ' +

Select the event for which you would like to produce a report.

+

You may produce an Event Summary report for only one event at a time.

+ ' + ) + ), + + // contacts Selection + 'contacts_section' => array( + 'field' => 'contacts_section', + 'as' => false, + 'type' => 'checkbox', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a', + 'quicktip' => array( + 'title' => 'Contacts Section', + 'tip' => ' +

Selects display of Contacts information in the report.

+ ' + ) + ), + + // Housing Selection + 'housing_section' => array( + 'field' => 'housing_section', + 'as' => false, + 'type' => 'checkbox', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a', + 'quicktip' => array( + 'title' => 'Housing Section', + 'tip' => ' +

Selects display of Housing information (properties, inventory, reservations) in the report.

+ ' + ) + ), + + // Housing Summary Only + 'housing_summary_only' => array( + 'field' => 'housing_summary_only', + 'as' => false, + 'type' => 'checkbox', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a', + 'quicktip' => array( + 'title' => 'Housing Summary Only', + 'tip' => ' +

Selects display of Housing summary information only in the report. + When this option is selected, only the summary is displayed without all of the property and inventory detail.

+ ' + ) + ), + + // Housing Available Only + 'housing_available_only' => array( + 'field' => 'housing_available_only', + 'as' => false, + 'type' => 'checkbox', + 'required' => false, + 'unique' => false, + 'default' => true, + 'use' => 'a', + 'quicktip' => array( + 'title' => 'Housing Available Only', + 'tip' => ' +

Removes the quantity of assigned and sold inventory and only displays the number currently available.

+ ' + ) + ), + + // Reservations Selection + 'reservations_section' => array( + 'field' => 'reservations_section', + 'as' => false, + 'type' => 'checkbox', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a', + 'quicktip' => array( + 'title' => 'Reservations Section', + 'tip' => ' +

Selects display of Reservations information in the report.

+ ' + ) + ), + + // Reservations Summary Only + 'reservations_summary_only' => array( + 'field' => 'reservations_summary_only', + 'as' => false, + 'type' => 'checkbox', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a', + 'quicktip' => array( + 'title' => 'Reservations Summary', + 'tip' => ' +

Selects display of Reservations summary information only in the report. + When this option is selected, only the summary is displayed without all of the reservation detail.

+ ' + ) + ), + + // Output Type + 'output_type' => array( + 'field' => 'output_type', + 'as' => false, + 'type' => 'list', + 'list' => array( + 'html' => 'Display on screen', + 'print' => 'Printable Report', + 'csv' => 'Export as speadsheet (.csv)' + ), + 'required' => true, + 'unique' => false, + 'default' => false, + 'use' => 'a', + 'quicktip' => array( + 'title' => 'Output Type', + 'tip' => ' +

This controls the way the report is output

+

Available options include

+
    +
  • Display on Screen - Display the report in your browser below the report request form.
  • +
  • Printable Report - Display the report in a separate browser window for output to a printer.
  • +
  • Export as Spreadsheet - Sends the report to your computer as a ".CSV" type file for import into a spreadsheet program.
  • +
+

If the Printable Report does not show, check to make sure you have permitted browser pop-ups for this Web site.

+ ' + ) + ) + + + ); + } + + /** + * Create Report Controls Data + * + * @return array + */ + function newControls() + { + + $r = $this->newEntry(); + + // If there's a currently selected Event, set that as default + if (isset($_SESSION[GLM_EVENT_SESSION]['Event']) && $_SESSION[GLM_EVENT_SESSION]['Event'] != false) { + $event = isset($_SESSION[GLM_EVENT_SESSION]['Event']); + $r['fieldData']['event_name']['pick_list'][$event]['default'] = true; + } + + return $r; + + } + + + /** + * Try to process controls input + * + * @return array + */ + function processControls() + { + + $r = $this->processInputData(); + + // If there's a currently selected Event, set that as default + if (isset($_SESSION[GLM_EVENT_SESSION]['Event']) && $_SESSION[GLM_EVENT_SESSION]['Event'] != false) { + $event = isset($_SESSION[GLM_EVENT_SESSION]['Event']); + $r['fieldData']['event_name']['pick_list'][$event]['default'] = true; + } + + return $r; + + } + + +} + + + + +?> \ No newline at end of file diff --git a/classes/data/Reports/dataReservationReport.php b/classes/data/Reports/dataReservationReport.php new file mode 100644 index 0000000..33be712 --- /dev/null +++ b/classes/data/Reports/dataReservationReport.php @@ -0,0 +1,357 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: Reports/dataReservationReport.php,v 1.0 2011/01/25 19:31:47 cscott Exp $ + * @link http://www.visitgreatlakesbay.org/ + */ + +/**** + * + * NOTE: This is a data class for form input validation only. + * There is no database table assoicated with this class! + * + ****/ + + +require_once DATA_ABSTRACT; + +/** + * EventManagementDataReservationReport class + * + * PHP version 5 + * + * @category Data + * @package EventManagement + * @author Chuck Scott + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: dataReservationReport.php,v 1.0 2011/01/25 19:31:47 cscott Exp $ + * @link http://www.visitgreatlakesbay.org + */ +class EventManagementDataReservationReport extends DataAbstract +{ + /** + * Field definitions + * + * @var $ini + * @access public + */ + public $table = ''; + + /** + * Field definitions + * + * 'type' is type of field as defined by the application + * text Regular text field + * pointer Pointer to an entry in another table + * 'filters' is the filter name for a particular filter ID in PHP filter functions + * See PHP filter_id() + * + * 'use' is when to use the field + * l = List + * g = Get + * n = New + * i = Insert + * e = Edit + * u = Update + * d = Delete + * a = All + * + * @var $ini + * @access public + */ + public $fields = false; + + /** + * Constructor + * + * @param object $d database connection + * + * @return void + * @access public + */ + function __construct($dbh, $config) + { + + parent::__construct($dbh, $config); + + $this->fields = array( + + // Event selection + 'event' => array( + 'field' => 'event', + 'as' => 'event_name', + 'type' => 'pointer', + 'p_table' => 'event', + 'p_field' => 'name', + 'p_id' => 'id', + 'required' => true, + 'unique' => false, + 'default' => false, + 'use' => 'a', + 'quicktip' => array( + 'title' => 'Event Name', + 'tip' => ' +

Select the event for which you would like to produce a report.

+

You may produce an Reservations report for only one event at a time.

+ ' + ) + ), + + // State selection + 'state' => array( + 'field' => 'state', + 'as' => 'state_rep', + 'type' => 'pointer', + 'p_table' => 'state_rep', + 'p_field' => 'code', + 'p_id' => 'id', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a', + 'quicktip' => array( + 'title' => 'State', + 'tip' => ' +

Optionally select a State for which you would like to produce the report.

+

If no State is selected, the report will include all states.

+ ' + ) + ), + + // Team selection + 'team' => array( + 'field' => 'team', + 'as' => 'team_code', + 'type' => 'pointer', + 'p_table' => 'team', + 'p_field' => 'team_code', + 'p_id' => 'id', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a', + 'quicktip' => array( + 'title' => 'Team', + 'tip' => ' +

Optionally select a Team for which you would like to produce the report.

+

If no Team is selected, the report will include all teams.

+ ' + ) + ), + + // Property filter selection + 'property' => array( + 'field' => 'property', + 'as' => 'prop_name', + 'type' => 'pointer', + 'p_table' => 'eventmgt.member', + 'p_field' => 'name', + 'p_id' => 'id', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a', + 'quicktip' => array( + 'title' => 'Property', + 'tip' => ' +

Optionally select a Property for which you would like to produce the report.

+

If no Property is selected, the report will include all properties matching reservations.

+ ' + ) + ), + + // Status + 'status' => array( + 'field' => 'status', + 'as' => false, + 'type' => 'list', + 'list' => array( + 'all' => 'All', + 'pending' => 'Pending', + 'confirmed' => 'Confirmed', + 'declined' => 'Declined' + ), + 'required' => true, + 'unique' => false, + 'default' => false, + 'use' => 'a', + 'quicktip' => array( + 'title' => 'Status', + 'tip' => ' +

This selects which reservations should be display by status

+

Available options include

+
    +
  • All - Display all reservations.
  • +
  • Pending - Display all pending reservations. This is reservations that have neither been confirmed or declined.
  • +
  • Confirmed - Display only reservations that have been confirmed.
  • +
  • Declined - Display only reservations that have been declined.
  • +
+ ' + ) + ), + + + // Output Type + 'output_type' => array( + 'field' => 'output_type', + 'as' => false, + 'type' => 'list', + 'list' => array( + 'html' => 'Display on screen', + 'print' => 'Printable Report', + 'csv' => 'Export as speadsheet (.csv)' + ), + 'required' => true, + 'unique' => false, + 'default' => false, + 'use' => 'a', + 'quicktip' => array( + 'title' => 'Output Type', + 'tip' => ' +

This controls the way the report is output

+

Available options include

+
    +
  • Display on Screen - Display the report in your browser below the report request form.
  • +
  • Printable Report - Display the report in a separate browser window for output to a printer.
  • +
  • Export as Spreadsheet - Sends the report to your computer as a ".CSV" type file for import into a spreadsheet program.
  • +
+

If the Printable Report does not show, check to make sure you have permitted browser pop-ups for this Web site.

+ ' + ) + ) + + + + ); + } + + /** + * Create Report Controls Data + * + * @return array + */ + function newControls() + { + + $r = $this->newEntry(); + + // Get event, state, team matrix and merge that with result + $eventStateTeamData = $this->getEventStateTeamMatrix(); + $r['eventStateTeam'] = $eventStateTeamData; + + // If there's a currently selected Event, set that as default + if (isset($_SESSION[GLM_EVENT_SESSION]['Event']) && $_SESSION[GLM_EVENT_SESSION]['Event'] != false) { + $event = isset($_SESSION[GLM_EVENT_SESSION]['Event']); + $r['fieldData']['event_name']['pick_list'][$event]['default'] = true; + $r['eventStateTeam'][$event]['default'] = true; + } + + return $r; + + } + + /** + * getStateTeamMatrix + * + */ + function getEventStateTeamMatrix() + { + + // Get property/accommodation matrix + $sql = " + SELECT C.id AS event_id, + C.name AS event_name, + C.event_code AS event_code, + S.id AS state_id, + S.code AS state_code, + S.event AS event, + T.id AS team_id, + T.team_code AS team_code, + T.name AS team_name + FROM eventmgt.event C + LEFT OUTER JOIN state_rep S ON (S.event = C.id) + LEFT OUTER JOIN team T ON (T.state = S.id) + ORDER BY C.name, S.code, T.team_code + ;"; + $stmt = $this->dbh->prepare($sql); + $stmt->execute(); + $eventStateTeamData = $stmt->fetchAll(PDO::FETCH_ASSOC); + if (count($eventStateTeamData) == 0) { + $reason[] = "No State Reps listed in the system."; + } + // *** LOOK FOR DEFAULTS *** + // Build array of Members with their accommodations + $eventStateTeam = array(); + foreach ($eventStateTeamData as $d) { + + // If event hasn't been added yet, do that. + if (!isset($eventStateTeam[$d['event_id']])) { + $eventStateTeam[$d['event_id']] = array( + 'eventID' => $d['event_id'], + 'eventName' => $d['event_name'], + 'eventCode' => $d['event_code'], + 'default' => false, + 'state' => array() + ); + } + + // If state hasn't been added yet, do that. + if ($d['state_id']) { + if (!isset($eventStateTeam[$d['event_id']]['state'][$d['state_id']])) { + $eventStateTeam[$d['event_id']]['state'][$d['state_id']] = array( + 'stateID' => $d['state_id'], + 'stateCode' => $d['state_code'], + 'team' => array() + ); + } + } + + // Add team + if ($d['team_id']) { + $eventStateTeam[$d['event_id']]['state'][$d['state_id']]['team'][$d['team_id']] = array( + 'teamID' => $d['team_id'], + 'teamName' => $d['team_name'] + ); + } + } + + return $eventStateTeam; + } + + + + /** + * Try to process controls input + * + * @return array + */ + function processControls() + { + + $r = $this->processInputData(); + + // If there's a currently selected Event, set that as default + if (isset($_SESSION[GLM_EVENT_SESSION]['Event']) && $_SESSION[GLM_EVENT_SESSION]['Event'] != false) { + $event = isset($_SESSION[GLM_EVENT_SESSION]['Event']); + $r['fieldData']['event_name']['pick_list'][$event]['default'] = true; + } + + return $r; + + } + + +} + + + + +?> \ No newline at end of file diff --git a/classes/data/Reports/dataRoomBlockReport.php b/classes/data/Reports/dataRoomBlockReport.php new file mode 100644 index 0000000..d634d7c --- /dev/null +++ b/classes/data/Reports/dataRoomBlockReport.php @@ -0,0 +1,391 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: Reports/dataRoomBlockReport.php,v 1.0 2011/01/25 19:31:47 cscott Exp $ + * @link http://www.gaslightmedia.com/ + */ + +/**** + * + * NOTE: This is a data class for form input validation only. + * There is no database table assoicated with this class! + * + ****/ + + +require_once DATA_ABSTRACT; + +/** + * EventManagementDataStates class + * + * PHP version 5 + * + * @category Data + * @package EventManagement + * @author Chuck Scott + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: dataRoomBlockReport.php,v 1.0 2011/01/25 19:31:47 cscott Exp $ + * @link http://www.gaslightmedia.com + */ +class EventManagementDataRoomBlockReport extends DataAbstract +{ + /** + * Field definitions + * + * @var $ini + * @access public + */ + public $table = ''; + + /** + * Field definitions + * + * 'type' is type of field as defined by the application + * text Regular text field + * pointer Pointer to an entry in another table + * 'filters' is the filter name for a particular filter ID in PHP filter functions + * See PHP filter_id() + * + * 'use' is when to use the field + * l = List + * g = Get + * n = New + * i = Insert + * e = Edit + * u = Update + * d = Delete + * a = All + * + * @var $ini + * @access public + */ + public $fields = false; + + /** + * Constructor + * + * @param object $d database connection + * + * @return void + * @access public + */ + function __construct($dbh, $config) + { + + parent::__construct($dbh, $config); + + $this->fields = array( + + // Event selection + 'event' => array( + 'field' => 'event', + 'as' => 'event_name', + 'type' => 'pointer', + 'p_table' => 'event', + 'p_field' => 'name', + 'p_id' => 'id', + 'required' => true, + 'unique' => false, + 'default' => false, + 'use' => 'a', + 'quicktip' => array( + 'title' => 'Event Name', + 'tip' => ' +

Select the event for which you would like to produce a report.

+

You may produce a Room Block report for only one event at a time.

+ ' + ) + ), + + // State filter selection + 'state' => array( + 'field' => 'state', + 'as' => 'state_rep', + 'type' => 'pointer', + 'p_table' => 'state_rep', + 'p_field' => 'code', + 'p_id' => 'id', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a', + 'quicktip' => array( + 'title' => 'State', + 'tip' => ' +

Optionally select a State for which you would like to produce the report.

+

If no State is selected, the report will include all states.

+ ' + ) + ), + + // Team filter selection + 'team' => array( + 'field' => 'team', + 'as' => 'team_code', + 'type' => 'pointer', + 'p_table' => 'team', + 'p_field' => 'team_code', + 'p_id' => 'id', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a', + 'quicktip' => array( + 'title' => 'Team', + 'tip' => ' +

Optionally select a Team for which you would like to produce the report.

+

If no Team is selected, the report will include all teams.

+ ' + ) + ), + + // Property filter selection + 'property' => array( + 'field' => 'property', + 'as' => 'prop_name', + 'type' => 'pointer', + 'p_table' => 'eventmgt.member', + 'p_field' => 'name', + 'p_id' => 'id', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a', + 'quicktip' => array( + 'title' => 'Property', + 'tip' => ' +

Optionally select a Property for which you would like to produce the report.

+

If no Property is selected, the report will include all properties with accommodations in the matching room blocks.

+ ' + ) + ), + + // Property section selection + 'property_section' => array( + 'field' => 'property_section', + 'as' => false, + 'type' => 'checkbox', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a', + 'quicktip' => array( + 'title' => 'Properties Section', + 'tip' => ' +

Selects display of Room Blocks listed by Property.

+ ' + ) + ), + + // Assigned Selection + 'assigned_section' => array( + 'field' => 'assigned_section', + 'as' => false, + 'type' => 'checkbox', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a', + 'quicktip' => array( + 'title' => 'Assigned Section', + 'tip' => ' +

Selects display of Room Blocks assigned to State Reps and Teams.

+ ' + ) + ), + + // Option: Show assigned quantities in addition to currently available quantities + 'option_assigned' => array( + 'field' => 'option_assigned', + 'as' => false, + 'type' => 'checkbox', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a', + 'quicktip' => array( + 'title' => 'Assigned Quantities', + 'tip' => ' +

When selected assigned quantities are included in addition to currently available quantities.

+ ' + ) + ), + + // Output Type + 'output_type' => array( + 'field' => 'output_type', + 'as' => false, + 'type' => 'list', + 'list' => array( + 'html' => 'Display on screen', + 'print' => 'Printable Report', + 'csv' => 'Export as speadsheet (.csv)' + ), + 'required' => true, + 'unique' => false, + 'default' => false, + 'use' => 'a', + 'quicktip' => array( + 'title' => 'Output Type', + 'tip' => ' +

This controls the way the report is output

+

Available options include

+
    +
  • Display on Screen - Display the report in your browser below the report request form.
  • +
  • Printable Report - Display the report in a separate browser window for output to a printer.
  • +
  • Export as Spreadsheet - Sends the report to your computer as a ".CSV" type file for import into a spreadsheet program.
  • +
+

If the Printable Report does not show, check to make sure you have permitted browser pop-ups for this Web site.

+ ' + ) + ) + + ); + } + + /** + * Create Report Controls Data + * + * @return array + */ + function newControls() + { + + $r = $this->newEntry(); + + // Get event, state, team matrix and merge that with result + $eventStateTeamData = $this->getEventStateTeamMatrix(); + $r['eventStateTeam'] = $eventStateTeamData; + + // If there's a currently selected Event, set that as default + if (isset($_SESSION[GLM_EVENT_SESSION]['Event']) && $_SESSION[GLM_EVENT_SESSION]['Event'] != false) { + $event = isset($_SESSION[GLM_EVENT_SESSION]['Event']); + $r['eventStateTeam'][$event]['default'] = true; + } + + return $r; + + } + + /** + * getStateTeamMatrix + * + */ + function getEventStateTeamMatrix() + { + + // Get property/accommodation matrix + $sql = " + SELECT C.id AS event_id, + C.name AS event_name, + C.event_code AS event_code, + S.id AS state_id, + S.code AS state_code, + S.event AS event, + T.id AS team_id, + T.team_code AS team_code, + T.name AS team_name + FROM eventmgt.event C + LEFT OUTER JOIN state_rep S ON (S.event = C.id) + LEFT OUTER JOIN team T ON (T.state = S.id) + ORDER BY C.name, S.code, T.team_code + ;"; + $stmt = $this->dbh->prepare($sql); + $stmt->execute(); + $eventStateTeamData = $stmt->fetchAll(PDO::FETCH_ASSOC); + if (count($eventStateTeamData) == 0) { + $reason[] = "No State Reps listed in the system."; + } +// *** LOOK FOR DEFAULTS *** + // Build array of Members with their accommodations + $eventStateTeam = array(); + foreach ($eventStateTeamData as $d) { + + // If event hasn't been added yet, do that. + if (!isset($eventStateTeam[$d['event_id']])) { + $eventStateTeam[$d['event_id']] = array( + 'eventID' => $d['event_id'], + 'eventName' => $d['event_name'], + 'eventCode' => $d['event_code'], + 'default' => false, + 'property' => array(), + 'state' => array() + ); + } + + // If state hasn't been added yet, do that. + if ($d['state_id']) { + if (!isset($eventStateTeam[$d['event_id']]['state'][$d['state_id']])) { + $eventStateTeam[$d['event_id']]['state'][$d['state_id']] = array( + 'stateID' => $d['state_id'], + 'stateCode' => $d['state_code'], + 'team' => array() + ); + } + } + + // Add team + if ($d['team_id']) { + $eventStateTeam[$d['event_id']]['state'][$d['state_id']]['team'][$d['team_id']] = array( + 'teamID' => $d['team_id'], + 'teamName' => $d['team_name'] + ); + } + } + + // Also layer in properties to event array + $sql = " + SELECT DISTINCT ON (B.event, B.member) + B.event AS event_id, B.member AS prop_id, M.name AS prop_name + FROM eventmgt.room_block B, eventmgt.member M + WHERE M.id = B.member + ;"; + $stmt = $this->dbh->prepare($sql); + $stmt->execute(); + $propData = $stmt->fetchAll(PDO::FETCH_ASSOC); + foreach ($propData as $p) { + $eventStateTeam[$p['event_id']]['property'][$p['prop_id']] = array( + 'propID' => $p['prop_id'], + 'propName' => $p['prop_name'] + ); + } + + + return $eventStateTeam; + } + + /** + * Try to process controls input + * + * @return array + */ + function processControls() + { + + $r = $this->processInputData(); + + // If there's a currently selected Event, set that as default + if (isset($_SESSION[GLM_EVENT_SESSION]['Event']) && $_SESSION[GLM_EVENT_SESSION]['Event'] != false) { + $event = isset($_SESSION[GLM_EVENT_SESSION]['Event']); + $r['fieldData']['event_name']['pick_list'][$event]['default'] = true; + } + + return $r; + + } + + +} + + + + +?> \ No newline at end of file diff --git a/classes/data/Reports/dataRoomRequestReport.php b/classes/data/Reports/dataRoomRequestReport.php new file mode 100644 index 0000000..9ff4155 --- /dev/null +++ b/classes/data/Reports/dataRoomRequestReport.php @@ -0,0 +1,392 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: Reports/dataRoomRequestReport.php,v 1.0 2011/01/25 19:31:47 cscott Exp $ + * @link http://www.gaslightmedia.com/ + */ + +/**** + * + * NOTE: This is a data class for form input validation only. + * There is no database table assoicated with this class! + * + ****/ + + +require_once DATA_ABSTRACT; + +/** + * EventManagementRoomRequestReport class + * + * PHP version 5 + * + * @category Data + * @package EventManagement + * @author Chuck Scott + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: dataRoomRequestReport.php,v 1.0 2011/01/25 19:31:47 cscott Exp $ + * @link http://www.gaslightmedia.com + */ +class EventManagementDataRoomRequestReport extends DataAbstract +{ + /** + * Field definitions + * + * @var $ini + * @access public + */ + public $table = ''; + + /** + * Field definitions + * + * 'type' is type of field as defined by the application + * text Regular text field + * pointer Pointer to an entry in another table + * 'filters' is the filter name for a particular filter ID in PHP filter functions + * See PHP filter_id() + * + * 'use' is when to use the field + * l = List + * g = Get + * n = New + * i = Insert + * e = Edit + * u = Update + * d = Delete + * a = All + * + * @var $ini + * @access public + */ + public $fields = false; + + /** + * Constructor + * + * @param object $d database connection + * + * @return void + * @access public + */ + function __construct($dbh, $config) + { + + parent::__construct($dbh, $config); + + $this->fields = array( + + // Event selection + 'event' => array( + 'field' => 'event', + 'as' => 'event_name', + 'type' => 'pointer', + 'p_table' => 'event', + 'p_field' => 'name', + 'p_id' => 'id', + 'required' => true, + 'unique' => false, + 'default' => false, + 'use' => 'a', + 'quicktip' => array( + 'title' => 'Event Name', + 'tip' => ' +

Select the event for which you would like to produce a report.

+

You may produce an Reservations report for only one event at a time.

+ ' + ) + ), + + // State selection + 'state' => array( + 'field' => 'state', + 'as' => 'state_rep', + 'type' => 'pointer', + 'p_table' => 'state_rep', + 'p_field' => 'code', + 'p_id' => 'id', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a', + 'quicktip' => array( + 'title' => 'State', + 'tip' => ' +

Optionally select a State for which you would like to produce the report.

+

If no State is selected, the report will include all states.

+ ' + ) + ), + + // Team selection + 'team' => array( + 'field' => 'team', + 'as' => 'team_code', + 'type' => 'pointer', + 'p_table' => 'team', + 'p_field' => 'team_code', + 'p_id' => 'id', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a', + 'quicktip' => array( + 'title' => 'Team', + 'tip' => ' +

Optionally select a Team for which you would like to produce the report.

+

If no Team is selected, the report will include all teams.

+ ' + ) + ), + + // Property filter selection + 'property' => array( + 'field' => 'property', + 'as' => 'prop_name', + 'type' => 'pointer', + 'p_table' => 'eventmgt.member', + 'p_field' => 'name', + 'p_id' => 'id', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a', + 'quicktip' => array( + 'title' => 'Property', + 'tip' => ' +

Optionally select a Property for which you would like to produce the report.

+

If no Property is selected, the report will include all properties with accommodations in the matching room requests.

+ ' + ) + ), + + // Show pending + 'pending_select' => array( + 'field' => 'pending_select', + 'as' => false, + 'type' => 'checkbox', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a', + 'quicktip' => array( + 'title' => 'Show pending', + 'tip' => ' +

Selects display of pending reservtions.

+ ' + ) + ), + + // Show confirmed + 'confirmed_select' => array( + 'field' => 'confirmed_select', + 'as' => false, + 'type' => 'checkbox', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a', + 'quicktip' => array( + 'title' => 'Show Confirmed', + 'tip' => ' +

Selects display of confirmed reservtions.

+ ' + ) + ), + + // Show declined + 'declined_select' => array( + 'field' => 'declined_select', + 'as' => false, + 'type' => 'checkbox', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a', + 'quicktip' => array( + 'title' => 'Show Declined', + 'tip' => ' +

Selects display of declined reservtions.

+ ' + ) + ), + + // Show Availabile + 'available_select' => array( + 'field' => 'available_select', + 'as' => false, + 'type' => 'checkbox', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a', + 'quicktip' => array( + 'title' => 'Show Available', + 'tip' => ' +

Selects display of assigned and available inventory for each room block.

+ ' + ) + ), + + // Output Type + 'output_type' => array( + 'field' => 'output_type', + 'as' => false, + 'type' => 'list', + 'list' => array( + 'html' => 'Display on screen', + 'print' => 'Printable Report', + 'csv' => 'Export as speadsheet (.csv)' + ), + 'required' => true, + 'unique' => false, + 'default' => false, + 'use' => 'a', + 'quicktip' => array( + 'title' => 'Output Type', + 'tip' => ' +

This controls the way the report is output

+

Available options include

+
    +
  • Display on Screen - Display the report in your browser below the report request form.
  • +
  • Printable Report - Display the report in a separate browser window for output to a printer.
  • +
  • Export as Spreadsheet - Sends the report to your computer as a ".CSV" type file for import into a spreadsheet program.
  • +
+

If the Printable Report does not show, check to make sure you have permitted browser pop-ups for this Web site.

+ ' + ) + ) + + + + ); + } + + /** + * Create Report Controls Data + * + * @return array + */ + function newControls() + { + + $r = $this->newEntry(); + + // Get event, state, team matrix and merge that with result + $eventStateTeamData = $this->getEventStateTeamMatrix(); + $r['eventStateTeam'] = $eventStateTeamData; + + // If there's a currently selected Event, set that as default + if (isset($_SESSION[GLM_EVENT_SESSION]['Event']) && $_SESSION[GLM_EVENT_SESSION]['Event'] != false) { + $event = isset($_SESSION[GLM_EVENT_SESSION]['Event']); + $r['eventStateTeam'][$event]['default'] = true; + } + + return $r; + + } + + /** + * getStateTeamMatrix + * + */ + function getEventStateTeamMatrix() + { + + // Get property/accommodation matrix + $sql = " + SELECT C.id AS event_id, + C.name AS event_name, + C.event_code AS event_code, + S.id AS state_id, + S.code AS state_code, + S.event AS event, + T.id AS team_id, + T.team_code AS team_code, + T.name AS team_name + FROM eventmgt.event C + LEFT OUTER JOIN state_rep S ON (S.event = C.id) + LEFT OUTER JOIN team T ON (T.state = S.id) + ORDER BY C.name, S.code, T.team_code + ;"; + $stmt = $this->dbh->prepare($sql); + $stmt->execute(); + $eventStateTeamData = $stmt->fetchAll(PDO::FETCH_ASSOC); + if (count($eventStateTeamData) == 0) { + $reason[] = "No State Reps listed in the system."; + } + // *** LOOK FOR DEFAULTS *** + // Build array of Members with their accommodations + $eventStateTeam = array(); + foreach ($eventStateTeamData as $d) { + + // If event hasn't been added yet, do that. + if (!isset($eventStateTeam[$d['event_id']])) { + $eventStateTeam[$d['event_id']] = array( + 'eventID' => $d['event_id'], + 'eventName' => $d['event_name'], + 'eventCode' => $d['event_code'], + 'default' => false, + 'state' => array() + ); + } + + // If state hasn't been added yet, do that. + if ($d['state_id']) { + if (!isset($eventStateTeam[$d['event_id']]['state'][$d['state_id']])) { + $eventStateTeam[$d['event_id']]['state'][$d['state_id']] = array( + 'stateID' => $d['state_id'], + 'stateCode' => $d['state_code'], + 'team' => array() + ); + } + } + + // Add team + if ($d['team_id']) { + $eventStateTeam[$d['event_id']]['state'][$d['state_id']]['team'][$d['team_id']] = array( + 'teamID' => $d['team_id'], + 'teamName' => $d['team_name'] + ); + } + } + + return $eventStateTeam; + } + + + /** + * Try to process controls input + * + * @return array + */ + function processControls() + { + + $r = $this->processInputData(); + + // If there's a currently selected Event, set that as default + if (isset($_SESSION[GLM_EVENT_SESSION]['Event']) && $_SESSION[GLM_EVENT_SESSION]['Event'] != false) { + $event = isset($_SESSION[GLM_EVENT_SESSION]['Event']); + $r['fieldData']['event_name']['pick_list'][$event]['default'] = true; + } + + return $r; + + } + + +} + + + + +?> \ No newline at end of file diff --git a/classes/data/dataAccoms.php b/classes/data/dataAccoms.php new file mode 100644 index 0000000..9fa360f --- /dev/null +++ b/classes/data/dataAccoms.php @@ -0,0 +1,468 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: dataAccoms.php,v 1.0 2011/01/25 19:31:47 cscott Exp $ + * @link http://www.gaslightmedia.com + */ + +require_once DATA_ABSTRACT; + +/** + * EventManagementDataAccoms class + * + * PHP version 5 + * + * @category Data + * @package EventManagement + * @author Chuck Scott + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: dataAccoms,v 1.0 2011/01/25 19:31:47 cscott Exp $ + * @link <> + */ +class EventManagementDataAccoms extends DataAbstract +{ + /** + * Tables + * + * @var $ini + * @access public + */ + public $table = 'eventmgt.accommodation'; + + /** + * Field definitions + * + * 'type' is type of field as defined by the application + * text Regular text field + * pointer Pointer to an entry in another table + * 'filters' is the filter name for a particular filter ID in PHP filter functions + * See PHP filter_id() + * + * 'use' is when to use the field + * l = List + * g = Get + * n = New + * i = Insert + * e = Edit + * u = Update + * d = Delete + * a = All + * + * @var $ini + * @access public + */ + public $fields = false; + + /** + * Constructor + * + * @param object $d database connection + * + * @return void + * @access public + */ + function __construct($dbh, $config) + { + + parent::__construct($dbh, $config); + + $this->fields = array( + + // Record ID + 'id' => array( + 'field' => 'id', + 'as' => false, + 'type' => 'integer', + 'required' => true, + 'unique' => true, + 'default' => false, + 'use' => 'lged' + ), + + // Member name + 'member' => array( + 'field' => 'member', + 'as' => 'property', + 'type' => 'pointer', + 'p_table' => 'members.member', + 'p_field' => 'member_name', + 'p_id' => 'member_id', + 'p_where' => 'member_id in + ( + SELECT DISTINCT member_id + FROM members.member_category + WHERE category_id IN + (SELECT category_id FROM members.category WHERE accommodations) + )', + 'required' => true, + 'unique' => false, + 'default' => $_SESSION[GLM_EVENT_SESSION]['Member'], + 'use' => 'ni' + ), + + // Member name + 'member_2' => array( + 'field' => 'member', + 'as' => 'property', + 'type' => 'pointer', + 'p_table' => 'members.member', + 'p_field' => 'member_name', + 'p_id' => 'member_id', + 'p_static' => true, + 'required' => true, + 'unique' => false, + 'default' => $_SESSION[GLM_EVENT_SESSION]['Member'], + 'view_only' => true, + 'use' => 'gleudc' + ), + + // Accommodation Name (internal use) + 'name' => array( + 'field' => 'name', + 'as' => false, + 'type' => 'text', + 'required' => true, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Accommodation Title (for display to users) + 'title' => array( + 'field' => 'title', + 'as' => false, + 'type' => 'text', + 'required' => true, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Category - Needs to be moved to a separate admin table + 'category' => array( + 'field' => 'category', + 'as' => false, + 'type' => 'list', + 'list' => $this->config->room_category->toArray(), + 'list_keytype' => 'int', + 'required' => true, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Description + 'descr' => array( + 'field' => 'descr', + 'as' => false, + 'type' => 'text', + 'filter' => FILTER_SANITIZE_MAGIC_QUOTES, + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Image + 'image' => array( + 'field' => 'image', + 'as' => false, + 'type' => 'text', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'gnieud' + ), + + // Quantity - Number of these accommodations at property + 'quant' => array( + 'field' => 'quant', + 'as' => false, + 'type' => 'integer', + 'required' => true, + 'unique' => false, + 'default' => false, + 'use' => 'lgnieud' + ), + + // Standard # of occupants + 'occupants' => array( + 'field' => 'occupants', + 'as' => false, + 'type' => 'integer', + 'required' => true, + 'unique' => false, + 'default' => false, + 'use' => 'gnieud' + ), + + // Max # of occupants + 'maxoccupants' => array( + 'field' => 'maxoccupants', + 'as' => false, + 'type' => 'integer', + 'required' => true, + 'unique' => false, + 'default' => false, + 'use' => 'gnieud' + ), + + // Display Order (sort) + 'sort' => array( + 'field' => 'sort', + 'as' => false, + 'type' => 'integer', + 'required' => false, + 'unique' => false, + 'default' => 0, + 'use' => 'a' + ) + + + ); + } + + /** + * Get Accommadations list + * + * @return object containing array as sub-objects + */ + function getAccomsList($member = false) + { + + // Get any specified member listing option - default to event + $option = 'event'; + if (($membersListOption = filter_input(INPUT_GET, 'AccomsListOption', FILTER_SANITIZE_STRING))) { + $option = $membersListOption; + } + + // Get event Member from session - if available + $memberID = $_SESSION[GLM_EVENT_SESSION]['Member']; + if ($member) { + $memberID = $member; + $option = 'member'; + } + + // Select type of list + $where = ''; + switch ($option) { + case 'all': + $where = 'TRUE'; + break; + case 'member': + if ($memberID) { + $where = "T.member = $memberID"; + } else { + $where .= "false"; + } + break; + default: + echo "Option not set"; + break; + } + + // Get list of all available Events + $accomsList = $this->getList($where, 'sort, name'); + + + if (count($accomsList) == 0) { + return false; + } + + + return $accomsList; + } + + + /** + * Get Accommodation Detail + * + * @return array + */ + function getAccomDetail() + { + + // Is there a new accom ID selected? + if (($accomID = filter_input(INPUT_GET, 'AccomID', FILTER_SANITIZE_NUMBER_INT))) { + + // If so then add it to the session + $_SESSION[GLM_EVENT_SESSION]['Accom'] = $accomID; + + } elseif (isset($_SESSION[GLM_EVENT_SESSION]['Accom'])) { + + // Otherwise, get the event ID from the session + $accomID = $_SESSION[GLM_EVENT_SESSION]['Accom']; + + } else { + + // Otherwise, we don't have an event id + return false; + + } + + $accomDetail = $this->getEntry($accomID); + + return $accomDetail; + + } + + + /** + * Edit Accommodation + * + * @return array + */ + function editAccom() + { + + // Is there a new accommodaton code selected? + if (($accomID = filter_input(INPUT_GET, 'AccomID', FILTER_SANITIZE_NUMBER_INT))) { + + // If so then add it to the session + $_SESSION[GLM_EVENT_SESSION]['Accom'] = $accomID; + + } elseif (isset($_SESSION[GLM_EVENT_SESSION]['Accom'])) { + + // Otherwise, get the accommodation ID from the session + $accomID = $_SESSION[GLM_EVENT_SESSION]['Accom']; + + } else { + + // Otherwise, we don't have a accommodation id + return false; + + } + + $accomDetail = $this->editEntry($accomID); + + // echo "
".print_r($accomDetail,1)."
"; + return $accomDetail; + + } + + /** + * Check for other field related issues + * + * This function must be here because it's called from a function + * in dataAbstract. Simply return $r if there's nothing to check. + * + * @return array + */ + function checkOther($r) + { + parent::checkOther($r); +/* + $fd = $r['fieldData']; + + // Is Start date is later than End date + if (strtotime($fd['start_date']) > strtotime($fd['end_date'])) { + $r['fieldFail']['start_date'] = 'Start date is later than end date.'; + $r['status'] = false; + } + + // Is cutoff date is later than end date + if (strtotime($fd['cutoff_date']) > strtotime($fd['end_date'])) { + $r['fieldFail']['cutoff_date'] = 'Cutoff date is later than end date.'; + $r['status'] = false; + } +*/ + return $r; + } + + /** + * Update Accommodation + * + * @return array + */ + function updateAccom() + { + + // Is there a new event code selected? + if (($accomID = filter_input(INPUT_GET, 'AccomID', FILTER_SANITIZE_NUMBER_INT))) { + + // If so then add it to the session + $_SESSION[GLM_EVENT_SESSION]['Accom'] = $accomID; + + } elseif (isset($_SESSION[GLM_EVENT_SESSION]['Accom'])) { + + // Otherwise, get the accommodation ID from the session + $accomID = $_SESSION[GLM_EVENT_SESSION]['Accom']; + + } else { + + // Otherwise, we don't have a accommodation id + return false; + + } + + // Try to update this data + $r = $this->updateEntry($accomID); + + return $r; + + } + + /** + * Add Accommodation + * + * @return array + */ + function newAccom() + { + + $r = $this->newEntry(); + + // If there's a currently selected Event, set that as default + if (isset($_SESSION[GLM_EVENT_SESSION]['Member']) && $_SESSION[GLM_EVENT_SESSION]['Member'] != false) { + $accomID = $_SESSION[GLM_EVENT_SESSION]['Member']; + + $r['fieldData']['property']['pick_list'][$accomID]['default'] = true; + $r['fieldData']['property']['name'] = $r['fieldData']['property']['pick_list'][$accomID]['name']; + $r['fieldData']['property']['value'] = $accomID; + } + + // If succesful then set current accommodation to the one just inserted. + if ($r['status']) { + $_SESSION[GLM_EVENT_SESSION]['Accom'] = $r['insertedID']; + } + + // echo "
".print_r($r,1)."
"; + return $r; + + } + + /** + * Insert Accommodation + * + * @return array + */ + function insertAccom() + { + + $r = $this->insertEntry(); + + // If succesful then set current accommodation to the one just inserted. + if ($r['status']) { + $_SESSION[GLM_EVENT_SESSION]['Accom'] = $r['insertedID']; + } + + // echo "
".print_r($r,1)."
"; + return $r; + + } + + +} + + + + +?> \ No newline at end of file diff --git a/classes/data/dataAddonSold.php b/classes/data/dataAddonSold.php new file mode 100644 index 0000000..5af00aa --- /dev/null +++ b/classes/data/dataAddonSold.php @@ -0,0 +1,290 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: dataAddonSold.php,v 1.0 2011/01/25 19:31:47 cscott Exp $ + * @link + */ + +require_once DATA_ABSTRACT; + +/** + * EventManagementDataAddonSold class + * + * PHP version 5 + * + * @category Data + * @package EventManagement + * @author Chuck Scott + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: dataAddonSold.php,v 1.0 2011/01/25 19:31:47 cscott Exp $ + * @link + */ +class EventManagementDataAddonSold extends DataAbstract +{ + /** + * Field definitions + * + * @var $ini + * @access public + */ + public $table = 'eventmgt.add_on_sold'; + + /** + * Field definitions + * + * 'type' is type of field as defined by the application + * text Regular text field + * pointer Pointer to an entry in another table + * 'filters' is the filter name for a particular filter ID in PHP filter functions + * See PHP filter_id() + * + * 'use' is when to use the field + * l = List + * g = Get + * n = New + * i = Insert + * e = Edit + * u = Update + * d = Delete + * a = All + * + * @var $ini + * @access public + */ + public $fields = false; + + /** + * Constructor + * + * @param object $d database connection + * + * @return void + * @access public + */ + function __construct($dbh, $config) + { + + parent::__construct($dbh, $config); + + $this->fields = array( + + // Record ID + 'id' => array( + 'field' => 'id', + 'as' => false, + 'type' => 'integer', + 'required' => true, + 'unique' => true, + 'default' => false, + 'use' => 'lg' + ), + + // Ticket Order + 'ticket_order' => array( + 'field' => 'ticket_order', + 'as' => false, + 'type' => 'integer', + 'required' => true, + 'unique' => false, + 'default' => false, + 'use' => 'niegdl' + ), + + // Ticket Sold + 'ticket_sold' => array( + 'field' => 'ticket_sold', + 'as' => false, + 'type' => 'integer', + 'required' => true, + 'unique' => false, + 'default' => false, + 'use' => 'niegdl' + ), + + // Add-on Name + 'add_on_name' => array( + 'field' => 'add_on_name', + 'as' => false, + 'type' => 'text', + 'required' => true, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Add-on type + 'add_on_type' => array( + 'field' => 'add_on_type', + 'as' => false, + 'type' => 'list', + 'list' => $this->config->ticket_add_on_type->toArray(), + 'required' => true, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Add-on type name + 'add_on_type_name' => array( + 'field' => 'add_on_type_name', + 'as' => false, + 'type' => 'text', + 'required' => true, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Unit name + 'unit_name' => array( + 'field' => 'unit_name', + 'as' => false, + 'type' => 'text', + 'required' => true, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Unit cost number + 'unit_price_numb' => array( + 'field' => 'unit_price', + 'as' => 'unit_price_numb', + 'type' => 'float', + 'required' => false, + 'unique' => false, + 'default' => 0.00, + 'use' => 'a' + ), + + // Unit price (money) + 'unit_price' => array( + 'field' => 'unit_price', + 'as' => false, + 'type' => 'money', + 'required' => false, + 'unique' => false, + 'default' => 0.00, + 'use' => 'lgd' + ), + + // Quantity selected + 'quant' => array( + 'field' => 'quant', + 'as' => false, + 'type' => 'integer', + 'required' => false, + 'unique' => false, + 'default' => 0, + 'use' => 'a' + ), + + // Total Price Paid - Number + 'price_paid_numb' => array( + 'field' => 'price_paid', + 'as' => 'price_paid_numb', + 'type' => 'float', + 'required' => false, + 'unique' => false, + 'default' => 0.00, + 'use' => 'a' + ), + + // Price paid (money) + 'price_paid' => array( + 'field' => 'price_paid', + 'as' => false, + 'type' => 'money', + 'required' => false, + 'unique' => false, + 'default' => 0.00, + 'use' => 'lgd' + ) + + ); + + } + + /** + * Get Ticket Sold Add-Ons list + * + * @return object containing array as sub-objects + */ + function getAddonsSoldList($ticketSoldID = false, $where = false) + { + + // If a where clause has not been supplied, use the $TicketSoldID - Otherwise $where + if (!$where) { + + $where = 'true'; + + // Check if there's a ticket sold ID, then filter by that + $ticketSoldID = ($ticketSoldID - 0); // Make sure it's number + if ($ticketSoldID > 0) { + $where .= " AND T.ticket_sold = $ticketSoldID"; + } + + } + + $addonsSoldList = $this->getList($where, 'id'); + + return $addonsSoldList; + } + + /** + * Get Add-On Sold Detail + * + * @return array + */ + function getAddonSoldDetail($addonSoldID = false) + { + + if ($addonSoldID == false) { + + // Otherwise, we don't have an add-on id + return false; + + } + + // If the add-on sold ID is valid, get the detail + $addonSoldID = filter_input(INPUT_GET, 'AddonSoldID', FILTER_SANITIZE_NUMBER_INT); + if ($addonSoldID) { + $addonSoldDetail = $this->getEntry($addonSoldID); + + // Otherwise fail + } else { + return false; + } + + return $addonSoldDetail; + + } + + /** + * Check for other field related issues + * + * This function must be here because it's called from a function + * in dataAbstract. Simply return $r if there's nothing to check. + * + * @return array + */ + function checkOther($r) + { + parent::checkOther($r); + return $r; + } + +} + + + + +?> \ No newline at end of file diff --git a/classes/data/dataAddons.php b/classes/data/dataAddons.php new file mode 100644 index 0000000..bdf6e26 --- /dev/null +++ b/classes/data/dataAddons.php @@ -0,0 +1,416 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: dataAddons.php,v 1.0 2011/01/25 19:31:47 cscott Exp $ + * @link + */ + +require_once DATA_ABSTRACT; + +/** + * EventManagementDataAddons class + * + * PHP version 5 + * + * @category Data + * @package EventManagement + * @author Chuck Scott + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: dataAddons.php,v 1.0 2011/01/25 19:31:47 cscott Exp $ + * @link + */ +class EventManagementDataAddons extends DataAbstract +{ + /** + * Field definitions + * + * @var $ini + * @access public + */ + public $table = 'eventmgt.ticket_add_on'; + + /** + * Field definitions + * + * 'type' is type of field as defined by the application + * text Regular text field + * pointer Pointer to an entry in another table + * 'filters' is the filter name for a particular filter ID in PHP filter functions + * See PHP filter_id() + * + * 'use' is when to use the field + * l = List + * g = Get + * n = New + * i = Insert + * e = Edit + * u = Update + * d = Delete + * a = All + * + * @var $ini + * @access public + */ + public $fields = false; + + /** + * Constructor + * + * @param object $d database connection + * + * @return void + * @access public + */ + function __construct($dbh, $config) + { + + parent::__construct($dbh, $config); + + $this->fields = array( + + // Record ID + 'id' => array( + 'field' => 'id', + 'as' => false, + 'type' => 'integer', + 'required' => true, + 'unique' => true, + 'default' => false, + 'use' => 'lg' + ), + + // Ticket + 'ticket' => array( + 'field' => 'ticket', + 'as' => false, + 'type' => 'integer', + 'required' => false, + 'unique' => false, + 'default' => $_SESSION[GLM_EVENT_SESSION]['Ticket'], + 'use' => 'niegdl' + ), + + // Add-on Name + 'name' => array( + 'field' => 'name', + 'as' => false, + 'type' => 'text', + 'required' => true, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Description + 'descr' => array( + 'field' => 'descr', + 'as' => false, + 'type' => 'text', + 'filter' => FILTER_SANITIZE_MAGIC_QUOTES, + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Add-on type + 'add_on_type' => array( + 'field' => 'add_on_type', + 'as' => false, + 'type' => 'list', + 'list' => $this->config->ticket_add_on_type->toArray(), + 'required' => true, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Maximum quant (0 is unlimited) + 'max_quant' => array( + 'field' => 'max_quant', + 'as' => false, + 'type' => 'integer', + 'required' => false, + 'unique' => false, + 'default' => 0, + 'use' => 'a' + ), + + // Unit name + 'unit_name' => array( + 'field' => 'unit_name', + 'as' => false, + 'type' => 'text', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Unit cost + 'unit_cost_numb' => array( + 'field' => 'unit_cost', + 'as' => 'unit_cost_numb', + 'type' => 'float', + 'required' => false, + 'unique' => false, + 'default' => 0.00, + 'use' => 'a' + ), + + // Unit cost (money) + 'unit_cost' => array( + 'field' => 'unit_cost', + 'as' => false, + 'type' => 'money', + 'required' => false, + 'unique' => false, + 'default' => 0.00, + 'use' => 'lgd' + ) + + ); + + } + + /** + * Get Add-Ons list + * + * @return object containing array as sub-objects + */ + function getAddonsList($ticketID = false, $where = false) + { + + // If a where clause has not been supplied + if (!$where) { + + $where = 'true'; + + // Check if there's a ticket ID and filter by that ticket if there is + $ticketID = ($ticketID - 0); // Make sure it's number + if ($ticketID > 0) { + $where .= " AND T.ticket = $ticketID"; + } elseif ($_SESSION[GLM_EVENT_MGT_ADMIN]['Ticket'] > 0) { + $where .= " AND T.ticket = ".$_SESSION[GLM_EVENT_MGT_ADMIN]['Ticket']; + } + + } + + // Get list of Add-Ons + $addonsList = $this->getList($where, 'name'); + + return $addonsList; + } + + /** + * Get Add-On Detail + * + * @return array + */ + function getAddonDetail($addonID = false) + { + + // If a Add-On ID has been supplied + if ($addonID != false) { + + $_SESSION[GLM_EVENT_SESSION]['Addon'] = $addonID; + + } elseif (($addonID = filter_input(INPUT_GET, 'AddonID', FILTER_SANITIZE_NUMBER_INT))) { + + // Otherwise if there a new add-on ID supplied via the request + $_SESSION[GLM_EVENT_SESSION]['Addon'] = $addonID; + + } elseif (isset($_SESSION[GLM_EVENT_SESSION]['Addon'])) { + + // Otherwise, get the add-on ID from the session + $addonID = $_SESSION[GLM_EVENT_SESSION]['Addon']; + + } else { + + // Otherwise, we don't have an add-on id + return false; + + } + + $addonDetail = $this->getEntry($addonID); + + return $addonDetail; + + } + + + /** + * Edit Add-On + * + * @return array + */ + function editAddon() + { + + if (($addonID = filter_input(INPUT_GET, 'AddonID', FILTER_SANITIZE_NUMBER_INT))) { + + // If so then add it to the session + $_SESSION[GLM_EVENT_SESSION]['Addon'] = $addonID; + + } elseif (isset($_SESSION[GLM_EVENT_SESSION]['Addon'])) { + + // Otherwise, get the add-on ID from the session + $addonID = $_SESSION[GLM_EVENT_SESSION]['Addon']; + + } else { + + // Otherwise, we don't have a add-on id + return false; + + } + + $addonDetail = $this->editEntry($addonID); + + return $addonDetail; + + } + + /** + * Check for other field related issues + * + * This function must be here because it's called from a function + * in dataAbstract. Simply return $r if there's nothing to check. + * + * @return array + */ + function checkOther($r) + { + parent::checkOther($r); + return $r; + } + + /** + * Update Add-On + * + * @return array + */ + function updateAddon() + { + + if (($addonID = filter_input(INPUT_GET, 'AddonID', FILTER_SANITIZE_NUMBER_INT))) { + + // If so then add it to the session + $_SESSION[GLM_EVENT_SESSION]['Addon'] = $addonID; + + } elseif (isset($_SESSION[GLM_EVENT_SESSION]['Addon'])) { + + // Otherwise, get the add-on ID from the session + $addonID = $_SESSION[GLM_EVENT_SESSION]['Addon']; + + } else { + + // Otherwise, we don't have a state rep id + return false; + + } + + // Try to update this data + $r = $this->updateEntry($addonID); + + return $r; + + } + + + /** + * Add New Add-On + * + * @return array + */ + function newAddon() + { + + $r = $this->newEntry(); + + return $r; + + } + + /** + * Insert add-on + * + * @return array + */ + function insertAddon() + { + + $r = $this->insertEntry(); + + // If succesful then set current add-on to the one just inserted. + if ($r['status']) { + $_SESSION[GLM_EVENT_SESSION]['Addon'] = $r['insertedID']; + } + + return $r; + + } + + + /** + * Delete add-on + * + * @param $confirm bool False to ask if user wants to delete and true to actually delete + * + * @return array + */ + function addonDelete($confirm = false) + { + + // Is there a new add-on code selected? + if (($addonID = filter_input(INPUT_GET, 'AddonID', FILTER_SANITIZE_NUMBER_INT))) { + + // If so then add it to the session + $_SESSION[GLM_EVENT_SESSION]['Addon'] = $addonID; + + } elseif (isset($_SESSION[GLM_EVENT_SESSION]['Addon'])) { + + // Otherwise, get the add-on ID from the session + $addonID = $_SESSION[GLM_EVENT_SESSION]['Addon']; + + } else { + + // Otherwise, we don't have an add-on id + return false; + + } + + $addonDetail = $this->deleteEntry($addonID, $confirm); + + return $addonDetail; + + } + + /** + * Get Add-Ons Stats + * + * @return object containing array as sub-objects + */ + function getAddonsStats($where = 'true') + { + + $addonsStats = $this->getStats($where); + + return $addonsStats; + } + + + +} + + + + +?> \ No newline at end of file diff --git a/classes/data/dataAmenities.php b/classes/data/dataAmenities.php new file mode 100644 index 0000000..3f50b0f --- /dev/null +++ b/classes/data/dataAmenities.php @@ -0,0 +1,486 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: dataAmenities.php,v 1.0 2011/01/25 19:31:47 cscott Exp $ + * @link http://www.gaslightmedia.com/ + */ + +require_once DATA_ABSTRACT; + +/** + * EventManagementDataAmenities class + * + * PHP version 5 + * + * @category Data + * @package EventManagement + * @author Chuck Scott + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: dataAmenities.php,v 1.0 2011/01/25 19:31:47 cscott Exp $ + * @link http://www.gaslightmedia.com + */ +class EventManagementDataAmenities extends DataAbstract +{ + /** + * Field definitions + * + * @var $ini + * @access public + */ + public $table = 'eventmgt.amenities'; + + /** + * Field definitions + * + * 'type' is type of field as defined by the application + * text Regular text field + * pointer Pointer to an entry in another table + * 'filters' is the filter name for a particular filter ID in PHP filter functions + * See PHP filter_id() + * + * 'use' is when to use the field + * l = List + * g = Get + * n = New + * i = Insert + * e = Edit + * u = Update + * d = Delete + * a = All + * + * @var $ini + * @access public + */ + public $fields = false; + + /** + * Constructor + * + * @param object $d database connection + * + * @return void + * @access public + */ + function __construct($dbh, $config) + { + + parent::__construct($dbh, $config); + + $this->fields = array( + + // Record ID + 'id' => array( + 'field' => 'id', + 'as' => false, + 'type' => 'integer', + 'required' => true, + 'unique' => true, + 'default' => false, + 'use' => 'lg' + ), + + // Affiliation (insert) - what type of entities is this Amenity for + 'affiliation_type' => array( + 'field' => 'affiliation_type', + 'as' => false, + 'type' => 'integer', + 'required' => true, + 'unique' => false, + 'default' => false, + 'use' => 'i' + ), + + // Affiliation (view) + 'affiliation_type_2' => array( + 'field' => 'affiliation_type', + 'as' => false, + 'type' => 'list', + 'list' => $this->config->reference_type_numb->toArray(), + 'required' => false, + 'unique' => false, + 'default' => false, + 'view_only' => true, + 'use' => 'gled' + ), + + // Amenity affiliation (non-standard pointer) + // Points to various tables depending on the "Affiliation type" value + 'owner' => array( + 'field' => 'owner', + 'as' => false, + 'type' => 'integer', + 'required' => true, + 'unique' => false, + 'default' => false, + 'use' => 'i' + ), + + // Amenity affiliation (non-standard pointer) + // Points to various tables depending on the "Affiliation To" value + 'owner_2' => array( + 'field' => 'owner', + 'as' => false, + 'type' => 'integer', + 'required' => false, + 'unique' => false, + 'default' => false, + 'view_only' => true, + 'use' => 'gled' + ), + + // Amenity Name + 'name' => array( + 'field' => 'name', + 'as' => false, + 'type' => 'text', + 'required' => true, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Quantity / Size + 'quant' => array( + 'field' => 'quant', + 'as' => false, + 'type' => 'integer', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Amenity Description + 'descr' => array( + 'field' => 'descr', + 'as' => false, + 'type' => 'text', + 'filter' => FILTER_SANITIZE_MAGIC_QUOTES, + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ) + + ); + } + + /** + * Get an array of Amenities for a particular affiliated entity + * + * $listOption Optional Type of affiliation - see config.ini 'reference_type' + * If not supplied will check for AmenitiesListOption GET value + * $whereRequest If supplied, use as WHERE clause instead + * + * @return object containing array as sub-objects + */ + function getAmenities($listOption = false, $whereRequest = false) + { + + $where = ''; + + // If there's a specific whereRequest, use that only + if ($whereRequest) { + $where = $whereRequest; + } else { + + // Get Event ID from session - if available + $eventID = $_SESSION[GLM_EVENT_SESSION]['Event']; + + // Get Member ID from session - if available + $memberID = $_SESSION[GLM_EVENT_SESSION]['Member']; + + // Get any specified listing option + if ($listOption != '') { + $option = $listOption; + + // Otheriwse check for list options provided in request + } elseif (($AmenitiesListOption = filter_input(INPUT_GET, 'AmenitiesListOption', FILTER_SANITIZE_STRING))) { + $option = $AmenitiesListOption; + } + + // Include selection of proper affiliation type + switch ($option) { + case 'member': + if ($memberID) { + $where .= "T.affiliation_type = ".$this->config->reference_type->property + ."AND owner = $memberID\n"; + } else { + $where .= "false"; + } + break; + } + } + + // Get the Amenities - return false if none found + $amenitiesList = $this->getList($where, 'name'); + if (!is_array($amenitiesList) || count($amenitiesList) == 0) { + return false; + } + + // Get affiliation type for each Amenity + reset($amenitiesList); + while( list($key, $val) = each( $amenitiesList ) ) { + + $aData = $this->getAffiliate( + $val['affiliation_type']['value'], + $val['owner'] + ); + + if ($aData) { + $amenitiesList[$key]['affiliation_type_name'] = $aData['applied_to_name']; + $amenitiesList[$key]['owner_name'] = $aData['owner_name']; + } + + } // Get Amenities affiliation + + return $amenitiesList; + } + + /** + * Get Amenity Detail + * + * @return array + */ + function getAmenityDetail() + { + + // Is there a new Amenity ID supplied? + if (!($amenityID = filter_input(INPUT_GET, 'AmenityID', FILTER_SANITIZE_NUMBER_INT))) { + // We don't have an amenity id + return false; + + } + + $amenityDetail = $this->getEntry($amenityID); + + // Get owner data + $aData = $this->getAffiliate( + $amenityDetail['affiliation_type']['value'], + $amenityDetail['owner'] + ); + + + if ($aData) { + $amenityDetail = array_merge($amenityDetail, $aData); + } + + return $amenityDetail; + + } + + /** + * Edit Amenity + * + * @return array + */ + function editAmenity() + { + + // Is there a new amenity ID supplied? + if (!($amenityID = filter_input(INPUT_GET, 'AmenityID', FILTER_SANITIZE_NUMBER_INT))) { + // We don't have an amenity id + return false; + + } + + $amenityDetail = $this->editEntry($amenityID); + + // Get owner data + $aData = $this->getAffiliate( + $amenityDetail['affiliation_type']['value'], + $amenityDetail['owner'] + ); + + if ($aData) { + $amenityDetail = array_merge($amenityDetail, $aData); + } + + return $amenityDetail; + + } + + /** + * Update Amenity + * + * @return array + */ + function updateAmenity() + { + + // Is there a new amenity ID supplied? + if (!($amenityID = filter_input(INPUT_GET, 'AmenityID', FILTER_SANITIZE_NUMBER_INT))) { + if (!($amenityID = filter_input(INPUT_POST, 'AmenityID', FILTER_SANITIZE_NUMBER_INT))) { + echo "::::::"; + // We don't have an Amenity id + return false; + } + } + + // Try to update this data + $r = $this->updateEntry($amenityID); + + // Get owner data + $aData = $this->getAffiliate( + $amenityDetail['affiliation_type']['value'], + $amenityDetail['owner'] + ); + + if ($aData) { + $amenityDetail = array_merge($amenityDetail, $aData); + } + + return $r; + + } + + /** + * New Amenity Affiliation + * + * @return array + */ + function newAmenityAffiliation($r) + { + + // Check for specified Amenity type + // We need to check for name rather than number because that's what the js is sending us + if (!isset($_REQUEST['amenity_type_code']) || $_REQUEST['amenity_type_code'] == '') { + return false; + } + + // Get type and affiliation + $amenityType = trim($_REQUEST['amenity_type_code']); + $affiliateID = false; + + switch ($amenityType) { + case 'property': + $amenityTypeNumber = $this->config->reference_type->property; + if (isset($_SESSION[GLM_EVENT_SESSION]['Member'])) { + $affiliateID = ($_SESSION[GLM_EVENT_SESSION]['Member'] - 0); + $amenityTypeName = 'Property'; + $aTable = 'eventmgt.member'; + $aField = 'name'; + $aFieldShort = $aField; + } + break; + } + + // If no match on Amenity type, then fail + if ($affiliateID == false) { + return false; + } + + // Get affiliate data + $sql = "SELECT $aField AS name, + $aFieldShort AS short_name + FROM $aTable + WHERE id = $affiliateID + ;"; + + $stmt = $this->dbh->prepare($sql); + $stmt->execute(); + $aData = $stmt->fetch(PDO::FETCH_ASSOC); + + // if no valid affiliate data - fail + if (!$aData) { + return false; + } + + $r['fieldData']['amenity_type_name'] = $amenityTypeName; + $r['fieldData']['amenity_type_code'] = $amenityType; + $r['fieldData']['amenity_type'] = $amenityTypeNumber; + $r['fieldData']['affiliation_name'] = $aData['name']; + $r['fieldData']['affiliation'] = $affiliateID; + $r['fieldData']['affiliation_short'] = $aData['short_name']; + + return $r; + + } + + function newAmenity() + { + + $r = $this->newEntry(); + + $r = $this->newAmenityAffiliation($r); + + // echo "
".print_r($r,1)."
"; + return $r; + + } + + + /** + * Insert Amenity + * + * @return array + */ + function insertAmenity() + { + + $r = $this->insertEntry(); + $r = $this->newAmenityAffiliation($r); + + // echo "
".print_r($r,1)."
"; + return $r; + + } + + /** + * Get Affiliate table and name + * + */ + function getAffiliate($type, $affiliation) + { + + // Deterimine Affliate table + $aTable = ''; + $aField = ''; + switch ($type) { + case $this->config->reference_type->property: + $aType = 'Property'; + $aTable = 'eventmgt.member'; + $aField = 'name'; + $aFieldShort = $aField; + break; + } + + $r = false; + + // If we have a good affiliate relationship + if ($aField != '') { + + $sql = "SELECT $aField AS name, + $aFieldShort AS short_name + FROM $aTable + WHERE id = $affiliation + ;"; + + $stmt = $this->dbh->prepare($sql); + $stmt->execute(); + $aData = $stmt->fetch(PDO::FETCH_ASSOC); + + if ($aData) { + $r = array( + 'amenity_type_name' => $aType, + 'affiliation_name' => $aData['name'], + 'affiliation_short' => $aData['short_name'] + ); + } + } + + return $r; + + } + +} + +?> \ No newline at end of file diff --git a/classes/data/dataAttendance.php b/classes/data/dataAttendance.php new file mode 100644 index 0000000..e76331d --- /dev/null +++ b/classes/data/dataAttendance.php @@ -0,0 +1,218 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: dataAttendance.php,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +require_once DATA_ABSTRACT; + +/** + * EventManagementDataAttendance class + * + * PHP version 5 + * + * @category Data + * @package EventManagement + * @author Chuck Scott + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: dataAttendance,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ +class EventManagementDataAttendance extends DataAbstract +{ + /** + * Tables + * + * @var $ini + * @access public + */ + public $table = 'eventmgt.attendance'; + + /** + * Field definitions + * + * 'type' is type of field as defined by the application + * text Regular text field + * pointer Pointer to an entry in another table + * 'filters' is the filter name for a particular filter ID in PHP filter functions + * See PHP filter_id() + * + * 'use' is when to use the field + * l = List + * g = Get + * n = New + * i = Insert + * e = Edit + * u = Update + * d = Delete + * a = All + * + * @var $ini + * @access public + */ + public $fields = false; + + /** + * Constructor + * + * @param object $d database connection + * + * @return void + * @access public + */ + function __construct($dbh, $config) + { + + parent::__construct($dbh, $config); + + $this->fields = array( + + // Record ID + 'id' => array( + 'field' => 'id', + 'as' => false, + 'type' => 'integer', + 'required' => true, + 'unique' => true, + 'default' => false, + 'use' => 'lged' + ), + + // Member ID for adding an entry + 'member' => array( + 'field' => 'member', + 'as' => false, + 'type' => 'pointer', + 'p_table' => 'eventmgt.member', + 'p_field' => 'name', + 'p_id' => 'id', + 'p_static' => true, + 'required' => true, + 'unique' => false, + 'default' => $_SESSION[GLM_EVENT_SESSION]['Member'], + 'use' => 'nid' + ), + + // Member ID + 'member_id' => array( + 'field' => 'member', + 'as' => 'member_id', + 'type' => 'integer', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'gle' + ), + + // Attendance record name + 'name' => array( + 'field' => 'name', + 'as' => false, + 'type' => 'text', + 'required' => true, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Attendance notes + 'notes' => array( + 'field' => 'notes', + 'as' => false, + 'type' => 'text', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Date + 'attendance_date' => array( + 'field' => 'attendance_date', + 'as' => false, + 'type' => 'date', + 'required' => false, + 'unique' => false, + 'default' => time(), + 'use' => 'a' + ), + + // Actual attendance entrance state time + 'entrance_start_time' => array( + 'field' => 'entrance_start_time', + 'as' => false, + 'type' => 'time', + 't_detailed_minutes' => true, + 'required' => false, + 'unique' => false, + 'default' => date('H:i'), + 'use' => 'a' + ), + + // Actual attendance entrance end time + 'entrance_end_time' => array( + 'field' => 'entrance_end_time', + 'as' => false, + 'type' => 'time', + 't_detailed_minutes' => true, + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Actual performance start time + 'perf_start_time' => array( + 'field' => 'perf_start_time', + 'as' => false, + 'type' => 'time', + 't_detailed_minutes' => true, + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Actual performance end time + 'perf_end_time' => array( + 'field' => 'perf_end_time', + 'as' => false, + 'type' => 'time', + 't_detailed_minutes' => true, + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ) + + ); + } + + /** + * Check for other field related issues + * + * Simply return $r if there's nothing to check. + * + * @return array + */ + function checkOther($r) + { + parent::checkOther($r); + + return $r; + } + + +} + + + + +?> \ No newline at end of file diff --git a/classes/data/dataBookings.php b/classes/data/dataBookings.php new file mode 100644 index 0000000..c613207 --- /dev/null +++ b/classes/data/dataBookings.php @@ -0,0 +1,252 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: dataBookings.php,v 1.0 2011/01/25 19:31:47 cscott Exp $ + * @link http://www.gaslightmedia.com/ + */ + +require_once DATA_ABSTRACT; + +/** + * EventManagementDataBookings class + * + * PHP version 5 + * + * @category Data + * @package EventManagement + * @author Chuck Scott + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: dataBookings.php,v 1.0 2011/01/25 19:31:47 cscott Exp $ + * @link http://www.gaslightmedia.com + */ +class EventManagementDataBookings extends DataAbstract +{ + /** + * Field definitions + * + * @var $ini + * @access public + */ + public $table = 'eventmgt.team_property'; + + /** + * Field definitions + * + * 'type' is type of field as defined by the application + * text Regular text field + * pointer Pointer to an entry in another table + * 'filters' is the filter name for a particular filter ID in PHP filter functions + * See PHP filter_id() + * + * 'use' is when to use the field + * l = List + * g = Get + * n = New + * i = Insert + * e = Edit + * u = Update + * d = Delete + * a = All + * + * @var $ini + * @access public + */ + public $fields = false; + + /** + * Constructor + * + * @param object $d database connection + * + * @return void + * @access public + */ + function __construct($dbh, $config) + { + + parent::__construct($dbh, $config); + + $this->fields = array( + + // Record ID + 'id' => array( + 'field' => 'id', + 'as' => false, + 'type' => 'integer', + 'required' => true, + 'unique' => true, + 'default' => false, + 'use' => 'a' + ), + + // Team + 'team' => array( + 'field' => 'team', + 'as' => 'team', + 'type' => 'pointer', + 'p_table' => 'eventmgt.team', + 'p_field' => 'name', + 'p_id' => 'id', + 'required' => true, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Property + 'property' => array( + 'field' => 'property', + 'as' => 'property', + 'type' => 'pointer', + 'p_table' => 'eventmgt.member', + 'p_field' => 'name', + 'p_id' => 'id', + 'required' => true, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Event + 'conv' => array( + 'field' => 'conv', + 'as' => 'event', + 'type' => 'pointer', + 'p_table' => 'eventmgt.event', + 'p_field' => 'name', + 'p_id' => 'id', + 'required' => true, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Start Date + 'start' => array( + 'field' => 'start', + 'as' => false, + 'type' => 'date', + 'required' => true, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Stop Date + 'stop' => array( + 'field' => 'stop', + 'as' => false, + 'type' => 'date', + 'required' => true, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ) + + ); + } + + /** + * Get Bookings list + * + * @return object containing array as sub-objects + */ + function getBookingsList() + { + + // Get event ID from session - if available + $eventID = $_SESSION[GLM_EVENT_SESSION]['Event']; + + // Get member ID from session - if available + $memberID = $_SESSION[GLM_EVENT_SESSION]['Member']; + + // Get team ID from session - if available + $teamID = $_SESSION[GLM_EVENT_SESSION]['Team']; + + // Get any specified bookings listing option - default to event + $option = 'event'; + if (($bookingsListOption = filter_input(INPUT_GET, 'BookingsListOption', FILTER_SANITIZE_STRING))) { + $option = $bookingsListOption; + } + + // Select type of list + $where = ''; + switch ($option) { + case 'all': + $where = 'TRUE'; + break; + case 'event': + if (!$eventID) { + return false; + } + $where = "T.conv = $eventID"; + break; + case 'member': + if (!$memberID) { + return false; + } + $where = "T.property = $memberID"; + break; + case 'team': + if (!$teamID) { + return false; + } + $where = "T.team = $teamID"; + break; + default: + echo "Option not set"; + break; + } + + // Get list of Bookings + $bookingsList = $this->getList($where); + + return $bookingsList; + } + + /** + * Get Booking Detail + * + * @return array + */ + function getBookingDetail() + { + + // Is there a new team code selected? + if (($bookingID = filter_input(INPUT_GET, 'BookingID', FILTER_SANITIZE_NUMBER_INT))) { + + // If so then add it to the session + $_SESSION[GLM_EVENT_SESSION]['Booking'] = $teamID; + + } elseif (isset($_SESSION[GLM_EVENT_SESSION]['Booking'])) { + + // Otherwise, get the booking ID from the session + $bookingID = $_SESSION[GLM_EVENT_SESSION]['Booking']; + + } else { + + // Otherwise, we don't have a booking id + return false; + + } + + $bookingDetail = $this->getEntry($bookingID); + + return $bookingDetail; + + } + +} + + + + +?> \ No newline at end of file diff --git a/classes/data/dataContacts.php b/classes/data/dataContacts.php new file mode 100644 index 0000000..de1ba1b --- /dev/null +++ b/classes/data/dataContacts.php @@ -0,0 +1,862 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: dataContacts.php,v 1.0 2011/01/25 19:31:47 cscott Exp $ + * @link http://www.gaslightmedia.com/ + */ + +require_once DATA_ABSTRACT; + +/** + * EventManagementDataContacts class + * + * PHP version 5 + * + * @category Data + * @package EventManagement + * @author Chuck Scott + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: dataContacts.php,v 1.0 2011/01/25 19:31:47 cscott Exp $ + * @link http://www.gaslightmedia.com + */ +class EventManagementDataContacts extends DataAbstract +{ + /** + * Field definitions + * + * @var $ini + * @access public + */ + public $table = 'eventmgt.res_contact'; + + /** + * Field definitions + * + * 'type' is type of field as defined by the application + * text Regular text field + * pointer Pointer to an entry in another table + * 'filters' is the filter name for a particular filter ID in PHP filter functions + * See PHP filter_id() + * + * 'use' is when to use the field + * l = List + * g = Get + * n = New + * i = Insert + * e = Edit + * u = Update + * d = Delete + * a = All + * + * @var $ini + * @access public + */ + public $fields = false; + + /** + * Delete restrictions + * + * @var $ini + * @access public + */ + public $delRestrictions = false; + + /** + * Constructor + * + * @param object $d database connection + * + * @return void + * @access public + */ + function __construct($dbh, $config) + { + + parent::__construct($dbh, $config); + + // Define fields for this data table + $this->fields = array( + + // Record ID + 'id' => array( + 'field' => 'id', + 'as' => false, + 'type' => 'integer', + 'required' => true, + 'unique' => true, + 'default' => false, + 'use' => 'lg' + ), + + // Contact Type + 'contact_type' => array( + 'field' => 'contact_type', + 'as' => false, + 'type' => 'integer', + 'required' => true, + 'unique' => false, + 'default' => false, + 'use' => 'i' + ), + + // Contact Type + 'contact_type_2' => array( + 'field' => 'contact_type', + 'as' => false, + 'type' => 'list', + 'list' => $this->config->reference_type_numb->toArray(), + 'required' => false, + 'unique' => false, + 'default' => false, + 'view_only' => true, + 'use' => 'gled' + ), + + // Contact affiliation (non-standard pointer) + // Points to various tables depending on the Contact Type + 'affiliation' => array( + 'field' => 'affiliation', + 'as' => false, + 'type' => 'integer', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'i' + ), + + // Contact affiliation (non-standard pointer) + // Points to various tables depending on the Contact Type + 'affiliation_2' => array( + 'field' => 'affiliation', + 'as' => false, + 'type' => 'integer', + 'required' => false, + 'unique' => false, + 'default' => false, + 'view_only' => true, + 'use' => 'gled' + ), + + // Contact First Name + 'fname' => array( + 'field' => 'fname', + 'as' => false, + 'type' => 'text', + 'required' => true, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Contact Last Name + 'lname' => array( + 'field' => 'lname', + 'as' => false, + 'type' => 'text', + 'required' => true, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Organization + 'org' => array( + 'field' => 'org', + 'as' => false, + 'type' => 'text', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Contact Address Line 1 + 'addr1' => array( + 'field' => 'addr1', + 'as' => false, + 'type' => 'text', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Contact Address Line 2 + 'addr2' => array( + 'field' => 'addr2', + 'as' => false, + 'type' => 'text', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Contact City + 'city' => array( + 'field' => 'city', + 'as' => false, + 'type' => 'text', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Contact State + 'state' => array( + 'field' => 'state', + 'as' => false, + 'type' => 'list', + 'list' => $this->config->states->toArray(), + 'required' => false, + 'unique' => false, + 'default' => 'MI', + 'use' => 'a' + ), + + // Contact Country + 'country' => array( + 'field' => 'country', + 'as' => false, + 'type' => 'list', + 'list' => $this->config->countries->toArray(), + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Contact ZIP + 'zip' => array( + 'field' => 'zip', + 'as' => false, + 'type' => 'text', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Office Phone + 'office_phone' => array( + 'field' => 'office_phone', + 'as' => false, + 'type' => 'text', + 'required' => true, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Contact Mobile Phone + 'mobile_phone' => array( + 'field' => 'mobile_phone', + 'as' => false, + 'type' => 'text', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Alternate Phone + 'alt_phone' => array( + 'field' => 'alt_phone', + 'as' => false, + 'type' => 'text', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // FAX + 'fax' => array( + 'field' => 'fax', + 'as' => false, + 'type' => 'text', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // E-Mail + 'email' => array( + 'field' => 'email', + 'as' => false, + 'type' => 'text', + 'required' => true, + 'unique' => true, + 'default' => false, + 'use' => 'a' + ), + + // Optional Login ID + 'login_id' => array( + 'field' => 'login_id', + 'as' => false, + 'type' => 'text', + 'required' => false, + 'unique' => true, + 'default' => false, + 'use' => 'a' + ), + + // Alternate E-Mail + 'alt_email' => array( + 'field' => 'alt_email', + 'as' => false, + 'type' => 'text', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Contact Image + 'image' => array( + 'field' => 'image', + 'as' => false, + 'type' => 'image', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Contact notes + 'notes' => array( + 'field' => 'notes', + 'as' => false, + 'type' => 'text', + 'filter' => FILTER_SANITIZE_MAGIC_QUOTES, + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Contact create_date + 'create_date' => array( + 'field' => 'create_date', + 'as' => false, + 'type' => 'date', + 'required' => false, + 'unique' => false, + 'default' => time(), + 'use' => 'a' + ), + + // Active flag + 'active' => array( + 'field' => 'active', + 'as' => false, + 'type' => 'checkbox', + 'required' => false, + 'unique' => false, + 'default' => true, + 'use' => 'a' + ), + + // Password - encrypted + 'password' => array( + 'field' => 'password', + 'as' => false, + 'type' => 'password', + 'pw_type' => 'strong', + 'required' => false, + 'unique' => false, + 'default' => false, + 'minLength' => 8, + 'maxLength' => 16, + 'no_update_when_blank' => true, + 'use' => 'a' + ), + + // User Rights + 'user_rights' => array( + 'field' => 'user_rights', + 'as' => false, + 'type' => 'list', + 'list' => $this->config->permissions->toArray(), + 'required' => false, + 'unique' => false, + 'default' => 0, // Note that this is a bitmap value + 'use' => 'a' + ) + + ); + + // Specify any delete restrictions + $this->delRestrictions = false; + + } + + /** + * Get an array of contacts for a particular affiliated entity + * + * $listOption Optional Type of affiliation - see config.ini 'reference_type' + * If not supplied will check for ContactsListOption GET value + * $whereRequest If supplied, use as WHERE clause instead + * + * @return object containing array as sub-objects + */ + function getContacts($listOption = false, $whereRequest = false) + { + + $where = ''; + + // If there's a specific whereRequest, use that only + if ($whereRequest) { + $where = $whereRequest; + } else { + + // Get Event ID from session - if available + $eventID = $_SESSION[GLM_EVENT_SESSION]['Event']; + + // Get Member ID from session - if available + $memberID = $_SESSION[GLM_EVENT_SESSION]['Member']; + + // Get State ID from session - if available + $stateID = $_SESSION[GLM_EVENT_SESSION]['State']; + + // Get team ID from session - if available + $teamID = $_SESSION[GLM_EVENT_SESSION]['Team']; + + // Get any specified event listing option - default to active + if ($listOption != '') { + $option = $listOption; + + // Otheriwse check for list options provided in request + } elseif (($contactsListOption = filter_input(INPUT_GET, 'ContactsListOption', FILTER_SANITIZE_STRING))) { + $option = $contactsListOption; + } + + // Include selection of proper contact type + switch ($option) { + case 'event': + if ($eventID) { + $where .= "T.contact_type = ".$this->config->reference_type->event + ."AND affiliation = $eventID"; + } else { + $where .= "false"; + } + break; + case 'member': + if ($memberID) { + $where .= "T.contact_type = ".$this->config->reference_type->member + ."AND affiliation = $memberID\n"; + } else { + $where .= "false"; + } + break; + case 'state': + if ($stateID) { + $where .= "T.contact_type = ".$this->config->reference_type->state + ."AND affiliation = $stateID\n"; + } else { + $where .= "false"; + } + break; + case 'team': + if ($teamID) { + $where .= "T.contact_type = ".$this->config->reference_type->team + ."AND affiliation = $teamID\n"; + } else { + $where .= "false"; + } + break; + } + + } + + // Get the contacts - return false if none found + $contactsList = $this->getList($where, 'org, lname, fname'); + if (!is_array($contactsList) || count($contactsList) == 0) { + return false; + } + + // Get contact affiliation for each contact + reset($contactsList); + while( list($key, $val) = each( $contactsList ) ) { + + $aData = $this->getAffiliate( + $val['contact_type']['value'], + $val['affiliation'] + ); + + if ($aData) { + $contactsList[$key]['contact_type_name'] = $aData['contact_type_name']; + $contactsList[$key]['affiliation'] = $aData['affiliation_name']; + $contactsList[$key]['affiliation_short'] = $aData['affiliation_short']; + } + + } // Get contact affiliation + + $r = array( + 'contact_list' => $contactsList, + 'type' => $t + ); + + return $r; + } + + /** + * Get Contact Detail + * + * @return array + */ + function getContactDetail($contactID = false) + { + + // If a contact ID is supplied + if ($contactID) { + // nothing to do here + + // Is there a new event code selected? + } elseif (($contactID = filter_input(INPUT_GET, 'ContactID', FILTER_SANITIZE_NUMBER_INT))) { + + // If so then add it to the session + $_SESSION[GLM_EVENT_SESSION]['Contact'] = $contactID; + + } elseif (isset($_SESSION[GLM_EVENT_SESSION]['Contact'])) { + + // Otherwise, get the contact ID from the session + $contactID = $_SESSION[GLM_EVENT_SESSION]['Contact']; + + } else { + + // Otherwise, we don't have an contact id + return false; + + } + + $contactDetail = $this->getEntry($contactID); + + // Get affiliate data + $aData = $this->getAffiliate( + $contactDetail['contact_type']['value'], + $contactDetail['affiliation'] + ); + if ($aData) { + $contactDetail = array_merge($contactDetail, $aData); + } + + return $contactDetail; + + } + + + /** + * Edit Contact + * + * @return array + */ + function editContact() + { + + // Check for contact ID in session + if (isset($_SESSION[GLM_EVENT_SESSION]['Contact'])) { + $contactID = $_SESSION[GLM_EVENT_SESSION]['Contact']; + } else { + return false; + } + + $contactDetail = $this->editEntry($contactID); + + // Get affiliate data + $aData = $this->getAffiliate( + $contactDetail['contact_type']['value'], + $contactDetail['affiliation'] + ); + if ($aData) { + $contactDetail = array_merge($contactDetail, $aData); + } + + return $contactDetail; + + } + + /** + * Update Contact + * + * @return array + */ + function updateContact() + { + + // Check for contact ID in session + if (isset($_SESSION[GLM_EVENT_SESSION]['Contact'])) { + $contactID = $_SESSION[GLM_EVENT_SESSION]['Contact']; + } else { + return false; + } + + // Try to update this data + $r = $this->updateEntry($contactID); + + // Get affiliate data + $aData = $this->getAffiliate( + $r['fieldData']['contact_type']['value'], + $r['fieldData']['affiliation'] + ); + + if ($aData) { + $r['fieldData'] = array_merge($r['fieldData'], $aData); + } + + + return $r; + + } + + /** + * New Contact + * + * @return array + */ + function newContactAffiliation($r) + { + + // Check for specified contact type + // We need to check for name rather than number because that's what the js is sending us + if (!isset($_REQUEST['contact_type_code']) || $_REQUEST['contact_type_code'] == '') { + + $this->addDebug("dataContacts.inc", 'newContactAffiliation()', 'No contact_type_code supplied.'); + + return false; + } + + // Get type and affiliation + $contactType = trim($_REQUEST['contact_type_code']); + $affiliateID = false; + + switch ($contactType) { + case 'event': + $contactTypeNumber = $this->config->reference_type->event; + if (isset($_SESSION[GLM_EVENT_SESSION]['Event'])) { + $affiliateID = ($_SESSION[GLM_EVENT_SESSION]['Event'] - 0); + $contactTypeName = $this->config->reference_type_numb->$contactTypeNumber; + $aTable = 'event'; + $aField = 'name'; + $aFieldShort = 'event_code'; + } + break; + case 'member': + $contactTypeNumber = $this->config->reference_type->member; + if (isset($_SESSION[GLM_EVENT_SESSION]['Member'])) { + $affiliateID = ($_SESSION[GLM_EVENT_SESSION]['Member'] - 0); + $contactTypeName = $this->config->reference_type_numb->$contactTypeNumber; + $aTable = 'eventmgt.member'; + $aField = 'name'; + $aFieldShort = $aField; + } + break; + case 'state': + $contactTypeNumber = $this->config->reference_type->state; + if (isset($_SESSION[GLM_EVENT_SESSION]['State'])) { + $affiliateID = ($_SESSION[GLM_EVENT_SESSION]['State'] - 0); + $contactTypeName = $this->config->reference_type_numb->$contactTypeNumber; + $aTable = 'state_rep'; + $aField = 'code'; + $aFieldShort = $aField; + } + break; + case 'team': + $contactTypeNumber = $this->config->reference_type->team; + if (isset($_SESSION[GLM_EVENT_SESSION]['Team'])) { + $affiliateID = ($_SESSION[GLM_EVENT_SESSION]['Team'] - 0); + $contactTypeName = $this->config->reference_type_numb->$contactTypeNumber; + $aTable = 'team'; + $aField = 'name'; + $aFieldShort = 'team_code'; + } + break; + } + + // If no match on contact type, then fail + if ($affiliateID == false) { + return false; + } + + // Get affiliate data + $sql = "SELECT $aField AS name, + $aFieldShort AS short_name + FROM $aTable + WHERE id = $affiliateID + ;"; + + $stmt = $this->dbh->prepare($sql); + $stmt->execute(); + $aData = $stmt->fetch(PDO::FETCH_ASSOC); + + // if no valid affiliate data - fail + if (!$aData) { + return false; + } + + $r['fieldData']['contact_type_name'] = $contactTypeName; + $r['fieldData']['contact_type_code'] = $contactType; + $r['fieldData']['contact_type'] = $contactTypeNumber; + $r['fieldData']['affiliation_name'] = $aData['name']; + $r['fieldData']['affiliation'] = $affiliateID; + $r['fieldData']['affiliation_short'] = $aData['short_name']; + + return $r; + + } + function newContact() + { + + $r = $this->newEntry(); + $r = $this->newContactAffiliation($r); + + return $r; + + } + + + /** + * Insert Contact + * + * @return array + */ + function insertContact() + { + + $r = $this->insertEntry(); + $r = $this->newContactAffiliation($r); + + // If succesful then set current contact to the one just inserted. + if ($r['status']) { + $_SESSION[GLM_EVENT_SESSION]['Contact'] = $r['insertedID']; + } + + return $r; + + } + + /** + * Get Affiliate table and name + * + */ + function getAffiliate($type, $affiliation) + { + + // Deterimine Affliate table + $aTable = ''; + $aField = ''; + switch ($type) { + case $this->config->reference_type->event: + $aType = 'Event'; + $aTable = 'event'; + $aField = 'name'; + $aFieldShort = 'event_code'; + break; + case $this->config->reference_type->member: + $aType = 'Member'; + $aTable = 'eventmgt.member'; + $aField = 'name'; + $aFieldShort = $aField; + break; + case $this->config->reference_type->state: + $aType = 'State Rep'; + $aTable = 'state_rep'; + $aField = 'code'; + $aFieldShort = $aField; + break; + case $this->config->reference_type->team: + $aType = 'Team'; + $aTable = 'team'; + $aField = 'name'; + $aFieldShort = 'team_code'; + break; + } + + $r = false; + + // If we have a good affiliate relationship + if ($aField != '') { + + $sql = "SELECT $aField AS name, + $aFieldShort AS short_name + FROM $aTable + WHERE id = $affiliation + ;"; + + $stmt = $this->dbh->prepare($sql); + $stmt->execute(); + $aData = $stmt->fetch(PDO::FETCH_ASSOC); + + if ($aData) { + $r = array( + 'contact_type_name' => $aType, + 'affiliation_name' => $aData['name'], + 'affiliation_short' => $aData['short_name'] + ); + } + } + + return $r; + + } + + + /** + * Delete Contact + * + * @param $confirm bool False to ask if user wants to delete and true to actually delete + * + * @return array + */ + function contactDelete($confirm = false) + { + + // Is there a new contact code selected? + if (($contactID = filter_input(INPUT_GET, 'ContactID', FILTER_SANITIZE_NUMBER_INT))) { + + // If so then add it to the session + $_SESSION[GLM_EVENT_SESSION]['Contact'] = $contactID; + + } elseif (isset($_SESSION[GLM_EVENT_SESSION]['Contact'])) { + + // Otherwise, get the contact ID from the session + $contactID = $_SESSION[GLM_EVENT_SESSION]['Contact']; + + } else { + + // Otherwise, we don't have an contact id + return false; + + } + + $contactDetail = $this->deleteEntry($contactID, $confirm); + + // Get affiliate data + $aData = $this->getAffiliate( + $contactDetail['contact_type']['value'], + $contactDetail['affiliation'] + ); + if ($aData) { + $contactDetail = array_merge($contactDetail, $aData); + } + + return $contactDetail; + + } + + + +} + +?> \ No newline at end of file diff --git a/classes/data/dataDivisions.php b/classes/data/dataDivisions.php new file mode 100644 index 0000000..fb4aaa9 --- /dev/null +++ b/classes/data/dataDivisions.php @@ -0,0 +1,353 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: dataDivisions.php,v 1.0 2011/01/25 19:31:47 cscott Exp $ + * @link http://www.gaslightmedia.com/ + */ + +require_once DATA_ABSTRACT; + +/** + * EventManagementDataDivisions class + * + * PHP version 5 + * + * @category Data + * @package EventManagement + * @author Chuck Scott + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: dataDivisions.php,v 1.0 2011/01/25 19:31:47 cscott Exp $ + * @link http://www.gaslightmedia.com + */ +class EventManagementDataDivisions extends DataAbstract +{ + /** + * Field definitions + * + * @var $ini + * @access public + */ + public $table = 'eventmgt.division'; + + /** + * Field definitions + * + * 'type' is type of field as defined by the application + * text Regular text field + * pointer Pointer to an entry in another table + * 'filters' is the filter name for a particular filter ID in PHP filter functions + * See PHP filter_id() + * + * 'use' is when to use the field + * l = List + * g = Get + * n = New + * i = Insert + * e = Edit + * u = Update + * d = Delete + * a = All + * + * @var $ini + * @access public + */ + public $fields = false; + + /** + * Constructor + * + * @param object $d database connection + * + * @return void + * @access public + */ + function __construct($dbh, $config) + { + + parent::__construct($dbh, $config); + + $this->fields = array( + + // Record ID + 'id' => array( + 'field' => 'id', + 'as' => false, + 'type' => 'integer', + 'required' => true, + 'unique' => true, + 'default' => false, + 'use' => 'lg' + ), + + // Event selection + 'conv' => array( + 'field' => 'conv', + 'as' => 'event_name', + 'type' => 'pointer', + 'p_table' => 'eventmgt.event', + 'p_field' => 'name', + 'p_id' => 'id', + 'p_static' => true, + 'required' => true, + 'unique' => false, + 'default' => false, + 'use' => 'nid' + ), + + // Event Name display + 'conv_view' => array( + 'field' => 'conv', + 'as' => 'event_name', + 'type' => 'pointer', + 'p_table' => 'eventmgt.event', + 'p_field' => 'name', + 'p_id' => 'id', + 'p_static' => true, + 'required' => true, + 'unique' => false, + 'default' => false, + 'view_only' => true, + 'use' => 'gleu' + ), + + // Division Name + 'name' => array( + 'field' => 'name', + 'as' => false, + 'type' => 'text', + 'required' => true, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Description + 'descr' => array( + 'field' => 'descr', + 'as' => false, + 'type' => 'text', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Notes + 'notes' => array( + 'field' => 'notes', + 'as' => false, + 'type' => 'text', + 'filter' => FILTER_SANITIZE_MAGIC_QUOTES, + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ) + + ); + } + + /** + * Get Divisions list + * + * @return object containing array as sub-objects + */ + function getDivisionsList() + { + + // Get event ID from session - if available + $eventID = $_SESSION[GLM_EVENT_SESSION]['Event']; + + // Get any specified division listing option - default to event + $option = 'event'; + if (($divisionsListOption = filter_input(INPUT_GET, 'DivisionsListOption', FILTER_SANITIZE_STRING))) { + $option = $divisionsListOption; + } + + // Select type of list + $where = ''; + switch ($option) { + case 'all': + $where = 'TRUE'; + break; + case 'event': + if (!$eventID) { + return false; + } + $where = "T.conv = $eventID"; + break; + default: + echo "Option not set"; + break; + } + + // Get list of Divisions + $divisionsList = $this->getList($where, 'name'); + + return $divisionsList; + } + + /** + * Get State Division + * + * @return array + */ + function getDivisionDetail() + { + + // Is there a new Division code selected? + if (($divisionID = filter_input(INPUT_GET, 'DivisionID', FILTER_SANITIZE_NUMBER_INT))) { + + // If so then add it to the session + $_SESSION[GLM_EVENT_SESSION]['Division'] = $divisionID; + + } elseif (isset($_SESSION[GLM_EVENT_SESSION]['Division'])) { + + // Otherwise, get the division ID from the session + $divisionID = $_SESSION[GLM_EVENT_SESSION]['Division']; + + } else { + + // Otherwise, we don't have a division id + return false; + + } + + $divisionDetail = $this->getEntry($divisionID); + + return $divisionDetail; + + } + + + /** + * Edit Division + * + * @return array + */ + function editDivision() + { + + if (($divisionID = filter_input(INPUT_GET, 'DivisionID', FILTER_SANITIZE_NUMBER_INT))) { + + // If so then add it to the session + $_SESSION[GLM_EVENT_SESSION]['Division'] = $stateID; + + } elseif (isset($_SESSION[GLM_EVENT_SESSION]['Division'])) { + + // Otherwise, get the division ID from the session + $divisionID = $_SESSION[GLM_EVENT_SESSION]['Division']; + + } else { + + // Otherwise, we don't have a state rep id + return false; + + } + + $divisionDetail = $this->editEntry($divisionID); + + return $divisionDetail; + + } + + /** + * Check for other field related issues + * + * This function must be here because it's called from a function + * in dataAbstract. Simply return $r if there's nothing to check. + * + * @return array + */ + function checkOther($r) + { + parent::checkOther($r); + return $r; + } + + /** + * Update Division + * + * @return array + */ + function updateDivision() + { + + if (($divisionID = filter_input(INPUT_GET, 'DivisionID', FILTER_SANITIZE_NUMBER_INT))) { + + // If so then add it to the session + $_SESSION[GLM_EVENT_SESSION]['Division'] = $stateID; + + } elseif (isset($_SESSION[GLM_EVENT_SESSION]['Division'])) { + + // Otherwise, get the dvision ID from the session + $divisionID = $_SESSION[GLM_EVENT_SESSION]['Division']; + + } else { + + // Otherwise, we don't have a divisio id + return false; + + } + + // Try to update this data + $r = $this->updateEntry($divisionID); + + return $r; + + } + + + /** + * Add New Division + * + * @return array + */ + function newDivision() + { + + $r = $this->newEntry(); + + // If there's a currently selected Event, set that as default + if (isset($_SESSION[GLM_EVENT_SESSION]['Event']) && $_SESSION[GLM_EVENT_SESSION]['Event'] != false) { + $eventID = isset($_SESSION[GLM_EVENT_SESSION]['Event']); + $r['fieldData']['event_name']['pick_list'][$eventID]['default'] = true; + } + + return $r; + + } + + /** + * Insert Division + * + * @return array + */ + function insertDivision() + { + + $r = $this->insertEntry(); + + // If succesful then set current division to the one just inserted. + if ($r['status']) { + $_SESSION[GLM_EVENT_SESSION]['Division'] = $r['insertedID']; + } + + return $r; + + } + +} + + + + +?> \ No newline at end of file diff --git a/classes/data/dataEntrances.php b/classes/data/dataEntrances.php new file mode 100644 index 0000000..034eed8 --- /dev/null +++ b/classes/data/dataEntrances.php @@ -0,0 +1,523 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: dataEntrances.php,v 1.0 2011/01/25 19:31:47 cscott Exp $ + * @link http://www.gaslightmedia.com/ + */ + +require_once DATA_ABSTRACT; + +/** + * EventManagementDataEntrances class + * + * PHP version 5 + * + * @category Data + * @package EventManagement + * @author Chuck Scott + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: dataEntrances.php,v 1.0 2011/01/25 19:31:47 cscott Exp $ + * @link http://www.gaslightmedia.com + */ +class EventManagementDataEntrances extends DataAbstract +{ + /** + * Field definitions + * + * @var $ini + * @access public + */ + public $table = 'eventmgt.entrance'; + + /** + * Field definitions + * + * 'type' is type of field as defined by the application + * text Regular text field + * pointer Pointer to an entry in another table + * 'filters' is the filter name for a particular filter ID in PHP filter functions + * See PHP filter_id() + * + * 'use' is when to use the field + * l = List + * g = Get + * n = New + * i = Insert + * e = Edit + * u = Update + * d = Delete + * a = All + * + * @var $ini + * @access public + */ + public $fields = false; + + /** + * Constructor + * + * @param object $d database connection + * + * @return void + * @access public + */ + function __construct($dbh, $config) + { + + parent::__construct($dbh, $config); + + $this->fields = array( + + // Record ID + 'id' => array( + 'field' => 'id', + 'as' => false, + 'type' => 'integer', + 'required' => true, + 'unique' => true, + 'default' => false, + 'use' => 'lg' + ), + + // Member ID for adding entrances + 'member' => array( + 'field' => 'member', + 'as' => false, + 'type' => 'integer', + 'required' => true, + 'unique' => false, + 'default' => $_SESSION[GLM_EVENT_SESSION]['Member'], + 'use' => 'nid' + ), + + // Member Name display + 'member_view' => array( + 'field' => 'member', + 'as' => 'member_name', + 'type' => 'pointer', + 'p_table' => 'eventmgt.member', + 'p_field' => 'name', + 'p_id' => 'id', + 'p_static' => true, + 'required' => true, + 'unique' => false, + 'default' => false, + 'view_only' => true, + 'use' => 'gleu' + ), + + // Entrance Name + 'name' => array( + 'field' => 'name', + 'as' => false, + 'type' => 'text', + 'required' => true, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Description + 'descr' => array( + 'field' => 'descr', + 'as' => false, + 'type' => 'text', + 'filter' => FILTER_SANITIZE_MAGIC_QUOTES, + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Image + 'image' => array( + 'field' => 'image', + 'as' => false, + 'type' => 'image', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Address Line 1 + 'addr1' => array( + 'field' => 'addr1', + 'as' => false, + 'type' => 'text', + 'required' => true, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Address Line 2 + 'addr2' => array( + 'field' => 'addr2', + 'as' => false, + 'type' => 'text', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // City + 'city' => array( + 'field' => 'city', + 'as' => false, + 'type' => 'text', + 'required' => true, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // State + 'state' => array( + 'field' => 'state', + 'as' => false, + 'type' => 'list', + 'list' => $this->config->states->toArray(), + 'required' => true, + 'unique' => false, + 'default' => 'MI', + 'use' => 'a' + ), + + // Country + 'country' => array( + 'field' => 'country', + 'as' => false, + 'type' => 'list', + 'list' => $this->config->countries->toArray(), + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // ZIP + 'zip' => array( + 'field' => 'zip', + 'as' => false, + 'type' => 'text', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Latitude + 'lat' => array( + 'field' => 'lat', + 'as' => false, + 'type' => 'float', + 'required' => false, + 'unique' => false, + 'default' => 45, + 'use' => 'a' + ), + + // Longitude + 'lon' => array( + 'field' => 'lon', + 'as' => false, + 'type' => 'float', + 'required' => false, + 'unique' => false, + 'default' => -84, + 'use' => 'a' + ), + + // Member phone - From main member db + 'phone' => array( + 'field' => 'phone', // ID in member table is same as in eventmgt.member + 'as' => false, + 'type' => 'text', + 'required' => true, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Colors for tickets and display + 'color' => array( + 'field' => 'color', + 'as' => false, + 'type' => 'list', + 'list' => $this->config->color->toArray(), + 'required' => true, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Sort order + 'sort' => array( + 'field' => 'sort', + 'as' => false, + 'type' => 'integer', + 'required' => true, + 'unique' => false, + 'default' => 999, + 'use' => 'a' + ), + + // Notes + 'notes' => array( + 'field' => 'notes', + 'as' => false, + 'type' => 'text', + 'filter' => FILTER_SANITIZE_MAGIC_QUOTES, + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ) + + + ); + } + + /** + * Get Entrancess list + * + * @return object containing array as sub-objects + */ + function getEntrancesList($memberID = false, $where = false) + { + + // If a where clause has not been supplied + if (!$where) { + + $where = 'true'; + + // Check if there's a member ID and filter by that member if there is + $memberID = ($memberID - 0); // Make sure it's number + if ($memberID > 0) { + $where .= " AND T.member = $memberID"; + } elseif ($_SESSION[GLM_EVENT_MGT_ADMIN]['Member'] > 0) { + $where .= " AND T.member = ".$_SESSION[GLM_EVENT_MGT_ADMIN]['Member']; + } + + } + + // Get list of Entrances + $entrancesList = $this->getList($where, 'sort, name'); + + return $entrancesList; + } + + /** + * Get Entrance Detail + * + * @return array + */ + function getEntranceDetail($entranceID = false) + { + + // If a entrance ID has been supplied + if ($entranceID != false) { + + $_SESSION[GLM_EVENT_SESSION]['Entrance'] = $entranceID; + + } elseif (($entranceID = filter_input(INPUT_GET, 'EntranceID', FILTER_SANITIZE_NUMBER_INT))) { + + // Otherwise if there a new entrance ID supplied via the request + $_SESSION[GLM_EVENT_SESSION]['Entrance'] = $entranceID; + + } elseif (isset($_SESSION[GLM_EVENT_SESSION]['Entrance'])) { + + // Otherwise, get the event ID from the session + $entranceID = $_SESSION[GLM_EVENT_SESSION]['Entrance']; + + } else { + + // Otherwise, we don't have an event id + return false; + + } + + $entranceDetail = $this->getEntry($entranceID); + + return $entranceDetail; + + } + + + /** + * Edit Entrance + * + * @return array + */ + function editEntrance() + { + + if (($entranceID = filter_input(INPUT_GET, 'EntranceID', FILTER_SANITIZE_NUMBER_INT))) { + + // If so then add it to the session + $_SESSION[GLM_EVENT_SESSION]['Entrance'] = $entranceID; + + } elseif (isset($_SESSION[GLM_EVENT_SESSION]['Entrance'])) { + + // Otherwise, get the entrance ID from the session + $entranceID = $_SESSION[GLM_EVENT_SESSION]['Entrance']; + + } else { + + // Otherwise, we don't have a entrance id + return false; + + } + + $entranceDetail = $this->editEntry($entranceID); + + return $entranceDetail; + + } + + /** + * Check for other field related issues + * + * This function must be here because it's called from a function + * in dataAbstract. Simply return $r if there's nothing to check. + * + * @return array + */ + function checkOther($r) + { + parent::checkOther($r); + return $r; + } + + /** + * Update Entrance + * + * @return array + */ + function updateEntrance() + { + + if (($entranceID = filter_input(INPUT_GET, 'EntranceID', FILTER_SANITIZE_NUMBER_INT))) { + + // If so then add it to the session + $_SESSION[GLM_EVENT_SESSION]['Entrance'] = $entranceID; + + } elseif (isset($_SESSION[GLM_EVENT_SESSION]['Entrance'])) { + + // Otherwise, get the entrance ID from the session + $entranceID = $_SESSION[GLM_EVENT_SESSION]['Entrance']; + + } else { + + // Otherwise, we don't have a state rep id + return false; + + } + + // Try to update this data + $r = $this->updateEntry($entranceID); + + return $r; + + } + + + /** + * Add New Entrance + * + * @return array + */ + function newEntrance() + { + + $r = $this->newEntry(); + + return $r; + + } + + /** + * Insert entrance + * + * @return array + */ + function insertEntrance() + { + + $r = $this->insertEntry(); + + // If succesful then set current entrance to the one just inserted. + if ($r['status']) { + $_SESSION[GLM_EVENT_SESSION]['Entrance'] = $r['insertedID']; + } + + return $r; + + } + + + /** + * Delete entrance + * + * @param $confirm bool False to ask if user wants to delete and true to actually delete + * + * @return array + */ + function entranceDelete($confirm = false) + { + + // Is there a new entrance code selected? + if (($entranceID = filter_input(INPUT_GET, 'EntranceID', FILTER_SANITIZE_NUMBER_INT))) { + + // If so then add it to the session + $_SESSION[GLM_EVENT_SESSION]['Entrance'] = $entranceID; + + } elseif (isset($_SESSION[GLM_EVENT_SESSION]['Entrance'])) { + + // Otherwise, get the entrance ID from the session + $entranceID = $_SESSION[GLM_EVENT_SESSION]['Entrance']; + + } else { + + // Otherwise, we don't have an entrance id + return false; + + } + + $entranceDetail = $this->deleteEntry($entranceID, $confirm); + + return $entranceDetail; + + } + + /** + * Get Entrances Stats + * + * @return object containing array as sub-objects + */ + function getEntrancesStats($where = 'true') + { + + $entrancesStats = $this->getStats($where); + + return $entrancesStats; + } + + + +} + + + + +?> \ No newline at end of file diff --git a/classes/data/dataEvents.php b/classes/data/dataEvents.php new file mode 100644 index 0000000..ecb55e4 --- /dev/null +++ b/classes/data/dataEvents.php @@ -0,0 +1,841 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: dataEvents.php,v 1.0 2011/01/25 19:31:47 cscott Exp $ + * @link http://www.gaslightmedia.com/ + */ + +require_once DATA_ABSTRACT; + +/** + * EventManagementDataEvents class + * + * PHP version 5 + * + * @category Data + * @package EventManagement + * @author Chuck Scott + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: dataEvents,v 1.0 2011/01/25 19:31:47 cscott Exp $ + * @link http://www.gaslightmedia.com/ + + + */ +class EventManagementDataEvents extends DataAbstract +{ + /** + * Field definitions + * + * @var $ini + * @access public + */ + public $table = 'eventmgt.event'; + + /** + * Field definitions + * + * 'type' is type of field as defined by the application + * text Regular text field + * pointer Pointer to an entry in another table + * 'filters' is the filter name for a particular filter ID in PHP filter functions + * See PHP filter_id() + * + * 'use' is when to use the field - see documentation + * + * @var $ini + * @access public + */ + public $fields = false; + + /** + * Constructor + * + * @param object $d database connection + * + * @return void + * @access public + */ + function __construct($dbh, $config) + { + + parent::__construct($dbh, $config); + + $this->fields = array( + + // Record ID + 'id' => array( + 'field' => 'id', + 'as' => false, + 'type' => 'integer', + 'required' => true, + 'unique' => true, + 'default' => false, + 'use' => 'lged', + 'quicktip' => '' + + ), + + // Name of event + 'name' => array( + 'field' => 'name', + 'as' => false, + 'type' => 'text', + 'required' => true, + 'unique' => true, + 'default' => false, + 'use' => 'a' + ), + + // General description of event + 'descr' => array( + 'field' => 'descr', + 'as' => false, + 'type' => 'text', + 'filter' => FILTER_SANITIZE_MAGIC_QUOTES, + 'required' => true, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Description of dates for this event + 'event_dates' => array( + 'field' => 'event_dates', + 'as' => false, + 'type' => 'text', + 'required' => true, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Active flag + 'active' => array( + 'field' => 'active', + 'as' => false, + 'type' => 'checkbox', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // event/Event Code + 'event_code' => array( + 'field' => 'event_code', + 'as' => false, + 'type' => 'text', + 'required' => true, + 'unique' => true, + 'default' => false, + 'use' => 'lgnie' + ), + + // Image + 'image' => array( + 'field' => 'image', + 'as' => false, + 'type' => 'image', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Team Event + 'team_event' => array( + 'field' => 'team_event', + 'as' => false, + 'type' => 'checkbox', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), +/* Not using now + // Minimim number of nights stay + 'days' => array( + 'field' => 'days', + 'as' => false, + 'type' => 'integer', + 'minValue' => 1, + 'maxValue' => false, + 'required' => true, + 'unique' => false, + 'default' => 1, + 'use' => 'a' + ), + + // Minimum number of adults + 'min_adults' => array( + 'field' => 'min_adults', + 'as' => false, + 'type' => 'integer', + 'minValue' => 1, + 'maxValue' => false, + 'required' => true, + 'unique' => false, + 'default' => 1, + 'use' => 'a' + ), +*/ + + // Front end reservations by Event Code rather than displaying for selection + 'reserve_by_code' => array( + 'field' => 'reserve_by_code', + 'as' => false, + 'type' => 'checkbox', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // May book multiple rooms + 'multiple_rooms' => array( + 'field' => 'multiple_rooms', + 'as' => false, + 'type' => 'checkbox', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), +/* + // Maximum number of rooms that may be booked a once + 'max_rooms' => array( + 'field' => 'max_rooms', + 'as' => false, + 'type' => 'integer', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), +*/ + // Start Date + 'start_date' => array( + 'field' => 'start_date', + 'as' => false, + 'type' => 'date', + 'format' => 'm/d/Y', + 'minValue' => strtotime('1/1/'.date('Y')), // Earliest is now + 'maxValue' => strtotime('1/1/'.date('Y').' +4 years'), // This year plus 3 + 'required' => true, + 'unique' => false, + 'default' => time(), + 'use' => 'a' + ), + + // End Date + 'end_date' => array( + 'field' => 'end_date', + 'as' => false, + 'type' => 'date', + 'format' => 'm/d/Y', + 'minValue' => strtotime('1/1/'.date('Y')), // Earliest is now + 'maxValue' => strtotime('1/1/'.date('Y').' +4 years'), // This year plus 3 + 'required' => true, + 'unique' => false, + 'default' => time(), + 'use' => 'a' + ), + + // Last date event may be booked + 'cutoff_date' => array( + 'field' => 'cutoff_date', + 'as' => false, + 'type' => 'date', + 'format' => 'm/d/Y', + 'minValue' => strtotime('1/1/'.date('Y')), // Earliest is now + 'maxValue' => strtotime('1/1/'.date('Y').' +4 years'), // This year plus 3 + 'required' => true, + 'unique' => false, + 'default' => time(), + 'use' => 'a' + ), + + // Use Required Stay + 'req_stay' => array( + 'field' => 'req_stay', + 'as' => false, + 'type' => 'checkbox', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Must arrive by date + 'req_stay_arrive' => array( + 'field' => 'req_stay_arrive', + 'as' => false, + 'type' => 'date', + 'format' => 'm/d/Y', + 'minValue' => strtotime('1/1/'.date('Y')), // Earliest is now + 'maxValue' => strtotime('1/1/'.date('Y').' +4 years'), // This year plus 3 + 'required' => true, + 'unique' => false, + 'default' => time(), + 'use' => 'a' + ), + + // Must depart no earlier than date - This is the date after the last required night's stay. + 'req_stay_depart' => array( + 'field' => 'req_stay_depart', + 'as' => false, + 'type' => 'date', + 'format' => 'm/d/Y', + 'minValue' => strtotime('1/1/'.date('Y')), // Earliest is now + 'maxValue' => strtotime('1/1/'.date('Y').' +4 years'), // This year plus 3 + 'required' => true, + 'unique' => false, + 'default' => time(), + 'use' => 'a' + ), + + // Required Stay Notices + 'req_stay_notice' => array( + 'field' => 'req_stay_notice', + 'as' => false, + 'type' => 'text', + 'filter' => FILTER_SANITIZE_MAGIC_QUOTES, + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Date after which team inventory becomes available to anyone + 'open_res_date' => array( + 'field' => 'open_res_date', + 'as' => false, + 'type' => 'date', + 'format' => 'm/d/Y', + 'minValue' => strtotime('1/1/'.date('Y')), // Earliest is now + 'maxValue' => strtotime('1/1/'.date('Y').' +4 years'), // This year plus 3 + 'required' => true, + 'unique' => false, + 'default' => time(), + 'use' => 'a' + ), + + // Confirmation hours (property must confirm by ...) + 'conf_hours' => array( + 'field' => 'conf_hours', + 'as' => false, + 'type' => 'integer', + 'required' => true, + 'unique' => false, + 'default' => 48, + 'use' => 'a' + ), + + // Inventory hold time in minutes + 'inven_hold_time' => array( + 'field' => 'inven_hold_time', + 'as' => false, + 'type' => 'integer', + 'required' => true, + 'unique' => false, + 'default' => 30, + 'use' => 'a' + ), + + // Sort + 'sort' => array( + 'field' => 'sort', + 'as' => false, + 'type' => 'integer', + 'required' => true, + 'unique' => false, + 'default' => 999, + 'use' => 'a' + ), + + // Address Line 1 + 'addr1' => array( + 'field' => 'addr1', + 'as' => false, + 'type' => 'text', + 'required' => true, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Address Line 2 + 'addr2' => array( + 'field' => 'addr2', + 'as' => false, + 'type' => 'text', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // City + 'city' => array( + 'field' => 'city', + 'as' => false, + 'type' => 'text', + 'required' => true, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // State + 'state' => array( + 'field' => 'state', + 'as' => false, + 'type' => 'list', + 'list' => $this->config->states->toArray(), + 'required' => true, + 'unique' => false, + 'default' => 'MI', + 'use' => 'a' + ), + + // ZIP/Postal Code + 'zip' => array( + 'field' => 'zip', + 'as' => false, + 'type' => 'text', + 'required' => true, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Country + 'country' => array( + 'field' => 'country', + 'as' => false, + 'type' => 'list', + 'list' => $this->config->countries->toArray(), + 'required' => true, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Latitude + 'lat' => array( + 'field' => 'lat', + 'as' => false, + 'type' => 'latitude', + 'required' => true, + 'unique' => false, + 'default' => false, + 'use' => 'lgnieudc' + ), + + // Longitude + 'lon' => array( + 'field' => 'lon', + 'as' => false, + 'type' => 'longitude', + 'required' => true, + 'unique' => false, + 'default' => false, + 'use' => 'lgnieudc' + ), + + // Central_payment + 'central_payment' => array( + 'field' => 'central_payment', + 'as' => false, + 'type' => 'checkbox', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Central Payment E-Mail + 'central_payment_email' => array( + 'field' => 'central_payment_email', + 'as' => false, + 'type' => 'text', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Host Property + 'host_property' => array( + 'field' => 'host_property', + 'as' => false, + 'type' => 'pointer', + 'p_table' => 'members.member', + 'p_field' => 'member_name', + 'p_id' => 'member_id', + 'p_where' => 'member_id in + ( + SELECT DISTINCT member_id + FROM members.member_category + WHERE category_id IN + (SELECT category_id FROM members.category WHERE accommodations) + )', + 'p_blank' => true, + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'nieu' + ), + + // Host Property + 'host_property_2' => array( + 'field' => 'host_property', + 'as' => false, + 'type' => 'pointer', + 'p_table' => 'members.member', + 'p_field' => 'member_name', + 'p_id' => 'member_id', + 'p_static' => true, + 'required' => true, + 'unique' => false, + 'default' => false, + 'view_only' => true, + 'use' => 'gldc' + ), + + // Reservation Policy + 'res_policy' => array( + 'field' => 'res_policy', + 'as' => false, + 'type' => 'text', + 'filter' => FILTER_SANITIZE_MAGIC_QUOTES, + 'required' => true, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Cancelation Policy + 'can_policy' => array( + 'field' => 'can_policy', + 'as' => false, + 'type' => 'text', + 'filter' => FILTER_SANITIZE_MAGIC_QUOTES, + 'required' => true, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Payment Policy + 'pmt_policy' => array( + 'field' => 'pmt_policy', + 'as' => false, + 'type' => 'text', + 'filter' => FILTER_SANITIZE_MAGIC_QUOTES, + 'required' => true, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Message to display at bottom of cart + 'cart_text' => array( + 'field' => 'cart_text', + 'as' => false, + 'type' => 'text', + 'filter' => FILTER_SANITIZE_MAGIC_QUOTES, + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Reservation Message to Guest + 'res_msg' => array( + 'field' => 'res_msg', + 'as' => false, + 'type' => 'text', + 'filter' => FILTER_SANITIZE_MAGIC_QUOTES, + 'required' => true, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Confirmation Message to Guest + 'conf_msg' => array( + 'field' => 'conf_msg', + 'as' => false, + 'type' => 'text', + 'filter' => FILTER_SANITIZE_MAGIC_QUOTES, + 'required' => true, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ) + + ); + + } + + + /** + * Get Events list + * + * @param string type of events list + * + * @return object containing array as sub-objects + */ + function getEventsList($whereRequest = false) + { + $where = ''; + + // If there's a specific whereRequest, use that only + if ($whereRequest) { + + $where = $whereRequest; + + } else { + + // Get member ID from session - if available + $memberID = $_SESSION[GLM_EVENT_SESSION]['Member']; + + // Get team ID from session - if available + $teamID = $_SESSION[GLM_EVENT_SESSION]['Team']; + + // Get any specified event listing option - default to active + $option = 'active'; + if (($eventsListOption = filter_input(INPUT_GET, 'EventsListOption', FILTER_SANITIZE_STRING))) { + $option = $eventsListOption; + } + + // Clear Session Event Selection +// $_SESSION[GLM_EVENT_SESSION]['Event'] = false; + + // Select type of list + switch ($option) { + case 'all': + $where = 'true'; + break; + case 'active': + $where = "active"; + break; + case 'inactive': + $where = "NOT active AND end_date > 'now'"; + break; + case 'expired': + $where = "active AND end_date < 'now'"; + break; + case 'archived': + $where = "NOT active AND end_date < 'now'"; + break; + case 'member': + if (!$memberID) { + return false; + } + $where = "T.id IN ( + SELECT DISTINCT event + FROM eventmgt.inventory + WHERE member = $memberID + )"; +/* Not using event_prop anymore + SELECT DISTINCT event + FROM eventmgt.event_prop + WHERE property = $memberID + */ + break; + case 'team': + if (!$teamID) { + return false; + } + $where = "T.id IN ( + SELECT DISTINCT event + FROM eventmgt.team_property + WHERE team = $teamID + )"; + break; + default: + echo "Option not set"; + break; + } + + } + + // Get list of all available Events + $eventsList = $this->getList($where, 'start_date'); + if (count($eventsList) == 0) { + return false; + } + + return $eventsList; + } + + + + /** + * Get Event Detail + * + * @return array + */ + function getEventDetail() + { + + // Is there a new event code selected? + if (($eventID = filter_input(INPUT_GET, 'EventID', FILTER_SANITIZE_NUMBER_INT))) { + + // If so then add it to the session + $_SESSION[GLM_EVENT_SESSION]['Event'] = $eventID; + + } elseif (isset($_SESSION[GLM_EVENT_SESSION]['Event'])) { + + // Otherwise, get the event ID from the session + $eventID = $_SESSION[GLM_EVENT_SESSION]['Event']; + + } else { + + // Otherwise, we don't have an event id + return false; + + } + + $eventDetail = $this->getEntry($eventID); + + return $eventDetail; + + } + + /** + * Edit Event + * + * @return array + */ + function editEvent() + { + + // Is there a new event code selected? + if (($eventID = filter_input(INPUT_GET, 'EventID', FILTER_SANITIZE_NUMBER_INT))) { + + // If so then add it to the session + $_SESSION[GLM_EVENT_SESSION]['Event'] = $eventID; + + } elseif (isset($_SESSION[GLM_EVENT_SESSION]['Event'])) { + + // Otherwise, get the event ID from the session + $eventID = $_SESSION[GLM_EVENT_SESSION]['Event']; + + } else { + + // Otherwise, we don't have an event id + return false; + + } + + $eventDetail = $this->editEntry($eventID); + //echo "
".print_r($eventDetail,1)."
"; + + return $eventDetail; + + } + + /** + * Check for other field related issues + * + * This function must be here because it's called from a function + * in dataAbstract. Simply return $r if there's nothing to check. + * + * @return array + */ + function checkOther($r) + { + parent::checkOther($r); + + $fd = $r['fieldData']; + + // Is Start date is later than End date + if ($fd['start_date']['timestamp'] > $fd['end_date']['timestamp']) { + $r['fieldFail']['start_date'] = 'Start date is later than end date.'; + $r['status'] = false; + } + + // Is cutoff date is later than end date + if ($fd['cutoff_date']['timestamp'] > $fd['end_date']['timestamp']) { + $r['fieldFail']['cutoff_date'] = 'Cutoff date is later than end date.'; + $r['status'] = false; + } + + return $r; + } + + /** + * Update Event + * + * @return array + */ + function updateEvent() + { + // If required dates is not selected, then drop the required start and end dates. + if (!isset($_REQUEST['req_stay']) || $_REQUEST['req_stay'] == '') { + unset($this->fields['req_stay_arrive']); + unset($this->fields['req_stay_depart']); + } + + // Is there a new event code selected? + if (($eventID = filter_input(INPUT_GET, 'EventID', FILTER_SANITIZE_NUMBER_INT))) { + + // If so then add it to the session + $_SESSION[GLM_EVENT_SESSION]['Event'] = $eventID; + + } elseif (isset($_SESSION[GLM_EVENT_SESSION]['Event'])) { + + // Otherwise, get the event ID from the session + $eventID = $_SESSION[GLM_EVENT_SESSION]['Event']; + + } else { + + // Otherwise, we don't have an event id + return false; + + } + + // Try to update this data + $r = $this->updateEntry($eventID); + + return $r; + + } + + /** + * Insert Event + * + * @return array + */ + function insertEvent() + { + + $r = $this->insertEntry(); + + // If succesful then set current event to the one just inserted. + if ($r['status']) { + $_SESSION[GLM_EVENT_SESSION]['Event'] = $r['insertedID']; + } + + return $r; + + } + + +} + + + + +?> \ No newline at end of file diff --git a/classes/data/dataFees.php b/classes/data/dataFees.php new file mode 100644 index 0000000..612efab --- /dev/null +++ b/classes/data/dataFees.php @@ -0,0 +1,662 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: dataFees.php,v 1.0 2011/01/25 19:31:47 cscott Exp $ + * @link http://www.gaslightmedia.com/ + */ + +require_once DATA_ABSTRACT; + +/** + * EventManagementDataFees class + * + * PHP version 5 + * + * @category Data + * @package EventManagement + * @author Chuck Scott + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: dataFees.php,v 1.0 2011/01/25 19:31:47 cscott Exp $ + * @link http://www.gaslightmedia.com + */ +class EventManagementDataFees extends DataAbstract +{ + /** + * Field definitions + * + * @var $ini + * @access public + */ + public $table = 'eventmgt.fees'; + + /** + * Field definitions + * + * 'type' is type of field as defined by the application + * text Regular text field + * pointer Pointer to an entry in another table + * 'filters' is the filter name for a particular filter ID in PHP filter functions + * See PHP filter_id() + * + * 'use' is when to use the field + * l = List + * g = Get + * n = New + * i = Insert + * e = Edit + * u = Update + * d = Delete + * a = All + * + * @var $ini + * @access public + */ + public $fields = false; + + /** + * Constructor + * + * @param object $d database connection + * + * @return void + * @access public + */ + function __construct($dbh, $config) + { + + parent::__construct($dbh, $config); + + $this->fields = array( + + // Record ID + 'id' => array( + 'field' => 'id', + 'as' => false, + 'type' => 'integer', + 'required' => true, + 'unique' => true, + 'default' => false, + 'use' => 'lg' + ), + + // Applied to (insert) - what type of entities is this fee for + 'affiliation_type' => array( + 'field' => 'affiliation_type', + 'as' => false, + 'type' => 'integer', + 'required' => true, + 'unique' => false, + 'default' => false, + 'use' => 'i' + ), + + // Applied to (view) + 'affiliation_type_2' => array( + 'field' => 'affiliation_type', + 'as' => false, + 'type' => 'list', + 'list' => $this->config->reference_type_numb->toArray(), + 'required' => false, + 'unique' => false, + 'default' => false, + 'view_only' => true, + 'use' => 'gled' + ), + + // Fee affiliation (non-standard pointer) + // Points to various tables depending on the "Applied To" value + 'owner' => array( + 'field' => 'owner', + 'as' => false, + 'type' => 'integer', + 'required' => true, + 'unique' => false, + 'default' => false, + 'use' => 'i' + ), + + // Fee affiliation (non-standard pointer) + // Points to various tables depending on the "Applied To" value + 'owner_2' => array( + 'field' => 'owner', + 'as' => false, + 'type' => 'integer', + 'required' => false, + 'unique' => false, + 'default' => false, + 'view_only' => true, + 'use' => 'gled' + ), + + // Fee method + 'fee_method' => array( + 'field' => 'fee_method', + 'as' => false, + 'type' => 'list', + 'list' => $this->config->fee_method_numb->toArray(), + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Event Specific - for only one particular event + 'room_specific' => array( + 'field' => 'room_specific', + 'as' => false, + 'type' => 'checkbox', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Fee Name + 'name' => array( + 'field' => 'name', + 'as' => false, + 'type' => 'text', + 'required' => true, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Fee Amount + 'fee_amount' => array( + 'field' => 'fee_amount', + 'as' => false, + 'type' => 'float', + 'output_format' => '.2', + 'required' => true, + 'minValue' => 0.01, + 'unique' => false, + 'default' => 0.0, + 'use' => 'a' + ), + + // Taxable + 'taxable' => array( + 'field' => 'taxable', + 'as' => false, + 'type' => 'checkbox', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Itemize + 'itemize' => array( + 'field' => 'itemize', + 'as' => false, + 'type' => 'checkbox', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Optional Service - guests may select + 'optional_service' => array( + 'field' => 'optional_service', + 'as' => false, + 'type' => 'checkbox', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Request Service Quantity - If off then assume single unit quantity + 'service_quant' => array( + 'field' => 'service_quant', + 'as' => false, + 'type' => 'checkbox', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Maximum Service Quantity - if service_quant on + 'service_max_quant' => array( + 'field' => 'service_max_quant', + 'as' => false, + 'type' => 'integer', + 'required' => false, + 'unique' => false, + 'default' => 2, + 'use' => 'a' + ), + + // Event Specific - for only one particular event + 'event_specific' => array( + 'field' => 'event_specific', + 'as' => false, + 'type' => 'checkbox', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Event - if event_specific then this is the event + 'event' => array( + 'field' => 'event', + 'as' => false, + 'type' => 'pointer', + 'p_table' => 'eventmgt.event', + 'p_field' => 'name', + 'p_id' => 'id', + 'p_sort' => 'start_date, name', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Description - used on front-end for description of service + 'descr' => array( + 'field' => 'descr', + 'as' => false, + 'type' => 'text', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ) + + ); + } + + /** + * Get an array of fees for a particular affiliated entity + * + * $listOption Optional Type of affiliation - see config.ini 'reference_type' + * If not supplied will check for FeesListOption GET value + * $whereRequest If supplied, use as WHERE clause instead + * + * @return object containing array as sub-objects + */ + function getFees($listOption = false, $whereRequest = false) + { + + $where = ''; + + // If there's a specific whereRequest, use that only + if ($whereRequest) { + $where = $whereRequest; + } else { + + // Get Event ID from session - if available + $eventID = $_SESSION[GLM_EVENT_SESSION]['Event']; + + // Get Member ID from session - if available + $memberID = $_SESSION[GLM_EVENT_SESSION]['Member']; + + // Get any specified event listing option - default to active\ + if ($listOption != '') { + $option = $listOption; + + // Otheriwse check for list options provided in request + } elseif (($feesListOption = filter_input(INPUT_GET, 'FeesListOption', FILTER_SANITIZE_STRING))) { + $option = $feesListOption; + } + + // Include selection of proper affiliation type + switch ($option) { + case 'event': + if ($eventID) { + $where .= "T.affiliation_type = ".$this->config->reference_type->event + ."AND owner = $eventID"; + } else { + $where .= "false"; + } + break; + case 'member': + if ($memberID) { + $where .= "T.affiliation_type = ".$this->config->reference_type->property + ."AND owner = $memberID\n"; + } else { + $where .= "false"; + } + break; + } + } + + // Get the fees - return false if none found + $feesList = $this->getList($where, 'name'); + if (!is_array($feesList) || count($feesList) == 0) { + return false; + } + + // Get affiliation type for each fee + reset($feesList); + while( list($key, $val) = each( $feesList ) ) { + + $aData = $this->getAffiliate( + $val['affiliation_type']['value'], + $val['owner'] + ); + + if ($aData) { + $feesList[$key]['affiliation_type_name'] = $aData['applied_to_name']; + $feesList[$key]['owner_name'] = $aData['owner_name']; + } + + // Specify if fee is in % rather than $ + $feesList[$key]['feePercent'] = false; + if ($feesList[$key]['fee_method']['value'] >= 10) { + $feesList[$key]['feePercent'] = true; + } + + } // Get Fee affiliation + + return $feesList; + } + + /** + * Get Fee Detail + * + * @return array + */ + function getFeeDetail() + { + + // Is there a new fee ID supplied? + if (!($feeID = filter_input(INPUT_GET, 'FeeID', FILTER_SANITIZE_NUMBER_INT))) { + // We don't have an fee id + return false; + } + + $feeDetail = $this->getEntry($feeID); + + // Get owner data + $aData = $this->getAffiliate( + $feeDetail['affiliation_type']['value'], + $feeDetail['owner'] + ); + + if ($aData) { + $feeDetail = array_merge($feeDetail, $aData); + } + + // Specify if fee is in % rather than $ + $feeDetail['feePercent'] = false; + if ($feeDetail['fee_method']['value'] >= 10) { + $feeDetail['feePercent'] = true; + } + + return $feeDetail; + + } + + /** + * Edit Fee + * + * @return array + */ + function editFee() + { + + // Is there a new fee ID supplied? + if (!($feeID = filter_input(INPUT_GET, 'FeeID', FILTER_SANITIZE_NUMBER_INT))) { + // We don't have an fee id + return false; + + } + + $feeDetail = $this->editEntry($feeID); + + // Get owner data + $aData = $this->getAffiliate( + $feeDetail['affiliation_type']['value'], + $feeDetail['owner'] + ); + + if ($aData) { + $feeDetail = array_merge($feeDetail, $aData); + } + + return $feeDetail; + + } + + /** + * Update Fee + * + * @return array + */ + function updateFee() + { + + // Is there a new fee ID supplied? + if (!($feeID = filter_input(INPUT_GET, 'FeeID', FILTER_SANITIZE_NUMBER_INT))) { + if (!($feeID = filter_input(INPUT_POST, 'FeeID', FILTER_SANITIZE_NUMBER_INT))) { + echo "::::::"; + // We don't have an fee id + return false; + } + } + + // Try to update this data + $r = $this->updateEntry($feeID); + + // Get owner data + $aData = $this->getAffiliate( + $r['fieldData']['affiliation_type']['value'], + $r['fieldData']['owner'] + ); + + if ($aData) { + $r['fieldData'] = array_merge($r['fieldData'], $aData); + } + + // Specify if fee is in % rather than $ + $r['fieldData']['feePercent'] = false; + + if ($r['fieldData']['fee_method']['value'] >= 10) { + $r['fieldData']['feePercent'] = true; + } + + return $r; + + } + + /** + * New Fee + * + * @return array + */ + function newFeeAffiliation($r) + { + + // Check for specified Fee type + // We need to check for name rather than number because that's what the js is sending us + if (!isset($_REQUEST['fee_type_code']) || $_REQUEST['fee_type_code'] == '') { + return false; + } + + // Get type and affiliation + $feeType = trim($_REQUEST['fee_type_code']); + $affiliateID = false; + + switch ($feeType) { + case 'event': + $feeTypeNumber = $this->config->reference_type->event; + if (isset($_SESSION[GLM_EVENT_SESSION]['Event'])) { + $affiliateID = ($_SESSION[GLM_EVENT_SESSION]['Event'] - 0); + $feeTypeName = 'Event'; + $aTable = 'event'; + $aField = 'name'; + $aFieldShort = 'event_code'; + } + break; + case 'property': + $feeTypeNumber = $this->config->reference_type->property; + if (isset($_SESSION[GLM_EVENT_SESSION]['Member'])) { + $affiliateID = ($_SESSION[GLM_EVENT_SESSION]['Member'] - 0); + $feeTypeName = 'Property'; + $aTable = 'eventmgt.member'; + $aField = 'name'; + $aFieldShort = $aField; + } + break; + } + + // If no match on Fee type, then fail + if ($affiliateID == false) { + return false; + } + + // Get affiliate data + $sql = "SELECT $aField AS name, + $aFieldShort AS short_name + FROM $aTable + WHERE id = $affiliateID + ;"; + + $stmt = $this->dbh->prepare($sql); + $stmt->execute(); + $aData = $stmt->fetch(PDO::FETCH_ASSOC); + + // if no valid affiliate data - fail + if (!$aData) { + return false; + } + + $r['fieldData']['fee_type_name'] = $feeTypeName; + $r['fieldData']['fee_type_code'] = $feeType; + $r['fieldData']['fee_type'] = $feeTypeNumber; + $r['fieldData']['affiliation_name'] = $aData['name']; + $r['fieldData']['affiliation'] = $affiliateID; + $r['fieldData']['affiliation_short'] = $aData['short_name']; + + return $r; + + } + + function newFee() + { + + $r = $this->newEntry(); + + $r = $this->newFeeAffiliation($r); + + // echo "
".print_r($r,1)."
"; + return $r; + + } + + + /** + * Insert Fee + * + * @return array + */ + function insertFee() + { + + $r = $this->insertEntry(); + $r = $this->newFeeAffiliation($r); + + // echo "
".print_r($r,1)."
"; + return $r; + + } + + /** + * Get Affiliate table and name + * + */ + function getAffiliate($type, $affiliation) + { + + // Deterimine Affliate table + $aTable = ''; + $aField = ''; + switch ($type) { + case $this->config->reference_type->event: + $aType = 'Event'; + $aTable = 'event'; + $aField = 'name'; + $aFieldShort = 'event_code'; + break; + case $this->config->reference_type->property: + $aType = 'Property'; + $aTable = 'eventmgt.member'; + $aField = 'name'; + $aFieldShort = $aField; + break; + } + + $r = false; + + // If we have a good affiliate relationship + if ($aField != '') { + + $sql = "SELECT $aField AS name, + $aFieldShort AS short_name + FROM $aTable + WHERE id = $affiliation + ;"; + + $stmt = $this->dbh->prepare($sql); + $stmt->execute(); + $aData = $stmt->fetch(PDO::FETCH_ASSOC); + + if ($aData) { + $r = array( + 'fee_type_name' => $aType, + 'affiliation_name' => $aData['name'], + 'affiliation_short' => $aData['short_name'] + ); + } + } + + return $r; + + } + + /** + * Delete Fee + * + * @return array + */ + function feeDelete($confirm = false) + { + // Is there a new fee code selected? + if (($feeID = filter_input(INPUT_GET, 'FeeID', FILTER_SANITIZE_NUMBER_INT))) { + + // If so then add it to the session + $_SESSION[GLM_EVENT_SESSION]['Fee'] = $feeID; + + } elseif (isset($_SESSION[GLM_EVENT_SESSION]['Fee'])) { + + // Otherwise, get the fee ID from the session + $feeID = $_SESSION[GLM_EVENT_SESSION]['Fee']; + + } else { + + // Otherwise, we don't have a fee id + return false; + + } + + $feeDetail = $this->deleteEntry($feeID, $confirm); + return $feeDetail; + + } + + +} +?> \ No newline at end of file diff --git a/classes/data/dataInventory.php b/classes/data/dataInventory.php new file mode 100644 index 0000000..0d5015d --- /dev/null +++ b/classes/data/dataInventory.php @@ -0,0 +1,1141 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: dataInventory.php,v 1.0 2011/01/25 19:31:47 cscott Exp $ + * @link http://www.gaslightmedia.com/ + */ + +require_once DATA_ABSTRACT; + +/** + * EventManagementAdminInventory class + * + * PHP version 5 + * + * @category Data + * @package EventManagement + * @author Chuck Scott + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: dataInventory.php,v 1.0 2011/01/25 19:31:47 cscott Exp $ + * @link <> + */ +class EventManagementDataInventory extends DataAbstract +{ + /** + * Field definitions + * + * @var $ini + * @access public + */ + public $table = 'eventmgt.inventory'; + + /** + * Field definitions + * + * 'type' is type of field as defined by the application + * text Regular text field + * pointer Pointer to an entry in another table + * 'filters' is the filter name for a particular filter ID in PHP filter functions + * See PHP filter_id() + * + * 'use' is when to use the field + * l = List + * g = Get + * n = New + * i = Insert + * e = Edit + * u = Update + * d = Delete + * a = All + * + * @var $ini + * @access public + */ + public $fields = false; + + /** + * Constructor + * + * @param object $d database connection + * + * @return void + * @access public + */ + function __construct($dbh, $config) + { + + parent::__construct($dbh, $config); + + $this->fields = array( + + // Record ID + 'id' => array( + 'field' => 'id', + 'as' => false, + 'type' => 'integer', + 'required' => false, + 'unique' => true, + 'default' => false, + 'view_only' => true, + 'use' => 'a' + ), + + // Event selection + 'event' => array( + 'field' => 'event', + 'as' => false, + 'type' => 'pointer', + 'p_table' => 'eventmgt.event', + 'p_field' => 'name', + 'p_id' => 'id', + 'required' => true, + 'unique' => false, + 'default' => false, + 'view_only' => true, + 'use' => 'lgud' + ), + + // Event ID + 'event_id' => array( + 'field' => 'event', + 'as' => 'event_id', + 'type' => 'integer', + 'required' => true, + 'unique' => false, + 'default' => false, + 'use' => 'lgud' + ), + + // Property selection + 'member' => array( + 'field' => 'member', + 'as' => false, + 'type' => 'pointer', + 'p_table' => 'eventmgt.member', + 'p_field' => 'name', + 'p_id' => 'id', + 'required' => true, + 'unique' => false, + 'default' => false, + 'view_only' => true, + 'use' => 'lgud' + ), + + // Member Street Address - From main member db + 'member_street' => array( + 'field' => 'member', // ID in member table is same as in eventmgt.member + 'as' => 'street', + 'type' => 'pointer', + 'p_table' => 'members.member', + 'p_field' => 'street', + 'p_id' => 'member_id', + 'required' => true, + 'unique' => true, + 'default' => false, + 'view_only' => true, + 'use' => 'gleu' + ), + + // Member City - From main member db + 'member_city' => array( + 'field' => 'member', // ID in member table is same as in eventmgt.member + 'as' => 'city', + 'type' => 'pointer', + 'p_table' => 'members.city', + 'p_field' => 'city_name', + 'p_id' => 'city_id', + 'p_where' => 'M.member_id = T.member AND city.city_id = M.city_id', + 'p_from' => 'members.member M', + 'p_static' => true, + 'required' => true, + 'unique' => true, + 'default' => false, + 'view_only' => true, + 'use' => 'gleu' + ), + + // member ID + 'memb_id' => array( + 'field' => 'member', + 'as' => 'member_id', + 'type' => 'integer', + 'required' => true, + 'unique' => false, + 'default' => false, + 'use' => 'lgdu' + ), + + // Accommodation ID + 'accommodation_id' => array( + 'field' => 'accommodation', + 'as' => 'accommodation_id', + 'type' => 'integer', + 'required' => false, + 'unique' => false, + 'default' => false, + 'view_only' => true, + 'use' => 'au' + ), + + // Accommodation + 'accommodation' => array( + 'field' => 'accommodation', + 'as' => false, + 'type' => 'pointer', + 'p_table' => 'eventmgt.accommodation', + 'p_field' => 'name', + 'p_id' => 'id', + 'required' => true, + 'unique' => false, + 'default' => false, + 'use' => 'ni' + ), + + // Accommodation name + 'accommodation_name' => array( + 'field' => 'accommodation', + 'as' => false, + 'type' => 'pointer', + 'p_table' => 'eventmgt.accommodation', + 'p_field' => 'name', + 'p_id' => 'id', + 'p_static' => true, + 'required' => true, + 'unique' => false, + 'default' => false, + 'view_only' => true, + 'use' => 'lged' + ), + + // Start Date + 'start_date' => array( + 'field' => 'start_date', + 'as' => false, + 'type' => 'date', + 'required' => true, + 'unique' => false, + 'default' => false, + 'use' => 'ni' + ), + + // End Date + 'end_date' => array( + 'field' => 'end_date', + 'as' => false, + 'type' => 'date', + 'required' => true, + 'unique' => false, + 'default' => false, + 'use' => 'niu' + ), + + // Date + 'date' => array( + 'field' => 'date', + 'as' => false, + 'type' => 'date', + 'required' => true, + 'unique' => false, + 'default' => date('m/d/Y'), + 'use' => 'lgeud' + ), + + // Assigned to Event + 'assigned' => array( + 'field' => 'assigned', + 'as' => false, + 'type' => 'integer', + 'required' => true, + 'unique' => false, + 'default' => 0, + 'minValue' => 1, + 'use' => 'a' + ), + + // Available to reserve + 'available' => array( + 'field' => 'available', + 'as' => false, + 'type' => 'integer', + 'required' => true, + 'unique' => false, + 'default' => 0, + 'use' => 'lgeud' + ), + + // On Hold + 'on_hold' => array( + 'field' => 'id', + 'as' => 'on_hold', + 'type' => 'pointer', + 'p_table' => 'eventmgt.inven_hold', + 'p_field' => 'quant', + 'p_id' => 'inventory', + 'p_where' => "expire_time > '".date('r')."' AND inventory = T.id", + 'p_sum' => true, + 'p_static' => true, + 'required' => false, + 'unique' => false, + 'default' => false, + 'view_only' => true, + 'use' => 'lg' + ), + +/* not using now + // Minimum Nights Requred + 'min_nights' => array( + 'field' => 'min_nights', + 'as' => false, + 'type' => 'integer', + 'required' => true, + 'unique' => false, + 'default' => 1, + 'minValue' => 1, + 'use' => 'a' + ), +*/ + // Event Room Rate - For standard number of occupants + 'rate' => array( + 'field' => 'rate', + 'as' => false, + 'type' => 'money', + 'required' => true, + 'unique' => false, + 'default' => 0.0, + 'minValue' => 1, + 'use' => 'a' + ) +/* not using now + // Additional Person Rate + 'add_person' => array( + 'field' => 'add_person', + 'as' => false, + 'type' => 'money', + 'required' => false, + 'unique' => false, + 'default' => 0.0, + 'minValue' => 0, + 'use' => 'a' + ) +*/ + +/* not using policies at this level for now + // Request Policy + 'res_policy' => array( + 'field' => 'res_policy', + 'as' => false, + 'type' => 'text', + 'filter' => FILTER_SANITIZE_MAGIC_QUOTES, + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Cancel Policy + 'can_policy' => array( + 'field' => 'can_policy', + 'as' => false, + 'type' => 'text', + 'filter' => FILTER_SANITIZE_MAGIC_QUOTES, + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ) +*/ + ); + } + + /** + * Get Inventory list + * + * @param string type of events list + * + * @return object containing array + * timestamp of first date of inventory + * array of inventory items + */ + function getInvenList($setType = false, $setId = false) + { + + // Get any specified member listing option - default to event + if ($setType) { + + $option = $setType; + + } else { + + $option = 'accom'; + if (($invenListOption = filter_input(INPUT_GET, 'InvenListOption', FILTER_SANITIZE_STRING))) { + $option = $invenListOption; + } + + } + + // Check for setId passed in URL + $setIdRequest = ($_REQUEST['setId'] - 0); + if ($setIdRequest > 0) { + $setId = $setIdRequest; + } + + // Select type of list + $where = ''; + switch ($option) { + case 'all': + $where = 'TRUE'; + $type = 'Summary'; + break; + case 'event': + // Get event ID from session - if available + $eventID = ( $setId ? $setId : $_SESSION[GLM_EVENT_SESSION]['Event'] ); + if (!$eventID) { + return false; + } + $where = "T.event = $eventID"; + $type = 'Summary'; + break; + case 'member': + $memberID = ( $setId ? $setId : $_SESSION[GLM_EVENT_SESSION]['Member'] ); + if (!$memberID) { + return false; + } + $where = "T.member = $memberID"; + $type = 'Calendar'; + break; + case 'accom': + // Get event ID from session - if available + $accomID = ( $setId ? $setId : $_SESSION[GLM_EVENT_SESSION]['Accom'] ); + if (!$accomID) { + return false; + } + $where = "T.accommodation = $accomID"; + $type = 'Calendar'; + break; + case 'team': + $teamID = ( $setId ? $setId : $_SESSION[GLM_EVENT_SESSION]['Team'] ); + if (!$teamID) { + return false; + } + $where = " + T.member in ( + SELECT property + FROM eventmgt.team_property + WHERE team = $teamID + )"; + $type = 'Calendar'; + break; + default: + echo "Option not set"; + break; + } + + // Only look for inventory from now forward. + $where .= " AND T.date > 'now'"; + + // Get list of all available Events + $inventoryList = $this->getList($where); + + // Clean up and fix specific fields and find first date of inventory + if ($inventoryList != false) { + + $firstDate = strtotime('+5 years'); // Start with something far out in time + reset($inventoryList); + while( list($key, $val) = each( $inventoryList ) ) { + + $thisDate = strtotime($val['date']['date']); + + // Is this date earlier than any others? + if ($thisDate < $firstDate) { + $firstDate = $thisDate; + } + + // Convert dates to format required for fullcalendar + $inventoryList[$key]['cal_date'] = date('Y-m-d', $thisDate); + + // Make member_name copy safe for inclusion in JAVAscript code + $inventoryList[$key]['member_name_h'] = addslashes($val['property']); + + } + } + + // Create a summary for certain list options + $sum = array(); + $dates = array(); + $have_summary = false; + $total_properties = 0; + $total_assigned = array(); + $total_available = array(); + $total_sold = array(); + if ($type == 'Summary' && is_array($inventoryList) && count($inventoryList) > 0) { + + // Start by building list of all inventory dates + // *** should be able to do this from the event dates data *** + foreach ($inventoryList as $inv) { + // Add to dates list + $t = strtotime($inv['date']['date']); + $dates[$t] = date('m/d/Y', $t); + $total_assigned[$t] = 0; + $total_available[$t] = 0; + $total_sold[$t] = 0; + } + ksort($dates); + + // Now go through it again and build all the data + foreach ($inventoryList as $inv) { + // If event has not been set yet + $event_id = $inv['event_id']; + if (!isset($sum[$event_id])) { + $sum[$event_id] = array( + 'id' => $event_id, + 'name' => $inv['event'], + 'memb' => array() + ); + } + + // If member has not been set yet + $memb_id = $inv['member_id']; + if (!isset($sum[$event_id]['memb'][$memb_id])) { + + // Get Member credit card types + $sql = " + SELECT CT.ccard_type_name AS ccardName + FROM members.ccard_type CT, members.member_ccard_type MCT + WHERE MCT.member_id = $memb_id + AND CT.ccard_type_id = MCT.ccard_type_id + ORDER BY CT.ccard_type_name + "; + $stmt = $this->dbh->prepare($sql); + $stmt->execute(); + $cc_types = $stmt->fetchAll(PDO::FETCH_ASSOC); + if (count($cc_types) == 0) { + $cc_types = false; + } + + $sum[$event_id]['memb'][$memb_id] = array( + 'id' => $memb_id, + 'name' => $inv['member'], + 'street' => $inv['street'], + 'city' => $inv['city'], + 'accom' => array(), + 'cc_types' => $cc_types + ); + + $total_properties++; + } + + // If accommodation has not been set yet + $accom_id = $inv['accommodation_id']; + if (!isset($sum[$event_id]['memb'][$memb_id]['accom'][$accom_id])) { + $sum[$event_id]['memb'][$memb_id]['accom'][$accom_id] = array( + 'id' => $memb_id, + 'name' => $inv['accommodation'], + 'date' => array() + ); + + // Also build all the dates as empty entries + reset($dates); + while( list($k, $v) = each($dates) ) { + $sum[$event_id]['memb'][$memb_id]['accom'][$accom_id]['date'][$k] = false; + } + + } + + // Add this inventory item + $inven_id = $inv['id']; + $t = strtotime($inv['date']['date']); + $sum[$event_id]['memb'][$memb_id]['accom'][$accom_id]['date'][$t] = array( + 'id' => $inven_id, + 'date' => $inv['date']['date'], + 'assigned' => $inv['assigned'], + 'avail' => $inv['available'], + 'sold' => $inv['assigned'] - $inv['available'], + 'rate' => $inv['rate'] + ); + ksort($sum[$event_id]['memb'][$memb_id]['accom'][$accom_id]['date']); + + $total_assigned[$t] += $inv['assigned']; + $total_available[$t] += $inv['available']; + $total_sold[$t] += ($inv['assigned'] - $inv['available']); + + } + + $sum[$event_id]['total_properties'] = $total_properties; + $sum[$event_id]['total_assigned'] = $total_assigned; + $sum[$event_id]['total_available'] = $total_available; + $sum[$event_id]['total_sold'] = $total_sold; + + // Calculate overall uptake rate per day + $ta = 0; + $ts = 0; + $daily_uptake = array(); + while (list($k, $v) = each($total_assigned)) { + $ta += $v; + $ts += $total_sold[$k]; + + // Calculate uptake rate for this day + $sum[$event_id]['daily_uptake'][$k] = sprintf('%.2f', (($total_sold[$k] / $v) * 100) )."%"; + } + $sum[$event_id]['overall_uptake'] = sprintf('%.2f', (($ts / $ta) * 100) )."%"; + + $have_summary = true; + + } + + $r = array( + 'inventory' => $inventoryList, + 'firstDate' => $firstDate, + 'type' => $type, + 'dates' => $dates, + 'sum' => $sum, + 'have_sum' => $have_summary + ); + + return $r; + + } + + + /** + * Get Inventory Detail + * + * @return array + */ + function getInvenDetail($invID = false) + { + + // If an inventory ID is supplied + if ($invID) { + $inventoryID = $invID; + + // Otherwise is there a new inventory item selected selected? + } elseif (($inventoryID = filter_input(INPUT_GET, 'InvenID', FILTER_SANITIZE_NUMBER_INT))) { + + // If so then add it to the session + $_SESSION[GLM_EVENT_SESSION]['Inven'] = $inventoryID; + + } elseif (isset($_SESSION[GLM_EVENT_SESSION]['Inven'])) { + + // Otherwise, get the inventory ID from the session + $inventoryID = $_SESSION[GLM_EVENT_SESSION]['Inven']; + + } else { + + // Otherwise, we don't have an inventory id + return false; + + } + + $inventoryDetail = $this->getEntry($inventoryID); + + return $inventoryDetail; + + } + + + /** + * Edit Inventory + * + * @return array + */ + function editInven() + { + + if (($invenID = filter_input(INPUT_GET, 'InvenID', FILTER_SANITIZE_NUMBER_INT))) { + + // If so then add it to the session + $_SESSION[GLM_EVENT_SESSION]['Inven'] = $invenID; + + } elseif (isset($_SESSION[GLM_EVENT_SESSION]['Inven'])) { + + // Otherwise, get the inventory ID from the session + $invenID = $_SESSION[GLM_EVENT_SESSION]['Inven']; + + } else { + + // Otherwise, we don't have an inventory id + return false; + + } + + $invenDetail = $this->editEntry($invenID); + + return $invenDetail; + + } + + /** + * Check for other field related issues + * + * This function must be here because it's called from a function + * in dataAbstract. Simply return $r if there's nothing to check. + * + * @return array + */ + function checkOther($r) + { + parent::checkOther($r); +/* + $fd = $r['fieldData']; + + // Is Start date is later than End date + if (strtotime($fd['start_date']) > strtotime($fd['end_date'])) { + $r['fieldFail']['start_date'] = 'Start date is later than end date.'; + $r['status'] = false; + } + + // Is cutoff date is later than end date + if (strtotime($fd['cutoff_date']) > strtotime($fd['end_date'])) { + $r['fieldFail']['cutoff_date'] = 'Cutoff date is later than end date.'; + $r['status'] = false; + } +*/ + return $r; + } + + /** + * Update Inventory + * + * @return array + */ + function updateInven() + { + + if (($invenID = filter_input(INPUT_GET, 'InvenID', FILTER_SANITIZE_NUMBER_INT))) { + + // If so then add it to the session + $_SESSION[GLM_EVENT_SESSION]['Inven'] = $invenID; + + } elseif (isset($_SESSION[GLM_EVENT_SESSION]['Inven'])) { + + // Otherwise, get the inventory ID from the session + $invenID = $_SESSION[GLM_EVENT_SESSION]['Inven']; + + } else { + + // Otherwise, we don't have a inventory id + return false; + + } + + // Assume no delete and no delete failure + $delete = false; + $deleteFail = false; + $reason = array(); + + // Check if we have valid data + $r = $this->updateEntry($invenID, 'id', false); + if ($r['status']) { + + // check if this is a Delete request + if (isset($_REQUEST['submitType']) && $_REQUEST['submitType'] == 'Delete Selected Inventory') { + + // Check if there are room block associated with this inventory + $sql = " + SELECT COUNT(id) + FROM eventmgt.room_block_seg + WHERE event = ".$r['fieldData']['event_id']." + AND accommodation = ".$r['fieldData']['accommodation_id']."; + "; + $stmt = $this->dbh->prepare($sql); + $stmt->execute(); + $blockData = $stmt->fetch(PDO::FETCH_ASSOC); + if ($blockData['count'] > 0) { + // Can't delete because room blocks associated with this inventory exist + $r['status'] = false; + $reason[] = 'The selected inventory is in use in a room block.'; + $reason[] = 'Delete the room block first if you want to delete this inventory.'; + $delete = false; + $deleteFail = true; + } else { + // No room blocks so inventory may be deleted. + $delete = true; + } + } + + // Check if this is only the original date + if ($r['fieldStore']['date'] == $r['fieldStore']['end_date'] && + $r['fieldData']['date']['date'] == $_REQUEST['original_date']) { + + $fields = $this->fields; + unset($fields['end_date']); + $this->fields = $fields; + + // It's only the original date, so do again but store it this time or delete it + if ($delete) { + + // Delete requested + $sql = "DELETE FROM eventmgt.inventory + WHERE id = ".$r['fieldData']['id'].";"; + $stmt = $this->dbh->prepare($sql); + $stmt->execute(); + + $r['fieldData']['date']['date'] .= " *** DELETED *** "; + + } else { + + $r = $this->updateEntry($invenID); + + } + + } else { // This is either not the original date or it's a date range + + // Check for sane dates + if ($r['fieldData']['date']['timestamp'] > $r['fieldData']['end_date']['timestamp']) { + + $r['status'] = false; + $r['fieldFail']['end_date'] = "Must be equal to or later than From Date."; + + } else { + + $accom_id = ($_REQUEST['accom_id'] - 0); + $event_id = ($_REQUEST['event_id'] - 0); + $memb_id = ($_REQUEST['member_id'] - 0); + + // Delete any inventory for this accommodation and event + $sql = "DELETE FROM eventmgt.inventory + WHERE event = ".$event_id." + AND accommodation = ".$accom_id." + AND date >= '".$r['fieldData']['date']['date']."' + AND date <= '".$r['fieldData']['end_date']['date']."';"; + $stmt = $this->dbh->prepare($sql); + $stmt->execute(); + + // Check if this is a request to delete the inventory + if (isset($_REQUEST['submitType']) && $_REQUEST['submitType'] == 'Delete Selected Inventory') { + $r['fieldData']['date']['date'] .= " through ".$r['fieldData']['end_date']['date'].' *** DELETED ***'; + } else { + + // Insert updated inventory for date range (note incriment is a bit more to accommodate leap seconds) + $sql = "INSERT INTO eventmgt.inventory + (date, member, accommodation, event, assigned, available, rate) + VALUES + ('{date}', $memb_id, $accom_id, $event_id, ".$r['fieldStore']['assigned'].", + ".$r['fieldStore']['available'].", ".$r['fieldStore']['rate']." + ); + "; + + // For each date, create new inventory. + for ($d = $r['fieldData']['date']['timestamp'] ; + $d <= $r['fieldData']['end_date']['timestamp'] ; + $d = strtotime(date('m/d/Y', $d+86500))) { + + $date = date('m/d/Y', $d); + $s = str_replace('{date}', $date, $sql); + $stmt = $this->dbh->prepare($s); + $stmt->execute(); + + } + + // Change date on detail display to show range + $r['fieldData']['date']['date'] .= " through ".$r['fieldData']['end_date']['date']; + } + } + } + + } + + // Check if there was a delete failure + if ($deleteFail) { + $r['status'] = false; + if (is_array($r['reason'])) { + $reason = array_merge($r['reason'], $reason); + } + $r['reason'] = $reason; + } + + return $r; + + } + + + /** + * Add Inventory + * + * @return array + */ + function addInven() + { + $reason = array(); + + // Make sure an Event has been selected. + if (isset($_SESSION[GLM_EVENT_SESSION]['Event']) && $_SESSION[GLM_EVENT_SESSION]['Event'] != false) { + $eventID = $_SESSION[GLM_EVENT_SESSION]['Event']; + } else { + $reason[] = "No event has been selected. Please select an Event and Property before adding inventory."; + } + + // Get selected event and property data + $eventData = $this->getEventMemberData($eventID); + + // Set dates to default to event dates + $this->fields['start_date']['default'] = strtotime($eventData['event_start_date']); + $this->fields['end_date']['default'] = strtotime($eventData['event_end_date']); + $this->fields['min_nights']['default'] = $eventData['event_days']; + + // Get new entry fields + $r = $this->newEntry(); + + // Check for available properties/accommodations + if (count($r['fieldData']['accommodation']['pick_list']) == 0) { + $r['status'] = false; + $r['reason'][] = 'No property accommodations in system to select from. Please add accommodations to a property.'; + } + + // Add in static Event and Property data + $r['fieldData'] = array_merge($r['fieldData'], $eventData); + + // Add in member/accommodation data + $membAccom = $this->getMembAccomMatrix(); + $r['membAccom'] = $membAccom; + + // echo "
".print_r($r,1)."
"; + return $r; + + } + + /** + * Insert Inventory + * + * @return array + */ + function insertInven() + { + + // Get selected event and property data using ID's passed from form + $eventID = ($_REQUEST['event'] - 0); + $memberID = ($_REQUEST['member'] - 0); + $eventData = $this->getEventMemberData($eventID); + + // Process input, but don't store any result + $r = $this->insertEntry(false); + + // Add in static Event and Property data + $r['fieldData'] = array_merge($r['fieldData'], $eventData); + + // Check for sane dates + if ($r['fieldData']['start_date']['timestamp'] > $r['fieldData']['end_date']['timestamp']) { + $r['status'] = false; + $r['fieldFail']['start_date'] = 'First date may not be later than last date when creating inventory.'; + } + + if ($memberID > 0 && $r['status'] ) { + + // Check for existing inventory conflicting with this new inventory + $sql = "SELECT count(id) + FROM eventmgt.inventory + WHERE event = $eventID + AND member = $memberID + AND accommodation = ".$r['fieldStore']['accommodation']." + AND date BETWEEN ".$r['fieldStore']['start_date']." AND ".$r['fieldStore']['end_date']." + ;"; + $stmt = $this->dbh->prepare($sql); + $stmt->execute(); + $eventData = $stmt->fetch(PDO::FETCH_ASSOC); + + if ($eventData['count'] > 0) { + $r['status'] = false; + $r['fieldFail']['start_date'] = 'Inventory already exists for at least one of the dates requested.'; + } + } + + if ($memberID == 0) { + $r['fieldFail']['member'] = 'Member is required.'; + } + + // If it's OK to create the inventory + if ($r['status']) { + + // Add each night as separate inventory item + $s = $r['fieldData']['start_date']['timestamp']; + $e = $r['fieldData']['end_date']['timestamp']; + $sql = array(); + for ($date=$s ; $date<=$e ; $date=strtotime(date('m/d/Y',$date)." +1 day")) { + $sql[] = "INSERT INTO eventmgt.inventory + (event, member, accommodation, date, assigned, available, rate) + VALUES + ( + $eventID, $memberID, ".$r['fieldStore']['accommodation'].", + '".date('m/d/Y',$date)."', ".$r['fieldStore']['assigned'].", + ".$r['fieldStore']['assigned'].", ".$r['fieldStore']['rate']." + ); + \n"; + } +/* Not using event_prop table anymore + // Check for existing event/property table entry + $sql2 = "SELECT count(id) + FROM eventmgt.event_prop + WHERE event = $eventID + AND property = $memberID + ;"; + $stmt = $this->dbh->prepare($sql2); + $stmt->execute(); + $eventpropData = $stmt->fetch(PDO::FETCH_ASSOC); + + // If there's not an entry, add one + if ($eventpropData['count'] == 0) { + $sql[] = "INSERT INTO eventmgt.event_prop + (event, property) + VALUES + ($eventID, $memberID) + ;"; + + } +*/ + // Try to add this inventory + try { + $this->dbh->beginTransaction(); + foreach ($sql as $s) { + $this->dbh->exec($s); + } + $this->dbh->commit(); + } catch (Exception $e) { + $this->dbh->rollBack(); + $r['status'] = false; + $r['reason'][] = 'Unable to store new inventory for unknown reason. '; + // var_dump($e); + } + + // Add to event-property table + } + + // Add in member/accommodation data + $membAccom = $this->getMembAccomMatrix(); + if ($memberID > 0) { + $r['membSelected'] = $membAccom[$memberID]; + $membAccom[$memberID]['selected'] = true; + } + $r['membAccom'] = $membAccom; + + // Check for selected accommodation + $a = ($r['fieldData']['accommodation']['in'] - 0); + if ($a > 0) { + $r['membSelected']['accoms'][$a]['selected'] = true; + } + + + // If succesful then set current inventory to the one just inserted. + if ($r['status']) { + + $sql = "select currval('inventory_id_seq');"; + $stmt = $this->dbh->prepare($sql); + $stmt->execute(); + $last = $stmt->fetch(PDO::FETCH_ASSOC); + $r['insertedID'] = $last['currval'] ; + + } + + return $r; + + } + + + + /** + * getMembAccomMatrix + * + * @param integer $memberID + */ + function getMembAccomMatrix() + { + + // Get property/accommodation matrix + if (count($reason) == 0) { + $sql = "SELECT M.id AS memb_id, + M.name AS memb_name, + A.id AS accom_id, + A.name AS accom_name + FROM eventmgt.member M, eventmgt.accommodation A + WHERE A.member = M.id + ORDER BY M.name, A.sort + ;"; + $stmt = $this->dbh->prepare($sql); + $stmt->execute(); + $membAccomData = $stmt->fetchAll(PDO::FETCH_ASSOC); + if (count($membAccomData) == 0) { + $reason[] = "No properties with accommodations are currently listed in the system."; + } + } + + // Build array of Members with their accommodations + $membAccom = array(); + foreach ($membAccomData as $d) { + + // If member hasn't been added to array yet + if (!isset($membAccom[$d['memb_id']])) { + $membAccom[$d['memb_id']] = array( + 'membID' => $d['memb_id'], + 'membName' => $d['memb_name'], + 'accoms' => array() + ); + } + + // Add this accommodation + $membAccom[$d['memb_id']]['accoms'][$d['accom_id']] = array( + 'accomID' => $d['accom_id'], + 'accomName' => $d['accom_name'] + ); + } + + return $membAccom; + } + + /** + * Get Event and Member information for specified event and member ID + * + * @param integer $eventID + * @param integer $memberID + */ + function getEventMemberData($eventID) + { + // Get event Data + $sql = "SELECT name, event_code, start_date, end_date, days + FROM eventmgt.event + WHERE id = $eventID; + "; + $stmt = $this->dbh->prepare($sql); + $stmt->execute(); + $eventData = $stmt->fetch(PDO::FETCH_ASSOC); + + // Add event information to returned array + $r['event'] = $eventData['name']; + $r['event_code'] = $eventData['event_code']; + $r['event_id'] = $eventID; + $r['event_days'] = $eventData['days']; + $r['event_start_date'] = $eventData['start_date']; + $r['event_end_date'] = $eventData['end_date']; + +/* + // Get property Data + $sql = "SELECT name + FROM eventmgt.member + WHERE id = $memberID; + "; + $stmt = $this->dbh->prepare($sql); + $stmt->execute(); + $memberData = $stmt->fetch(PDO::FETCH_ASSOC); + + // Add event information to returned array + $r['member'] = $memberData['name']; + $r['member_id'] = $memberID; +*/ + return $r; + + } + + + +} + + + + +?> diff --git a/classes/data/dataMemberScansFor.php b/classes/data/dataMemberScansFor.php new file mode 100644 index 0000000..79d6da1 --- /dev/null +++ b/classes/data/dataMemberScansFor.php @@ -0,0 +1,234 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: dataMemberScansFor.php,v 1.0 2011/01/25 19:31:47 cscott Exp $ + * @link http://www.gaslightmedia.com + */ + +require_once DATA_ABSTRACT; + +/** + * EventManagementDataMemberScansFor class + * + * PHP version 5 + * + * @category Data + * @package EventManagement + * @author Chuck Scott + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: dataMemberScansFor,v 1.0 2011/01/25 19:31:47 cscott Exp $ + * @link <> + */ +class EventManagementDataMemberScansFor extends DataAbstract +{ + /** + * Tables + * + * @var $ini + * @access public + */ + public $table = 'eventmgt.member_scans_for'; + + /** + * Field definitions + * + * 'type' is type of field as defined by the application + * text Regular text field + * pointer Pointer to an entry in another table + * 'filters' is the filter name for a particular filter ID in PHP filter functions + * See PHP filter_id() + * + * 'use' is when to use the field + * l = List + * g = Get + * n = New + * i = Insert + * e = Edit + * u = Update + * d = Delete + * a = All + * + * @var $ini + * @access public + */ + public $fields = false; + + /** + * Constructor + * + * @param object $d database connection + * + * @return void + * @access public + */ + function __construct($dbh, $config) + { + + parent::__construct($dbh, $config); + + $this->fields = array( + + // Record ID + 'id' => array( + 'field' => 'id', + 'as' => false, + 'type' => 'integer', + 'required' => true, + 'unique' => true, + 'default' => false, + 'use' => 'lged' + ), + + // Pointer to a member who does the scanning + 'member' => array( + 'field' => 'member', + 'as' => false, + 'type' => 'integer', + 'required' => true, + 'unique' => false, + 'use' => 'a' + ), + + // Name of member who does the scanning + 'member_name' => array( + 'field' => 'member', + 'as' => 'member_name', + 'type' => 'pointer', + 'p_table' => 'eventmgt.member', + 'p_field' => 'name', + 'p_id' => 'id', + 'p_static' => true, + 'required' => false, + 'unique' => false, + 'default' => false, + 'view_only' => true, + 'use' => 'gleu' + ), + + // Pointer to a member who the scanning is for + 'scans_for' => array( + 'field' => 'scans_for', + 'as' => false, + 'type' => 'integer', + 'required' => true, + 'unique' => false, + 'use' => 'a' + ), + + // Name of member who does the scanning + 'scans_for_name' => array( + 'field' => 'scans_for', + 'as' => 'scans_for_name', + 'type' => 'pointer', + 'p_table' => 'eventmgt.member', + 'p_field' => 'name', + 'p_id' => 'id', + 'p_static' => true, + 'required' => false, + 'unique' => false, + 'default' => false, + 'view_only' => true, + 'use' => 'gleu' + ) + + ); + } + + /** + * Get List + * + * + * @return object containing array as sub-objects + */ + public function getMemberScansForList($memberID = false) + { + + // if member ID is not supplied, try to find it + if ($memberID == false) { + + // Check submit input + $memberID = filter_input(INPUT_GET, 'MemberID', FILTER_SANITIZE_NUMBER_INT); + + // If we still don't have it + if ($memberID == false || $memberID < 1) { + + // Try the session + if (isset($_SESSION[GLM_EVENT_SESSION]['Member'])) { + + $memberID = $_SESSION[GLM_EVENT_SESSION]['Member']; + + } + + } + + } + + // If we still don't have a valid member ID + if ($memberID == false || ($memberID - 0) <= 0) { + return false; + } + + $where = "T.member = $memberID"; + + // Get the list of members a member scans for + $memberScansFor = $this->getList($where); + if (count($memberScansFor) == 0) { + return false; + } + + return $memberScansFor; + + } + + /** + * Update member scans for list + * + * Expects request input "selectedMember[id]" array. + */ + + public function updateMemberScansForList($memberID = false) + { + + if ($memberID == false) { + return false; + } + + // Query to delete current Member Scans For list + $sql = " + BEGIN; + DELETE FROM eventmgt.member_scans_for + WHERE member = $memberID; + "; + + // Now add in any members who this member will be scanning for + $newMembers = $_REQUEST['selectedMember']; + if ($newMembers) { + foreach ($newMembers as $m) { + $sql .= " + INSERT INTO eventmgt.member_scans_for + ( member, scans_for ) + VALUES ( $memberID, $m ) + ;"; + } + } + $sql .= "COMMIT;"; + $this->dbh->exec($sql); + + return $this->getMemberScansForList($memberID); + + } + +} + + + + +?> \ No newline at end of file diff --git a/classes/data/dataMembers.php b/classes/data/dataMembers.php new file mode 100644 index 0000000..9871c92 --- /dev/null +++ b/classes/data/dataMembers.php @@ -0,0 +1,1219 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: dataMembers.php,v 1.0 2011/01/25 19:31:47 cscott Exp $ + * @link http://www.gaslightmedia.com/ + */ + +require_once DATA_ABSTRACT; + +/** + * EventManagementDataMembers class + * + * PHP version 5 + * + * @category Data + * @package EventManagement + * @author Chuck Scott + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: dataMembers.php,v 1.0 2011/01/25 19:31:47 cscott Exp $ + * @link http://www.gaslightmedia.com/ + */ +class EventManagementDataMembers extends DataAbstract +{ + /** + * Field definitions + * + * @var $ini + * @access public + */ + public $table = 'eventmgt.member'; + + /** + * Field definitions + * + * 'type' is type of field as defined by the application + * text Regular text field + * pointer Pointer to an entry in another table + * 'filters' is the filter name for a particular filter ID in PHP filter functions + * See PHP filter_id() + * + * 'use' is when to use the field + * l = List + * g = Get + * n = New + * i = Insert + * e = Edit + * u = Update + * d = Delete + * a = All + * + * @var $ini + * @access public + */ + public $fields = false; + + /** + * Constructor + * + * @param object $d database connection + * + * @return void + * @access public + */ + function __construct($dbh, $config) + { + + parent::__construct($dbh, $config); + + $this->fields = array( + + 'id' => array( + 'field' => 'id', + 'as' => false, + 'type' => 'integer', + 'required' => false, + 'unique' => false, + 'default' => false, + 'view_only' => true, + 'use' => 'a' + ), + + // Member Type + 'member_type' => array( + 'field' => 'member_type', + 'as' => false, + 'type' => 'list', + 'list' => $this->config->member_type->toArray(), + 'required' => false, + 'unique' => false, + 'default' => 1, + 'use' => 'a' + ), + + // Description + 'descr' => array( + 'field' => 'descr', + 'as' => false, + 'type' => 'text', + 'filter' => FILTER_SANITIZE_MAGIC_QUOTES, + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // E-Mail + 'email' => array( + 'field' => 'email', + 'as' => false, + 'type' => 'email', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Processing E-Mail + 'proc_email' => array( + 'field' => 'proc_email', + 'as' => false, + 'type' => 'email', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Processing E-Mail #2 + 'proc_email2' => array( + 'field' => 'proc_email2', + 'as' => false, + 'type' => 'email', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Notify member of each checkout + 'checkout_notify' => array( + 'field' => 'checkout_notify', + 'as' => false, + 'type' => 'checkbox', + 'required' => false, + 'unique' => false, + 'default' => true, + 'use' => 'a' + ), + + // Check In Time + 'check_in' => array( + 'field' => 'check_in', + 'as' => false, + 'type' => 'time', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Check Out Time + 'check_out' => array( + 'field' => 'check_out', + 'as' => false, + 'type' => 'time', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Defalut Ticket Policy + 'def_ticket_pol' => array( + 'field' => 'def_ticket_pol', + 'as' => false, + 'type' => 'text', + 'filter' => FILTER_SANITIZE_MAGIC_QUOTES, + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + + /* + * Fields used whether or not we're using an integrated member database + */ + +/* not using policies at this level for now + // Defalut Reservation Policy + 'def_res_pol' => array( + 'field' => 'def_res_pol', + 'as' => false, + 'type' => 'text', + 'filter' => FILTER_SANITIZE_MAGIC_QUOTES, + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + + // Defalut Cancel Policy + 'def_can_pol' => array( + 'field' => 'def_can_pol', + 'as' => false, + 'type' => 'text', + 'filter' => FILTER_SANITIZE_MAGIC_QUOTES, + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), +*/ + // Member amenity #1 + 'amen_1' => array( + 'field' => 'amen_1', + 'as' => false, + 'type' => 'checkbox', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Member amenity #2 + 'amen_2' => array( + 'field' => 'amen_2', + 'as' => false, + 'type' => 'checkbox', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Member amenity #3 + 'amen_3' => array( + 'field' => 'amen_3', + 'as' => false, + 'type' => 'checkbox', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Member amenity #4 + 'amen_4' => array( + 'field' => 'amen_4', + 'as' => false, + 'type' => 'checkbox', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Member amenity #5 + 'amen_5' => array( + 'field' => 'amen_5', + 'as' => false, + 'type' => 'checkbox', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Member amenity #6 + 'amen_6' => array( + 'field' => 'amen_6', + 'as' => false, + 'type' => 'checkbox', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Member amenity #7 + 'amen_7' => array( + 'field' => 'amen_7', + 'as' => false, + 'type' => 'checkbox', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Member amenity #8 + 'amen_8' => array( + 'field' => 'amen_8', + 'as' => false, + 'type' => 'checkbox', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Member amenity #9 + 'amen_9' => array( + 'field' => 'amen_9', + 'as' => false, + 'type' => 'checkbox', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Member amenity #10 + 'amen_10' => array( + 'field' => 'amen_10', + 'as' => false, + 'type' => 'checkbox', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Intro Text for front-end + 'intro_text' => array( + 'field' => 'intro_text', + 'as' => false, + 'type' => 'text', + 'filter' => FILTER_UNSAFE_RAW, + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Checkout E-Mail + 'checkout_email' => array( + 'field' => 'checkout_email', + 'as' => false, + 'type' => 'text', + 'filter' => FILTER_SANITIZE_MAGIC_QUOTES, + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Notes + 'notes' => array( + 'field' => 'notes', + 'as' => false, + 'type' => 'text', + 'filter' => FILTER_SANITIZE_MAGIC_QUOTES, + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ) + + ); + + + /* + * Fields used if we're using an integrated member database + */ + if ($this->config->option->member_db_integrated) { + + $integratedDb = array( + + // Member name - From main member db - Used only if db is Integrated + 'member_name' => array( + 'field' => 'id', // ID in member table is same as in eventmgt.member + 'as' => 'member_name', + 'type' => 'pointer', + 'p_table' => 'members.member', + 'p_field' => 'member_name', + 'p_id' => 'member_id', + // Only permit members set at providing accommodations + 'p_where' => 'member_id in + ( + SELECT DISTINCT member_id + FROM members.member_category + WHERE category_id IN + (SELECT category_id FROM members.category WHERE accommodations) + )', + 'required' => true, + 'unique' => true, + 'default' => false, + 'use' => 'nid' + ), + + // Member name - From main member db - Used only if db is Integrated + 'member_name_view' => array( + 'field' => 'id', // ID in member table is same as in eventmgt.member + 'as' => 'member_name', + 'type' => 'pointer', + 'p_table' => 'members.member', + 'p_field' => 'member_name', + 'p_id' => 'member_id', + 'p_static' => true, + 'required' => true, + 'unique' => true, + 'default' => false, + 'view_only' => true, + 'use' => 'gleu' + ), + + // Member login - From main member db - Used only if db is Integrated + 'member_login_view' => array( + 'field' => 'id', // ID in member table is same as in eventmgt.member + 'as' => 'member_login', + 'type' => 'pointer', + 'p_table' => 'members.member', + 'p_field' => 'member_login', + 'p_id' => 'member_id', + 'p_static' => true, + 'required' => true, + 'unique' => true, + 'default' => false, + 'view_only' => true, + 'use' => 'gleu' + ), + + // Member password - From main member db - Used only if db is Integrated + 'member_passwd_view' => array( + 'field' => 'id', // ID in member table is same as in eventmgt.member + 'as' => 'member_passwd', + 'type' => 'pointer', + 'p_table' => 'members.member', + 'p_field' => 'member_passwd', + 'p_id' => 'member_id', + 'p_static' => true, + 'required' => false, + 'unique' => true, + 'default' => false, + 'view_only' => true, + 'use' => 'gleu' + ), + + // Member Street Address - From main member db + 'member_street' => array( + 'field' => 'id', // ID in member table is same as in eventmgt.member + 'as' => 'street', + 'type' => 'pointer', + 'p_table' => 'members.member', + 'p_field' => 'street', + 'p_id' => 'member_id', + 'required' => true, + 'unique' => true, + 'default' => false, + 'view_only' => true, + 'use' => 'gleu' + ), + + // Member City - From main member db + 'member_city' => array( + 'field' => 'id', // ID in member table is same as in eventmgt.member + 'as' => 'city', + 'type' => 'pointer', + 'p_table' => 'members.city', + 'p_field' => 'city_name', + 'p_id' => 'city_id', + 'p_where' => 'M.member_id = T.id AND city.city_id = M.city_id', + 'p_from' => 'members.member M', + 'p_static' => true, + 'required' => true, + 'unique' => true, + 'default' => false, + 'view_only' => true, + 'use' => 'gleu' + ), + + // Member phone - From main member db + 'member_phone' => array( + 'field' => 'id', // ID in member table is same as in eventmgt.member + 'as' => 'phone', + 'type' => 'pointer', + 'p_table' => 'members.member', + 'p_field' => 'phone', + 'p_id' => 'member_id', + 'required' => true, + 'unique' => true, + 'default' => false, + 'view_only' => true, + 'use' => 'gleu' + ), + + // Member Lat - From main member db + 'member_lat' => array( + 'field' => 'id', // ID in member table is same as in eventmgt.member + 'as' => 'lat', + 'type' => 'pointer', + 'p_table' => 'members.member', + 'p_field' => 'lat', + 'p_id' => 'member_id', + 'required' => false, + 'unique' => true, + 'default' => false, + 'view_only' => true, + 'use' => 'gleu' + ), + + // Member Lon - From main member db + 'member_lon' => array( + 'field' => 'id', // ID in member table is same as in eventmgt.member + 'as' => 'lon', + 'type' => 'pointer', + 'p_table' => 'members.member', + 'p_field' => 'lon', + 'p_id' => 'member_id', + 'required' => false, + 'unique' => true, + 'default' => false, + 'view_only' => true, + 'use' => 'gleu' + ), + + // Member number of rooms at property + 'prop_rooms' => array( + 'field' => 'id', // ID in member table is same as in eventmgt.member + 'as' => 'prop_rooms', + 'type' => 'pointer', + 'p_table' => 'members.member_accommodations', + 'p_field' => 'num_rooms', + 'p_id' => 'member_id', + 'required' => false, + 'unique' => true, + 'default' => false, + 'view_only' => true, + 'use' => 'gleu' + ) + + ); + + $this->fields = array_merge($this->fields, $integratedDb); + + } + + + /* + * Fields used if we're not using an integrated database + */ + if (!$this->config->option->member_db_integrated) { + + $nonIntegratedDb = array( + + // Member Name + 'name' => array( + 'field' => 'name', + 'as' => false, + 'type' => 'text', + 'required' => true, + 'unique' => true, + 'default' => false, + 'use' => 'a' + ), + + // Address Line 1 + 'addr1' => array( + 'field' => 'addr1', + 'as' => false, + 'type' => 'text', + 'required' => true, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Address Line 2 + 'addr2' => array( + 'field' => 'addr2', + 'as' => false, + 'type' => 'text', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // City + 'city' => array( + 'field' => 'city', + 'as' => false, + 'type' => 'text', + 'required' => true, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // State + 'state' => array( + 'field' => 'state', + 'as' => false, + 'type' => 'list', + 'list' => $this->config->states->toArray(), + 'required' => true, + 'unique' => false, + 'default' => 'MI', + 'use' => 'a' + ), + + // Country + 'country' => array( + 'field' => 'country', + 'as' => false, + 'type' => 'list', + 'list' => $this->config->countries->toArray(), + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // ZIP + 'zip' => array( + 'field' => 'zip', + 'as' => false, + 'type' => 'text', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Latitude + 'lat' => array( + 'field' => 'lat', + 'as' => false, + 'type' => 'float', + 'required' => false, + 'unique' => false, + 'default' => 45, + 'use' => 'a' + ), + + // Longitude + 'lon' => array( + 'field' => 'lon', + 'as' => false, + 'type' => 'float', + 'required' => false, + 'unique' => false, + 'default' => -84, + 'use' => 'a' + ), + + // Member phone - From main member db + 'phone' => array( + 'field' => 'phone', // ID in member table is same as in eventmgt.member + 'as' => false, + 'type' => 'text', + 'required' => true, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Credit Cards Accepted - multi-pick + 'cards_accepted' => array( + 'field' => 'cards_accepted', + 'as' => false, + 'type' => 'bitmap', + 'bitmap' => $this->config->ccard->toArray(), + 'required' => false, + 'unique' => false, + 'default' => 0, // Note that this is a bitmap of card indexes + 'use' => 'a' + ), + + // Payment Gateway + 'payment_gateway' => array( + 'field' => 'payment_gateway', + 'as' => false, + 'type' => 'list', + 'list' => $this->config->ccard_processor->toArray(), + 'required' => false, + 'unique' => false, + 'default' => '99', + 'use' => 'a' + ), + + // Payment Gateway Parameter 1 (Authorize.net: login, Merchant Solutions: acctid) + 'gateway_par1' => array( + 'field' => 'gateway_par1', + 'as' => false, + 'type' => 'text', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Payment Gateway Parameter 2 (Authorize.net: key, Merchant Solutions: merchantpin) + 'gateway_par2' => array( + 'field' => 'gateway_par2', + 'as' => false, + 'type' => 'text', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Payment Gateway Parameter 3 (Authorize.net: test, Merchant Solutions: n/a) + // test: LOCAL_TEST, LOCAL_FAIL, TRUE, FALSE (Must be FALSE for production) + 'gateway_par3' => array( + 'field' => 'gateway_par3', + 'as' => false, + 'type' => 'list', + 'list' => $this->config->cc_mode->toArray(), + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Payment Gateway Parameter 4 (Authorize.net: Send Conf Flag, Merchant Solutions: n/a) + 'gateway_par4' => array( + 'field' => 'gateway_par4', + 'as' => false, + 'type' => 'checkbox', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Payment Gateway Parameter 5 (Authorize.net: Merchant Email, Merchant Solutions: n/a) + 'gateway_par5' => array( + 'field' => 'gateway_par5', + 'as' => false, + 'type' => 'text', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // PayPal enabled flag + 'paypal' => array( + 'field' => 'paypal', + 'as' => false, + 'type' => 'checkbox', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // PayPal Client ID + 'paypal_client_id' => array( + 'field' => 'paypal_client_id', + 'as' => false, + 'type' => 'text', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // PayPal Secret + 'paypal_secret' => array( + 'field' => 'paypal_secret', + 'as' => false, + 'type' => 'text', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // PayPal payment mode + // test: + 'paypal_mode' => array( + 'field' => 'paypal_mode', + 'as' => false, + 'type' => 'list', + 'list' => $this->config->paypal_mode->toArray(), + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Member Image + 'image' => array( + 'field' => 'image', + 'as' => false, + 'type' => 'image', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Parking Map + 'parking_map' => array( + 'field' => 'parking_map', + 'as' => false, + 'type' => 'image', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Ticket Sector Map + 'ticket_sec_map' => array( + 'field' => 'ticket_sec_map', + 'as' => false, + 'type' => 'image', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Ticket Policy + 'ticket_policy' => array( + 'field' => 'ticket_policy', + 'as' => false, + 'type' => 'text', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Ticket Special Request Accepted + 'ticket_spec_req' => array( + 'field' => 'ticket_spec_req', + 'as' => false, + 'type' => 'checkbox', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Sort order + 'sort' => array( + 'field' => 'sort', + 'as' => false, + 'type' => 'integer', + 'required' => true, + 'unique' => false, + 'default' => 999, + 'use' => 'a' + ), + + // Member account active + 'active' => array( + 'field' => 'active', + 'as' => false, + 'type' => 'checkbox', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ) + ); + + $this->fields = array_merge($this->fields, $nonIntegratedDb); + + } + + } + + /** + * Get Members list + * + * @param string type of events list + * + * @return object containing array as sub-objects + */ + function getMembersList($option = 'event', $where = 'TRUE', $sort = 'name') + { + + // Check if a member ID was submitted + $locationID = filter_input(INPUT_GET, 'locationID', FILTER_SANITIZE_NUMBER_INT); + if ($locationID) { + $option = 'member'; + } + + if ($option == 'all') { + $_SESSION[GLM_EVENT_SESSION]['Event'] = false; + } + + // Get event ID from session - if available + $eventID = $_SESSION[GLM_EVENT_SESSION]['Event']; + + // Get any specified member listing option - default to event + if (($membersListOption = filter_input(INPUT_GET, 'MembersListOption', FILTER_SANITIZE_STRING))) { + $option = $membersListOption; + } + + // Select type of list + $sortByDist = false; + switch ($option) { + + case 'all': + break; + + case 'active': + $where .= ' AND active'; + break; + + case 'accom': + $where .= " AND id in + ( + SELECT DISTINCT member + FROM eventmgt.accommodation + ) + "; + break; + + case 'member': + $where .= " AND active AND id = ".($locationID - 0); + break; + + case 'event': + if (!$eventID) { + return false; + } + $where .= "AND id IN + ( + SELECT DISTINCT member + FROM eventmgt.inventory + WHERE conv = $eventID + ) + "; + /* Not using event_prop anymore + SELECT DISTINCT property + FROM eventmgt.event_prop + WHERE event = $eventID + */ + $sortByDist = true; + break; + + case 'type1': + $where .= " AND member_type = 1 AND active"; + break; + + case 'type2': + $where .= " AND member_type = 2 AND active"; + break; + + case 'type3': + $where .= " AND member_type = 3 AND active"; + break; + + default: + echo "Option not set"; + break; + } + + // Get Members List + $membersList = $this->getList($where, $sort); + + // Add distances to the member data and sort by distance + if ($sortByDist) { + if (!class_exists('EventManagementGeoCalculations')) { + require COMMON_APP_BASE.APP_VERSION.'/classes/GeoCalculations.php'; + } + $Geo = new EventManagementGeoCalculations($this->dbh); + $membersList = $Geo->getMemberEventDistance( $eventID, $membersList, 'lat', 'lon', 'distance', 'duration', 'id', true); + } + + // echo "
".print_r($membersList,1)."
"; + return $membersList; + } + + + /** + * Get Member Detail + * + * @return array + */ + function getMemberDetail($memberID = false) + { + $this->optionIncludeSelectListData = false; + + // If a member ID has been supplied + if ($memberID != false) { + + $_SESSION[GLM_EVENT_SESSION]['Member'] = $memberID; + + } elseif (($memberID = filter_input(INPUT_GET, 'MemberID', FILTER_SANITIZE_NUMBER_INT))) { + + // Otherwise if there a new member ID supplied via the request + $_SESSION[GLM_EVENT_SESSION]['Member'] = $memberID; + + } elseif (isset($_SESSION[GLM_EVENT_SESSION]['Member'])) { + + // Otherwise, get the event ID from the session + $memberID = $_SESSION[GLM_EVENT_SESSION]['Member']; + + } else { + + // Otherwise, we don't have an event id + return false; + + } + + $memberDetail = $this->getEntry($memberID); + + // echo "
".print_r($memberDetail,1)."
"; + return $memberDetail; + + } + + + /** + * Edit Member + * + * @return array + */ + function editMember() + { + // Is there a new member code selected? + if (($memberID = filter_input(INPUT_GET, 'MemberID', FILTER_SANITIZE_NUMBER_INT))) { + + // If so then add it to the session + $_SESSION[GLM_EVENT_SESSION]['Member'] = $memberID; + + } elseif (isset($_SESSION[GLM_EVENT_SESSION]['Member'])) { + + // Otherwise, get the member ID from the session + $memberID = $_SESSION[GLM_EVENT_SESSION]['Member']; + + } else { + + // Otherwise, we don't have a member id + return false; + + } + + $memberDetail = $this->editEntry($memberID); + + return $memberDetail; + + } + + /** + * Check for other field related issues + * + * This function must be here because it's called from a function + * in dataAbstract. Simply return $r if there's nothing to check. + * + * @return array + */ + function checkOther($r) + { + parent::checkOther($r); +/* + $fd = $r['fieldData']; + + // Is Start date is later than End date + if (strtotime($fd['start_date']) > strtotime($fd['end_date'])) { + $r['fieldFail']['start_date'] = 'Start date is later than end date.'; + $r['status'] = false; + } + + // Is cutoff date is later than end date + if (strtotime($fd['cutoff_date']) > strtotime($fd['end_date'])) { + $r['fieldFail']['cutoff_date'] = 'Cutoff date is later than end date.'; + $r['status'] = false; + } +*/ + return $r; + } + + /** + * Update Member + * + * @return array + */ + function updateMember() + { + + // Is there a new event code selected? + if (($memberID = filter_input(INPUT_GET, 'MemberID', FILTER_SANITIZE_NUMBER_INT))) { + + // If so then add it to the session + $_SESSION[GLM_EVENT_SESSION]['Member'] = $memberID; + + } elseif (isset($_SESSION[GLM_EVENT_SESSION]['Member'])) { + + // Otherwise, get the member ID from the session + $memberID = $_SESSION[GLM_EVENT_SESSION]['Member']; + + } else { + + // Otherwise, we don't have a member id + return false; + + } + + // Try to update this data + $r = $this->updateEntry($memberID); + + // echo "
".print_r($r,1)."
"; + return $r; + + } + + /** + * Insert Member + * + * @return array + */ + function insertMember() + { + + $r = $this->insertEntry(); + + // If succesful then set current member to the one just inserted. + if ($r['status']) { + $_SESSION[GLM_EVENT_SESSION]['Member'] = $r['insertedID']; + } + + return $r; + + } + + + /** + * Delete Member + * + * @param $confirm bool False to ask if user wants to delete and true to actually delete + * + * @return array + */ + function memberDelete($confirm = false) + { + + // Is there a new member code selected? + if (($memberID = filter_input(INPUT_GET, 'MemberID', FILTER_SANITIZE_NUMBER_INT))) { + + // If so then add it to the session + $_SESSION[GLM_EVENT_SESSION]['Member'] = $memberID; + + } elseif (isset($_SESSION[GLM_EVENT_SESSION]['Member'])) { + + // Otherwise, get the member ID from the session + $memberID = $_SESSION[GLM_EVENT_SESSION]['Member']; + + } else { + + // Otherwise, we don't have a member id + return false; + + } + + /* + * Delete all supporting information + * + * Contacts + * Performance + * Sections + * Events + * Tickets + * Ticket inventory + * Orders + * Sold + * + * + * inven_hold gets cleaned out and does not need to be deleted + */ +/* + DELETE FROM eventmgt.ticket_order + WHERE member = $memberID; + DELETE FROM eventmgt.ticket_sold + WHERE member = $memberID; +*/ + $sql = " + DELETE FROM eventmgt.res_contact + WHERE contact_type = ".$this->config->reference_type->member." + AND affiliation = $memberID; + DELETE FROM eventmgt.section + WHERE member = $memberID; + DELETE FROM eventmgt.ticket_inventory + WHERE ticket in ( + SELECT id + FROM eventmgt.ticket + WHERE member = $memberID + ); + DELETE FROM eventmgt.ticket + WHERE member = $memberID; + DELETE FROM eventmgt.performance + WHERE member = $memberID; + "; + $this->dbh->exec($sql); + + // Delete member and return their old data + $memberDetail = $this->deleteEntry($memberID, $confirm); + + return $memberDetail; + + } + + + +} + + + + +?> diff --git a/classes/data/dataMisc.php b/classes/data/dataMisc.php new file mode 100644 index 0000000..ca124a7 --- /dev/null +++ b/classes/data/dataMisc.php @@ -0,0 +1,283 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: dataMisc.php,v 1.0 2011/01/25 19:31:47 cscott Exp $ + * @link <> + */ + +require_once DATA_ABSTRACT; + +/** + * EventManagementDataMisc class + * + * PHP version 5 + * + * @category Data + * @package EventManagement + * @author Chuck Scott + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: dataMisc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + * @link <> + */ +class EventManagementDataMisc extends DataAbstract +{ + /** + * Tables + * + * @var $ini + * @access public + */ + public $table = 'eventmgt.misc'; + + /** + * Field definitions + * + * 'type' is type of field as defined by the application + * text Regular text field + * pointer Pointer to an entry in another table + * 'filters' is the filter name for a particular filter ID in PHP filter functions + * See PHP filter_id() + * + * 'use' is when to use the field + * l = List + * g = Get + * n = New + * i = Insert + * e = Edit + * u = Update + * d = Delete + * a = All + * + * @var $ini + * @access public + */ + public $fields = false; + + /** + * Constructor + * + * @param object $d database connection + * + * @return void + * @access public + */ + function __construct($dbh, $config) + { + + parent::__construct($dbh, $config); + + $this->fields = array( + + // ID - in this table there's only one entry and the ID is always 1 + 'id' => array( + 'field' => 'id', + 'as' => false, + 'type' => 'integer', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Text for intro page + 'intro_text' => array( + 'field' => 'intro_text', + 'as' => false, + 'type' => 'text', + 'filter' => FILTER_UNSAFE_RAW, + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Text for section selection page + 'section_text' => array( + 'field' => 'section_text', + 'as' => false, + 'type' => 'text', + 'filter' => FILTER_UNSAFE_RAW, + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Text for ticket selection page + 'ticket_text' => array( + 'field' => 'ticket_text', + 'as' => false, + 'type' => 'text', + 'filter' => FILTER_UNSAFE_RAW, + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Text for ticket date, time, section, quantity, selection page + 'ticket_opt_text' => array( + 'field' => 'ticket_opt_text', + 'as' => false, + 'type' => 'text', + 'filter' => FILTER_UNSAFE_RAW, + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Text for cart page + 'cart_text' => array( + 'field' => 'cart_text', + 'as' => false, + 'type' => 'text', + 'filter' => FILTER_UNSAFE_RAW, + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Text for checkout page + 'checkout_text' => array( + 'field' => 'checkout_text', + 'as' => false, + 'type' => 'text', + 'filter' => FILTER_UNSAFE_RAW, + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Text for checkout success page + 'success_text' => array( + 'field' => 'success_text', + 'as' => false, + 'type' => 'text', + 'filter' => FILTER_UNSAFE_RAW, + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Google tracking script for checkout page + 'tracking' => array( + 'field' => 'tracking', + 'as' => false, + 'type' => 'text', + 'filter' => FILTER_UNSAFE_RAW, + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // No payment reasons for admin checkout + 'no_payment_reasons' => array( + 'field' => 'no_payment_reasons', + 'as' => false, + 'type' => text, + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Optional Checkout Field Name #1 + 'opt_field_1_name' => array( + 'field' => 'opt_field_1_name', + 'as' => false, + 'type' => text, + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Optional Checkout Field Name #2 + 'opt_field_2_name' => array( + 'field' => 'opt_field_2_name', + 'as' => false, + 'type' => text, + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Optional Checkout Field Name #3 + 'opt_field_3_name' => array( + 'field' => 'opt_field_3_name', + 'as' => false, + 'type' => text, + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // SSL Certificate Seal Head Script + 'ssl_seal_head_script' => array( + 'field' => 'ssl_seal_head_script', + 'as' => false, + 'type' => 'text', + 'filter' => FILTER_UNSAFE_RAW, + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // SSL Certificate Seal Body Script + 'ssl_seal_body_script' => array( + 'field' => 'ssl_seal_body_script', + 'as' => false, + 'type' => 'text', + 'filter' => FILTER_UNSAFE_RAW, + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Central Payment Location + 'central_payment' => array( + 'field' => 'central_payment', + 'as' => false, + 'type' => 'pointer', + 'p_table' => 'eventmgt.member', + 'p_field' => 'name', + 'p_id' => 'id', + 'required' => false, + 'unique' => false, + 'default' => 0, + 'use' => 'a' + ), + + // Central Payment Location ID + 'central_payment_id' => array( + 'field' => 'central_payment', + 'as' => 'central_payment_id', + 'type' => 'integer', + 'required' => false, + 'unique' => false, + 'default' => 0, + 'use' => 'g' + ) + + ); + } + +} +?> \ No newline at end of file diff --git a/classes/data/dataOrders.php b/classes/data/dataOrders.php new file mode 100644 index 0000000..2850a64 --- /dev/null +++ b/classes/data/dataOrders.php @@ -0,0 +1,714 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: dataOrders.php,v 1.0 2011/01/25 19:31:47 cscott Exp $ + * @link <> + */ + +require_once DATA_ABSTRACT; + +/** + * EventManagementDataTickets class + * + * PHP version 5 + * + * @category Data + * @package EventManagement + * @author Chuck Scott + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: dataOrders,v 1.0 2011/01/25 19:31:47 cscott Exp $ + * @link <> + */ +class EventManagementDataOrders extends DataAbstract +{ + /** + * Tables + * + * @var $ini + * @access public + */ + public $table = 'eventmgt.ticket_order'; + + /** + * Field definitions + * + * 'type' is type of field as defined by the application + * text Regular text field + * pointer Pointer to an entry in another table + * 'filters' is the filter name for a particular filter ID in PHP filter functions + * See PHP filter_id() + * + * 'use' is when to use the field + * l = List + * g = Get + * n = New + * i = Insert + * e = Edit + * u = Update + * d = Delete + * a = All + * + * @var $ini + * @access public + */ + public $fields = false; + + /** + * Constructor + * + * @param object $d database connection + * + * @return void + * @access public + */ + function __construct($dbh, $config) + { + + parent::__construct($dbh, $config); + + $this->fields = array( + + // Record ID + 'id' => array( + 'field' => 'id', + 'as' => false, + 'type' => 'integer', + 'required' => true, + 'unique' => true, + 'default' => false, + 'use' => 'lged' + ), + + // user_trace_info + 'user_trace_info' => array( + 'field' => 'user_trace_info', + 'as' => false, + 'type' => 'text', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // First Name + 'fname' => array( + 'field' => 'fname', + 'as' => false, + 'type' => 'text', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Last Name + 'lname' => array( + 'field' => 'lname', + 'as' => false, + 'type' => 'text', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Address Line 1 + 'addr1' => array( + 'field' => 'addr1', + 'as' => false, + 'type' => 'text', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Address Line 2 + 'addr2' => array( + 'field' => 'addr2', + 'as' => false, + 'type' => 'text', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // First Name + 'city' => array( + 'field' => 'city', + 'as' => false, + 'type' => 'text', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Contact State + 'state' => array( + 'field' => 'state', + 'as' => false, + 'type' => 'list', + 'list' => $this->config->states->toArray(), + 'required' => false, + 'unique' => false, + 'default' => 'MI', + 'use' => 'a' + ), + + // Contact Country + 'country' => array( + 'field' => 'country', + 'as' => false, + 'type' => 'list', + 'list' => $this->config->countries->toArray(), + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Contact ZIP + 'zip' => array( + 'field' => 'zip', + 'as' => false, + 'type' => 'text', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Phone + 'phone' => array( + 'field' => 'phone', + 'as' => false, + 'type' => 'text', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // E-Mail + 'email' => array( + 'field' => 'email', + 'as' => false, + 'type' => 'text', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // E-Mail OK + 'email_ok' => array( + 'field' => 'email_ok', + 'as' => false, + 'type' => 'checkbox', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Purchase Date + 'purchase_date' => array( + 'field' => 'purchase_date', + 'as' => false, + 'type' => 'date', + 'format' => 'm/d/Y', + 'required' => false, + 'unique' => false, + 'default' => time(), + 'use' => 'lged' + ), + + // Member ID + 'member' => array( + 'field' => 'member', + 'as' => false, + 'type' => 'integer', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'gle' + ), + + // Member Name display + 'member_view' => array( + 'field' => 'member', + 'as' => 'member_name', + 'type' => 'pointer', + 'p_table' => 'eventmgt.member', + 'p_field' => 'name', + 'p_id' => 'id', + 'p_static' => true, + 'required' => true, + 'unique' => false, + 'default' => false, + 'view_only' => true, + 'use' => 'gleu' + ), + + // CC Type + 'cctype' => array( + 'field' => 'cctype', + 'as' => false, + 'type' => 'text', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'lge' + ), + + // CC Number + 'ccnumber' => array( + 'field' => 'ccnumber', + 'as' => false, + 'type' => 'text', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'lge' + ), + + // CC Expiration$_SESSION[GLM_EVENT_SESSION]['Ticket'] + 'expire' => array( + 'field' => 'expire', + 'as' => false, + 'type' => 'text', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'lge' + ), + + // Name on Card + 'ccname' => array( + 'field' => 'ccname', + 'as' => false, + 'type' => 'text', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'lge' + ), + + // CC Confirmation # + 'ccconf' => array( + 'field' => 'ccconf', + 'as' => false, + 'type' => 'text', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'lge' + ), + + // Charge Number + 'charge_numb' => array( + 'field' => 'charge_total', + 'as' => 'charge_numb', + 'type' => 'float', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'gle' + ), + + // Charge Total Money + 'charge_total' => array( + 'field' => 'charge_total', + 'as' => false, + 'type' => 'money', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'lge' + ), + + // Special Needs + 'special_needs' => array( + 'field' => 'special_needs', + 'as' => false, + 'type' => 'text', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Optional Checkout Field Name #1 + 'opt_field_1_name' => array( + 'field' => 'opt_field_1_name', + 'as' => false, + 'type' => text, + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'gle' + ), + + // Optional Checkout Field #1 + 'opt_field_1' => array( + 'field' => 'opt_field_1', + 'as' => false, + 'type' => text, + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'gle' + ), + + // Optional Checkout Field Name #2 + 'opt_field_1_name' => array( + 'field' => 'opt_field_1_name', + 'as' => false, + 'type' => text, + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'gle' + ), + + // Optional Checkout Field #2 + 'opt_field_2' => array( + 'field' => 'opt_field_2', + 'as' => false, + 'type' => text, + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'gle' + ), + + // Optional Checkout Field Name #3 + 'opt_field_1_name' => array( + 'field' => 'opt_field_1_name', + 'as' => false, + 'type' => text, + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'gle' + ), + + // Optional Checkout Field #3 + 'opt_field_3' => array( + 'field' => 'opt_field_3', + 'as' => false, + 'type' => text, + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'gle' + ), + + // Notes + 'notes' => array( + 'field' => 'notes', + 'as' => false, + 'type' => 'text', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ) + + ); + } + + + /** + * Get Orders list + * + * @return object containing array as sub-objects + */ + function getOrdersList($memberID = false, $performanceID = false, $sectionID = false, $listType = false) + { + + // Get member ID + if ($memberID == false) { + $memberID = $_SESSION[GLM_EVENT_SESSION]['Member']; + } + + // Get performance ID + if ($performanceID == false) { + $performanceID = $_SESSION[GLM_EVENT_SESSION]['Performance']; + } + + // Get section ID + if ($sectionID == false) { + $sectionID = $_SESSION[GLM_EVENT_SESSION]['Section']; + } + + // Get URI search type + if (!$listType && isset($_REQUEST['listType'])) { + $listType = $_REQUEST['listType']; + } + + // Build query Where clause + $where = 'true'; + + switch ($listType) { + + case 'norm': + default: + if ($memberID) { + $where .= " AND T.member = $memberID"; + } + if ($performanceID) { + $where .= " AND T.performance = $performanceID"; + } + if ($sectionID) { + $where .= " AND T.section = $sectionID"; + } + break; + + case 'all': + break; + + } + + // Get list of Orders + $ordersList = $this->getList($where, 'purchase_date'); + + return $ordersList; + } + + /** + * Get Order Detail + * + * @return array + */ + function getOrderDetail($orderID = false, $memberID = false) + { + + // If a order has been specified + if ($orderID != false) { + + $_SESSION[GLM_EVENT_SESSION]['Order'] = $orderID; + + // Otherwise if there's a order ID in the request + } elseif (($orderID = filter_input(INPUT_GET, 'OrderID', FILTER_SANITIZE_NUMBER_INT))) { + + $_SESSION[GLM_EVENT_SESSION]['Order'] = $orderID; + + } elseif (isset($_SESSION[GLM_EVENT_SESSION]['Order'])) { + + $orderID = $_SESSION[GLM_EVENT_SESSION]['Order']; + + } else { + + // Otherwise, we don't have an order id + return false; + + } + + $where = ''; + if ($memberID) { + $where = "AND T.member = $memberID"; + } + + $orderDetail = $this->getEntry($orderID, 'id', $where); + + // If we have a member ID then make sure the sold ticket is for that member + if ($memberID && $orderDetail['member'] != $memberID) { + return false; + } + + return $orderDetail; + + } + + + /** + * Edit Order + * + * @return array + */ + function editOrder() + { + + if (($orderID = filter_input(INPUT_GET, 'OrderID', FILTER_SANITIZE_NUMBER_INT))) { + + // If so then add it to the session + $_SESSION[GLM_EVENT_SESSION]['Order'] = $orderID; + + } elseif (isset($_SESSION[GLM_EVENT_SESSION]['Order'])) { + + // Otherwise, get the order ID from the session + $orderID = $_SESSION[GLM_EVENT_SESSION]['Order']; + + } else { + + // Otherwise, we don't have an order id + return false; + + } + + $orderDetail = $this->editEntry($orderID); + + return $orderDetail; + + } + + /** + * Check for other field related issues + * + * This function must be here because it's called from a function + * in dataAbstract. Simply return $r if there's nothing to check. + * + * @return array + */ + function checkOther($r) + { + parent::checkOther($r); + return $r; + } + + /** + * Update Order + * + * @return array + */ + function updateOrder() + { + + if (($orderID = filter_input(INPUT_GET, 'OrderID', FILTER_SANITIZE_NUMBER_INT))) { + + // If so then add it to the session + $_SESSION[GLM_EVENT_SESSION]['Order'] = $orderID; + + } elseif (isset($_SESSION[GLM_EVENT_SESSION]['Order'])) { + + // Otherwise, get the order ID from the session + $orderID = $_SESSION[GLM_EVENT_SESSION]['Order']; + + } else { + + // Otherwise, we don't have an order id + return false; + + } + + // Try to update this data + $r = $this->updateEntry($orderID); + + return $r; + + } + + /** + * Delete Order + * + * @param $confirm bool False to ask if user wants to delete and true to actually delete + * @param $orderID int If supplied, use for order ID, otherwise check for orderID REQUEST param. + * + * @return int Deleted order ID or false if fail + */ + function orderDelete($confirm = false, $orderID = false) + { + + $orderID = $orderID - 0; + + // If an order wasn't supplied in the function call or it's not a positive integer + if ($orderID <= 0) { + + $orderID = filter_input(INPUT_GET, 'OrderID', FILTER_SANITIZE_NUMBER_INT); + $orderID = $orderID - 0; + + // Is there isn't a new order ID provided on the URL + if ($orderID <= 0) { + echo "

No valid order ID supplied.

"; + return false; + } + + } + + // Get order to validate order ID + $orderDetail = $this->getEntry($orderID); + if (!$orderDetail) { + echo "

Order ID $orderID not found.

"; + return false; + } + + $sql = "BEGIN;\n"; + + // Build query to delete add_on_sold data + $sql .= "DELETE FROM eventmgt.add_on_sold WHERE ticket_order = $orderID;\n"; + + // Build query to delete promo_sold data + $sql .= "DELETE FROM eventmgt.promo_sold WHERE ticket_order = $orderID;\n"; + + // Get list of tickets sold in this order + require_once EVENT_MANAGEMENT_APP_BASE.'classes/data/dataSold.php'; + $Sold = new EventManagementDataSold($this->dbh, $this->config); + $sold = $Sold->getSoldList($orderID); + if (!$sold) { + echo "

No tickets found for order ID $orderID.

"; + return false; + } + + // Build query to update inventory for each ticket sold and to delete the ticket sold + foreach ($sold as $s) { + + // If this is not a package sold item, adjust inventory - Only the tickets in a package get processed + if (!$s['ticket_package']) { + + // Note that we don't check to see if the ticket is marked as having unlimited quantity. If it's unlimited, decrementing the inventory has no effect. + + // If this is a date specific ticket, specify the inventory for that date + $dateWhere = ''; + if ($s['date_specific']['value']) { + $dateWhere = " AND ticket_date = '".$s['ticket_date']['date']."'"; + } + + // If this is a time specific ticket, specify the inventory for that time + $timeWhere = ''; + if ($s['time_specific']['value']) { + $timeWhere = " AND ticket_time = '".$s['ticket_time']['time']."'"; + } + + // Build the query for this ticket sold to adjust the inventory levels + $sql .= "UPDATE eventmgt.ticket_inventory SET available = available + 1, sold = sold - 1 WHERE ticket = ".$s['ticket']."$dateWhere$timeWhere;\n"; + + } + + } + + // Build the query to delete the ticket_sold records + $sql .= "DELETE FROM eventmgt.ticket_sold WHERE ticket_order = $orderID;\n"; + + // Build the query to delete the ticket_claim_tracking records + $sql .= "DELETE FROM eventmgt.ticket_claim_tracking WHERE ticket_order = $orderID;\n"; + + // Lastly, build the query to delete the ticket_order record + $sql .= "DELETE FROM eventmgt.ticket_order WHERE id = $orderID;\n"; + + $sql .= "COMMIT\n"; + +// echo "
$sql
"; + + $res = $this->dbh->exec($sql); + + return $res; + } + + +} + + + + +?> diff --git a/classes/data/dataPerformances.php b/classes/data/dataPerformances.php new file mode 100644 index 0000000..66989e0 --- /dev/null +++ b/classes/data/dataPerformances.php @@ -0,0 +1,956 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: dataPerformances.php,v 1.0 2011/01/25 19:31:47 cscott Exp $ + * @link http://www.gaslightmedia.com/ + */ + +require_once DATA_ABSTRACT; + +/** + * EventManagementDataPerformances class + * + * PHP version 5 + * + * @category Data + * @package EventManagement + * @author Chuck Scott + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: dataPerformances.php,v 1.0 2011/01/25 19:31:47 cscott Exp $ + * @link http://www.gaslightmedia.com + */ +class EventManagementDataPerformances extends DataAbstract +{ + /** + * Field definitions + * + * @var $ini + * @access public + */ + public $table = 'eventmgt.performance'; + + /** + * Field definitions + * + * 'type' is type of field as defined by the application + * text Regular text field + * pointer Pointer to an entry in another table + * 'filters' is the filter name for a particular filter ID in PHP filter functions + * See PHP filter_id() + * + * 'use' is when to use the field + * l = List + * g = Get + * n = New + * i = Insert + * e = Edit + * u = Update + * d = Delete + * a = All + * + * @var $ini + * @access public + */ + public $fields = false; + + /** + * Constructor + * + * @param object $d database connection + * + * @return void + * @access public + */ + function __construct($dbh, $config) + { + + parent::__construct($dbh, $config); + + $this->fields = array( + + // Record ID + 'id' => array( + 'field' => 'id', + 'as' => false, + 'type' => 'integer', + 'required' => true, + 'unique' => true, + 'default' => false, + 'use' => 'lg' + ), + + // Member ID for adding performances + 'member' => array( + 'field' => 'member', + 'as' => false, + 'type' => 'pointer', + 'p_table' => 'eventmgt.member', + 'p_field' => 'name', + 'p_id' => 'id', + 'p_static' => true, + 'required' => true, + 'unique' => false, + 'default' => $_SESSION[GLM_EVENT_SESSION]['Member'], + 'use' => 'nid' + ), + + // Member ID for adding performances + 'member_id' => array( + 'field' => 'member', + 'as' => member_id, + 'type' => 'integer', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'gle' + ), + + // Performance Name + 'name' => array( + 'field' => 'name', + 'as' => false, + 'type' => 'text', + 'required' => true, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Active + 'active' => array( + 'field' => 'active', + 'as' => false, + 'type' => 'checkbox', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Admin Only Flag + 'admin_only' => array( + 'field' => 'admin_only', + 'as' => false, + 'type' => 'checkbox', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Description + 'descr' => array( + 'field' => 'descr', + 'as' => false, + 'type' => 'text', + 'filter' => FILTER_SANITIZE_MAGIC_QUOTES, + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Short Description + 'short_descr' => array( + 'field' => 'short_descr', + 'as' => false, + 'type' => 'text', + 'filter' => FILTER_SANITIZE_MAGIC_QUOTES, + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Start Date + 'start_date' => array( + 'field' => 'start_date', + 'as' => false, + 'type' => 'date', + 'format' => 'm/d/Y', + 'minValue' => strtotime('1/1/'.date('Y')), // Earliest is now + 'maxValue' => strtotime('12/31/'.date('Y').' +3 years'), // This year plus 3 + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // End Date + 'end_date' => array( + 'field' => 'end_date', + 'as' => false, + 'type' => 'date', + 'format' => 'm/d/Y', + 'minValue' => strtotime('1/1/'.date('Y')), // Earliest is now + 'maxValue' => strtotime('12/31/'.date('Y').' +3 years'), // This year plus 3 + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Purchase lead-time in hours + 'purch_leadtime' => array( + 'field' => 'purch_leadtime', + 'as' => false, + 'type' => 'integer', + 'required' => false, + 'unique' => false, + 'default' => 24, + 'use' => 'a' + ), + + // Image + 'image' => array( + 'field' => 'image', + 'as' => false, + 'type' => 'image', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Policy + 'policy' => array( + 'field' => 'policy', + 'as' => false, + 'type' => 'text', + 'filter' => FILTER_SANITIZE_MAGIC_QUOTES, + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Voucher Text + 'voucher_text' => array( + 'field' => 'voucher_text', + 'as' => false, + 'type' => 'text', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Confirmation E-Mail Text + 'conf_text' => array( + 'field' => 'conf_text', + 'as' => false, + 'type' => 'text', + 'filter' => FILTER_SANITIZE_MAGIC_QUOTES, + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Promote in Cart + 'promote_in_cart' => array( + 'field' => 'promote_in_cart', + 'as' => false, + 'type' => 'checkbox', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Sort order + 'sort' => array( + 'field' => 'sort', + 'as' => false, + 'type' => 'integer', + 'required' => true, + 'unique' => false, + 'default' => 999, + 'use' => 'a' + ), + + // Notes + 'notes' => array( + 'field' => 'notes', + 'as' => false, + 'type' => 'text', + 'filter' => FILTER_SANITIZE_MAGIC_QUOTES, + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + /* Also get some member information in case we need it */ + + + // Member Name display + 'member_view' => array( + 'field' => 'member', + 'as' => 'member_name', + 'type' => 'pointer', + 'p_table' => 'eventmgt.member', + 'p_field' => 'name', + 'p_id' => 'id', + 'p_static' => true, + 'required' => true, + 'unique' => false, + 'default' => false, + 'view_only' => true, + 'use' => 'gleu' + ), + + // Member Address line 1 + 'member_addr1' => array( + 'field' => 'member', + 'as' => 'member_addr1', + 'type' => 'pointer', + 'p_table' => 'eventmgt.member', + 'p_field' => 'addr1', + 'p_id' => 'id', + 'p_static' => true, + 'required' => true, + 'unique' => false, + 'default' => false, + 'view_only' => true, + 'use' => 'gleu' + ), + + // Member Address line 2 + 'member_addr2' => array( + 'field' => 'member', + 'as' => 'member_addr2', + 'type' => 'pointer', + 'p_table' => 'eventmgt.member', + 'p_field' => 'addr2', + 'p_id' => 'id', + 'p_static' => true, + 'required' => true, + 'unique' => false, + 'default' => false, + 'view_only' => true, + 'use' => 'gleu' + ), + + // Member City + 'member_city' => array( + 'field' => 'member', + 'as' => 'member_city', + 'type' => 'pointer', + 'p_table' => 'eventmgt.member', + 'p_field' => 'city', + 'p_id' => 'id', + 'p_static' => true, + 'required' => true, + 'unique' => false, + 'default' => false, + 'view_only' => true, + 'use' => 'gleu' + ), + + // Member State + 'member_state' => array( + 'field' => 'member', + 'as' => 'member_state', + 'type' => 'pointer', + 'p_table' => 'eventmgt.member', + 'p_field' => 'state', + 'p_id' => 'id', + 'p_static' => true, + 'required' => true, + 'unique' => false, + 'default' => false, + 'view_only' => true, + 'use' => 'gleu' + ), + + // Member ZIP + 'member_zip' => array( + 'field' => 'member', + 'as' => 'member_zip', + 'type' => 'pointer', + 'p_table' => 'eventmgt.member', + 'p_field' => 'zip', + 'p_id' => 'id', + 'p_static' => true, + 'required' => true, + 'unique' => false, + 'default' => false, + 'view_only' => true, + 'use' => 'gleu' + ), + + // Member Country + 'member_country' => array( + 'field' => 'member', + 'as' => 'member_country', + 'type' => 'pointer', + 'p_table' => 'eventmgt.member', + 'p_field' => 'country', + 'p_id' => 'id', + 'p_static' => true, + 'required' => true, + 'unique' => false, + 'default' => false, + 'view_only' => true, + 'use' => 'gleu' + ), + + // Member LAT + 'member_lat' => array( + 'field' => 'member', + 'as' => 'member_lat', + 'type' => 'pointer', + 'p_table' => 'eventmgt.member', + 'p_field' => 'lat', + 'p_id' => 'id', + 'p_static' => true, + 'required' => true, + 'unique' => false, + 'default' => false, + 'view_only' => true, + 'use' => 'gleu' + ), + + // Member LON + 'member_lon' => array( + 'field' => 'member', + 'as' => 'member_lon', + 'type' => 'pointer', + 'p_table' => 'eventmgt.member', + 'p_field' => 'lon', + 'p_id' => 'id', + 'p_static' => true, + 'required' => true, + 'unique' => false, + 'default' => false, + 'view_only' => true, + 'use' => 'gleu' + ), + + // Member phone + 'member_phone' => array( + 'field' => 'member', + 'as' => 'member_phone', + 'type' => 'pointer', + 'p_table' => 'eventmgt.member', + 'p_field' => 'phone', + 'p_id' => 'id', + 'p_static' => true, + 'required' => true, + 'unique' => false, + 'default' => false, + 'view_only' => true, + 'use' => 'gleu' + ), + + // Member payment gateways + 'member_payment_gateway' => array( + 'field' => 'member', + 'as' => 'member_payment_gateway', + 'type' => 'pointer', + 'p_table' => 'eventmgt.member', + 'p_field' => 'payment_gateway', + 'p_id' => 'id', + 'p_static' => true, + 'required' => true, + 'unique' => false, + 'default' => false, + 'view_only' => true, + 'use' => 'gleu' + ), + + // Member credit cards accepted + 'member_cards_accepted' => array( + 'field' => 'member', + 'as' => 'member_cards_accepted', + 'type' => 'pointer', + 'p_table' => 'eventmgt.member', + 'p_field' => 'cards_accepted', + 'p_id' => 'id', + 'p_static' => true, + 'required' => true, + 'unique' => false, + 'default' => false, + 'view_only' => true, + 'use' => 'gleu' + ), + + // Member credit cards accepted + 'member_cards_accepted' => array( + 'field' => 'member', + 'as' => 'member_cards_accepted', + 'type' => 'pointer', + 'p_table' => 'eventmgt.member', + 'p_field' => 'cards_accepted', + 'p_id' => 'id', + 'p_static' => true, + 'required' => true, + 'unique' => false, + 'default' => false, + 'view_only' => true, + 'use' => 'gleu' + ), + + // Member payment gateway parameter 1 + 'member_gateway_par1' => array( + 'field' => 'member', + 'as' => 'member_gateway_par1', + 'type' => 'pointer', + 'p_table' => 'eventmgt.member', + 'p_field' => 'gateway_par1', + 'p_id' => 'id', + 'p_static' => true, + 'required' => true, + 'unique' => false, + 'default' => false, + 'view_only' => true, + 'use' => 'gleu' + ), + + // Member payment gateway parameter 2 + 'member_gateway_par2' => array( + 'field' => 'member', + 'as' => 'member_gateway_par2', + 'type' => 'pointer', + 'p_table' => 'eventmgt.member', + 'p_field' => 'gateway_par2', + 'p_id' => 'id', + 'p_static' => true, + 'required' => true, + 'unique' => false, + 'default' => false, + 'view_only' => true, + 'use' => 'gleu' + ), + + + + ); + } + + /** + * Get Performances list + * + * @param $listType String A particular list type ('all', 'member', 'cart_promotions', ...) + * @return object containing array as sub-objects + */ + function getPerformancesList($listType = false, $memberID = false, $includeAdminOnly = false) + { + + $where = ''; + $and = ''; + + // Determine if there's a list type request (otherwise default to call parameter $listType) + if (!$listType && isset($_REQUEST['listType'])) { + $listType = $_REQUEST['listType']; + $and = ' AND '; + } + + // Check if adminUser + if (!$includeAdminOnly) { + $where .= $and.' NOT T.admin_only'; + $and = ' AND '; + } + + switch ($listType) { + + case 'member': + if ($memberID == false) { + $memberID = $_SESSION[GLM_EVENT_SESSION]['Member']; + } + $where .= $and."member = $memberID"; + break; + + case 'member_and_active': + if ($memberID == false) { + $memberID = $_SESSION[GLM_EVENT_SESSION]['Member']; + } + $where .= $and."member = $memberID AND T.active"; + break; + + case 'cart_promotions': + $where .= $and."T.promote_in_cart AND T.active AND (SELECT active FROM eventmgt.member WHERE active = true AND member.id = T.member)"; + break; + + case 'all': + default: + break; + + } + + $performancesList = $this->getList($where, 'sort, name'); + + return $performancesList; + } + + /** + * Get Performance Detail + * + * @return array + */ + function getPerformanceDetail($performanceID = false) + { + + $where = ''; + + // If a performance has been specified + if ($performanceID != false) { + + // Don't do anything here + + // Is there a new Performance code selected? + } elseif (($performanceID = filter_input(INPUT_GET, 'PerformanceID', FILTER_SANITIZE_NUMBER_INT))) { + + // If so then add it to the session + $_SESSION[GLM_EVENT_SESSION]['Performance'] = $performanceID; + + } elseif (isset($_SESSION[GLM_EVENT_SESSION]['Performance'])) { + + // Otherwise, get the performance ID from the session + $performanceID = $_SESSION[GLM_EVENT_SESSION]['Performance']; + + } else { + + // Otherwise, we don't have a performance specified + return false; + + } + + + $performanceDetail = $this->getEntry($performanceID, 'id', $where); + + return $performanceDetail; + + } + + + /** + * Edit Performance + * + * @return array + */ + function editPerformance() + { + + if (($performanceID = filter_input(INPUT_GET, 'PerformanceID', FILTER_SANITIZE_NUMBER_INT))) { + + // If so then add it to the session + $_SESSION[GLM_EVENT_SESSION]['Performance'] = $performanceID; + + } elseif (isset($_SESSION[GLM_EVENT_SESSION]['Performance'])) { + + // Otherwise, get the state rep ID from the session + $performanceID = $_SESSION[GLM_EVENT_SESSION]['Performance']; + + } else { + + // Otherwise, we don't have a state rep id + return false; + + } + + $performanceDetail = $this->editEntry($performanceID); + + return $performanceDetail; + + } + + /** + * Check for other field related issues + * + * This function must be here because it's called from a function + * in dataAbstract. Simply return $r if there's nothing to check. + * + * @return array + */ + function checkOther($r) + { + parent::checkOther($r); + return $r; + } + + /** + * Update Performance + * + * @return array + */ + function updatePerformance() + { + + if (($performanceID = filter_input(INPUT_GET, 'PerformanceID', FILTER_SANITIZE_NUMBER_INT))) { + + // If so then add it to the session + $_SESSION[GLM_EVENT_SESSION]['Performance'] = $performanceID; + + } elseif (isset($_SESSION[GLM_EVENT_SESSION]['Performance'])) { + + // Otherwise, get the state rep ID from the session + $performanceID = $_SESSION[GLM_EVENT_SESSION]['Performance']; + + } else { + + // Otherwise, we don't have a state rep id + return false; + + } + + // Try to update this data + $r = $this->updateEntry($performanceID); + + // If the update was successful and we ahve start and end dates, Set inventory outside of the dates set for this performance to inactive + $start = $r['fieldData']['start_date']['date']; + $end = $r['fieldData']['end_date']['date']; + if ($r['status'] && $r['fieldData']['start_date']['date'] != '' && $r['fieldData']['end_date']['date'] != '') { + $sql = " + UPDATE eventmgt.ticket_inventory + SET active = false + WHERE id in ( + SELECT I.id + FROM eventmgt.ticket T, eventmgt.ticket_inventory I + WHERE T.performance = $performanceID + AND T.id = I.ticket + AND ( I.ticket_date < '$start' OR I.ticket_date > '$end') + ) + ;"; + $this->dbh->exec($sql); + + } + + return $r; + + } + + + /** + * Add New Performance + * + * @return array + */ + function newPerformance() + { + + $r = $this->newEntry(); + + return $r; + + } + + /** + * Insert Performance + * + * @return array + */ + function insertPerformance() + { + + $r = $this->insertEntry(); + + // If succesful then set current performance to the one just inserted. + if ($r['status']) { + $_SESSION[GLM_EVENT_SESSION]['Performance'] = $r['insertedID']; + } + + return $r; + + } + + + /** + * Delete Performance + * + * @param $confirm bool False to ask if user wants to delete and true to actually delete + * + * @return array + */ + function performanceDelete($confirm = false) + { + + // Is there a new performance code selected? + if (($performanceID = filter_input(INPUT_GET, 'PerformanceID', FILTER_SANITIZE_NUMBER_INT))) { + + // If so then add it to the session + $_SESSION[GLM_EVENT_SESSION]['Performance'] = $performanceID; + + } elseif (isset($_SESSION[GLM_EVENT_SESSION]['Performance'])) { + + // Otherwise, get the performance ID from the session + $performanceID = $_SESSION[GLM_EVENT_SESSION]['Performance']; + + } else { + + // Otherwise, we don't have an performance id + return false; + + } + + $performanceDetail = $this->deleteEntry($performanceID, $confirm); + + return $performanceDetail; + + } + + /** + * Get Performance Inventory Summary + * + * @return array + */ + function getPerformanceInventorySummary($performanceID = false, $year = false) + { + + // If a performance has been specified + if ($performanceID != false) { + + // Don't do anything here + + // Is there a new Performance code selected? + } elseif (($performanceID = filter_input(INPUT_GET, 'PerformanceID', FILTER_SANITIZE_NUMBER_INT))) { + + // Don't do anything here + + } elseif (isset($_SESSION[GLM_EVENT_SESSION]['Performance'])) { + + // Otherwise, get the performance ID from the session + $performanceID = $_SESSION[GLM_EVENT_SESSION]['Performance']; + + } else { + + // Otherwise, we don't have a state rep id + return false; + + } + + $yearWhere = ''; + if ($year) { + $yearWhere = "AND I.ticket_date BETWEEN '01/01/$year' AND '12/31/$year'"; + } + // Get detail on the performance + $performanceDetail = $this->getPerformanceDetail($performanceID); + + // Get inventory summary data for the performance + $sql = " + SELECT I.active, I.ticket_date AS date, I.ticket_time AS time, I.id AS invenID, I.quant, I.available, I.sold, + S.id AS sectionID, S.name AS sectionName, COALESCE(sum(H.quant),0) AS quantHeld, + T.name AS ticketname, T.price, t.unlimited_quant + FROM eventmgt.ticket T, eventmgt.ticket_inventory I LEFT OUTER JOIN eventmgt.inven_hold H ON (H.inventory = I.id), + eventmgt.section S + WHERE T.performance = $performanceID + AND I.ticket = T.id + AND S.id = T.section + $yearWhere + GROUP BY I.active, I.ticket_date, I.ticket_time, I.id, I.quant, I.available, I.sold, S.id, S.name, T.name, T.price, T.unlimited_quant + ORDER BY date, time, sectionID, ticketname + ;"; + $stmt = $this->dbh->prepare($sql); + $stmt->execute(); + $invData = $stmt->fetchAll(PDO::FETCH_ASSOC); + + // Build inventory summary array organized by date, time, section, ticket + $sum = array(); + $date = false; + $time = false; + $section = false; + foreach ($invData as $i) { + + $dow = date('D', strtotime($i['date'])); + + $t = explode(':', $i['time']); + $ampm = 'AM'; + $hour = ($t[0] - 0); + if ($hour > 11) { + $ampm = 'PM'; + } else { + } + if ($hour > 12) { + $hour -= 12; + } + $timeString = sprintf('%2d:%02d %s', $hour, $min, $ampm); + + // Insert ticket with inventory + $s = array( + 'id' => $i['invenid'], + 'active' => $i['active'], + 'date' => $dow." ".$i['date'], + 'time' => $timeString, + 'section' => $i['sectionname'], + 'name' => $i['ticketname'], + 'unlimited_quant' => $i['unlimited_quant'], + 'quant' => $i['quant'], + 'avail' => $i['available'], + 'sold' => $i['sold'], + 'held' => $i['quantheld'], + 'netAvail' => $i['available'] - $i['held'], + 'price' => $this->money($i['price']) + ); + + // Clear redundant values + if ($i['date'] == $date) { + $s['date'] = ''; + } else { + $date = $i['date']; + $time = false; + $section = false; + } + + if ($i['time'] == $time) { + $s['time'] = ''; + } else { + $time = $i['time']; + $section = false; + } + + if ($i['sectionname'] == $section) { + $s['section'] = ''; + } else { + $section = $i['sectionname']; + } + + + $sum[] = $s; + } + + return $sum; + + } + + /** + * Format a number as money + * + * @param $value Value to format + * @param $option Options that control output + * NOPREFIX stops the "$" prefix + * + * @return none + * @access public + */ + private function money($value, $option = "") + { + + if ($option == "NOPREFIX") + $prefix = ""; + else + $prefix = "$"; + + // Do value sanity check + + if (!is_numeric($value)) + return ($prefix."0.00"); + + return ($prefix.number_format($value, 2, ".", ",")); + } + + +} + + + + +?> diff --git a/classes/data/dataPromoSold.php b/classes/data/dataPromoSold.php new file mode 100644 index 0000000..9ad7ab4 --- /dev/null +++ b/classes/data/dataPromoSold.php @@ -0,0 +1,268 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: dataPromoSold.php,v 1.0 2011/01/25 19:31:47 cscott Exp $ + * @link + */ + +require_once DATA_ABSTRACT; + +/** + * EventManagementDataPromoSold class + * + * PHP version 5 + * + * @category Data + * @package EventManagement + * @author Chuck Scott + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: dataPromoSold.php,v 1.0 2011/01/25 19:31:47 cscott Exp $ + * @link + */ +class EventManagementDataPromoSold extends DataAbstract +{ + /** + * Field definitions + * + * @var $ini + * @access public + */ + public $table = 'eventmgt.promo_sold'; + + /** + * Field definitions + * + * 'type' is type of field as defined by the application + * text Regular text field + * pointer Pointer to an entry in another table + * 'filters' is the filter name for a particular filter ID in PHP filter functions + * See PHP filter_id() + * + * 'use' is when to use the field + * l = List + * g = Get + * n = New + * i = Insert + * e = Edit + * u = Update + * d = Delete + * a = All + * + * @var $ini + * @access public + */ + public $fields = false; + + /** + * Constructor + * + * @param object $d database connection + * + * @return void + * @access public + */ + function __construct($dbh, $config) + { + + parent::__construct($dbh, $config); + + $this->fields = array( + + // Record ID + 'id' => array( + 'field' => 'id', + 'as' => false, + 'type' => 'integer', + 'required' => true, + 'unique' => true, + 'default' => false, + 'use' => 'lg' + ), + + // Ticket Order + 'ticket_order' => array( + 'field' => 'ticket_order', + 'as' => false, + 'type' => 'integer', + 'required' => true, + 'unique' => false, + 'default' => false, + 'use' => 'niegdl' + ), + + // Ticket Sold + 'ticket_sold' => array( + 'field' => 'ticket_sold', + 'as' => false, + 'type' => 'integer', + 'required' => true, + 'unique' => false, + 'default' => false, + 'use' => 'niegdl' + ), + + // Promo + 'promo' => array( + 'field' => 'promo', + 'as' => false, + 'type' => 'integer', + 'required' => true, + 'unique' => false, + 'default' => false, + 'use' => 'niegdl' + ), + + // Promo Name + 'promo_name' => array( + 'field' => 'promo_name', + 'as' => false, + 'type' => 'text', + 'required' => true, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Promo type + 'promo_type' => array( + 'field' => 'promo_type', + 'as' => false, + 'type' => 'list', + 'list' => $this->config->promo_ticket_type->toArray(), + 'required' => true, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Promo type name + 'promo_type_name' => array( + 'field' => 'promo_type_name', + 'as' => false, + 'type' => 'text', + 'required' => true, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Amount + 'amount' => array( + 'field' => 'amount', + 'as' => false, + 'type' => 'float', + 'required' => false, + 'unique' => false, + 'default' => 0.00, + 'use' => 'a' + ), + + // Amount (money) + 'amount_money' => array( + 'field' => 'amount', + 'as' => 'amount_money', + 'type' => 'money', + 'required' => false, + 'unique' => false, + 'default' => 0.00, + 'use' => 'lgd' + ), + + // Session ID + 'session_id' => array( + 'field' => 'session_id', + 'as' => false, + 'type' => 'text', + 'required' => true, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ) + + ); + + } + + /** + * Get Ticket Sold promos list + * + * @return object containing array as sub-objects + */ + function getPromosSoldList($ticketSoldID = false, $where = false) + { + + // If a where clause has not been supplied, use the $TicketSoldID - Otherwise $where + if (!$where) { + + $where = 'true'; + + // Check if there's a ticket sold ID, then filter by that + $ticketSoldID = ($ticketSoldID - 0); // Make sure it's number + if ($ticketSoldID > 0) { + $where .= " AND T.ticket_sold = $ticketSoldID"; + } + + } + + $promosSoldList = $this->getList($where, 'id'); + + return $promosSoldList; + } + + /** + * Get Promo Sold Detail + * + * @return array + */ + function getPromoSoldDetail($promoSoldID = false) + { + + if ($promoSoldID == false) { + + // Otherwise, we don't have an promo sold id + return false; + + } + + // If the promo sold ID is valid, get the detail + $promoSoldID = filter_input(INPUT_GET, 'PromoSoldID', FILTER_SANITIZE_NUMBER_INT); + if ($promoSoldID) { + $promoSoldDetail = $this->getEntry($promoSoldID); + + // Otherwise fail + } else { + return false; + } + + return $promoSoldDetail; + + } + + /** + * Check for other field related issues + * + * This function must be here because it's called from a function + * in dataAbstract. Simply return $r if there's nothing to check. + * + * @return array + */ + function checkOther($r) + { + parent::checkOther($r); + return $r; + } + +} + + + + +?> \ No newline at end of file diff --git a/classes/data/dataPromoTickets.php b/classes/data/dataPromoTickets.php new file mode 100644 index 0000000..183b38d --- /dev/null +++ b/classes/data/dataPromoTickets.php @@ -0,0 +1,505 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: dataPromoTickets.php,v 1.0 2011/01/25 19:31:47 cscott Exp $ + * @link + */ + +require_once DATA_ABSTRACT; + +/** + * EventManagementDataPromoTickets class + * + * PHP version 5 + * + * @category Data + * @package EventManagement + * @author Chuck Scott + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: dataPromoTickets,v 1.0 2011/01/25 19:31:47 cscott Exp $ + * @link <> + */ +class EventManagementDataPromoTickets extends DataAbstract +{ + /** + * Tables + * + * @var $ini + * @access public + */ + public $table = 'eventmgt.promo_ticket'; + + /** + * Field definitions + * + * 'type' is type of field as defined by the application + * text Regular text field + * pointer Pointer to an entry in another table + * 'filters' is the filter name for a particular filter ID in PHP filter functions + * See PHP filter_id() + * + * 'use' is when to use the field + * l = List + * g = Get + * n = New + * i = Insert + * e = Edit + * u = Update + * d = Delete + * a = All + * + * @var $ini + * @access public + */ + public $fields = false; + + /** + * Constructor + * + * @param object $d database connection + * + * @return void + * @access public + */ + function __construct($dbh, $config) + { + + parent::__construct($dbh, $config); + + $this->fields = array( + + // Record ID + 'id' => array( + 'field' => 'id', + 'as' => false, + 'type' => 'integer', + 'required' => true, + 'unique' => true, + 'default' => false, + 'use' => 'lged' + ), + + // Promo Code + 'promo' => array( + 'field' => 'promo', + 'as' => false, + 'type' => 'integer', + 'required' => true, + 'unique' => false, + 'default' => false, + 'view_only' => true, + 'use' => 'gleu' + ), + + // Promomotion Name + 'promo_name' => array( + 'field' => 'promo', + 'as' => 'promo_name', + 'type' => 'pointer', + 'p_table' => 'eventmgt.promo_code', + 'p_field' => 'name', + 'p_id' => 'id', + 'p_static' => true, + 'required' => false, + 'unique' => false, + 'default' => false, + 'view_only' => true, + 'use' => 'gleu' + ), + + // Promomotion Description + 'promo_descr' => array( + 'field' => 'promo', + 'as' => 'promo_descr', + 'type' => 'pointer', + 'p_table' => 'eventmgt.promo_code', + 'p_field' => 'descr', + 'p_id' => 'id', + 'p_static' => true, + 'required' => false, + 'unique' => false, + 'default' => false, + 'view_only' => true, + 'use' => 'gleu' + ), + + // Promomotion Start Date + 'promo_start_date' => array( + 'field' => 'promo', + 'as' => 'promo_start_date', + 'type' => 'pointer', + 'p_table' => 'eventmgt.promo_code', + 'p_field' => 'start_date', + 'p_id' => 'id', + 'p_static' => true, + 'required' => false, + 'unique' => false, + 'default' => false, + 'view_only' => true, + 'use' => 'gleu' + ), + + // Promomotion end Date + 'promo_end_date' => array( + 'field' => 'promo', + 'as' => 'promo_end_date', + 'type' => 'pointer', + 'p_table' => 'eventmgt.promo_code', + 'p_field' => 'end_date', + 'p_id' => 'id', + 'p_static' => true, + 'required' => false, + 'unique' => false, + 'default' => false, + 'view_only' => true, + 'use' => 'gleu' + ), + + // Ticket ID + 'ticket' => array( + 'field' => 'ticket', + 'as' => false, + 'type' => 'integer', + 'required' => true, + 'unique' => false, + 'default' => false, + 'view_only' => true, + 'use' => 'gleu' + ), + + // Ticket Name + 'ticket_name' => array( + 'field' => 'ticket', + 'as' => 'ticket_name', + 'type' => 'pointer', + 'p_table' => 'eventmgt.ticket', + 'p_field' => 'title', + 'p_id' => 'id', + 'p_static' => true, + 'required' => true, + 'unique' => false, + 'default' => false, + 'view_only' => true, + 'use' => 'gleu' + ), + + // Promo type + 'promo_type' => array( + 'field' => 'promo_type', + 'as' => false, + 'type' => 'list', + 'list' => $this->config->promo_ticket_type->toArray(), + 'required' => true, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Amount + 'amount' => array( + 'field' => 'amount', + 'as' => false, + 'type' => 'float', + 'required' => true, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Notes + 'notes' => array( + 'field' => 'notes', + 'as' => false, + 'type' => 'text', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ) + + ); + } + + /** + * Check for other field related issues + * + * Simply return $r if there's nothing to check. + * + * @return array + */ + function checkOther($r) + { + parent::checkOther($r); + + return $r; + } + + /** + * Get Promo Ticket list + * + * If $promoID is supplied also returns sales counts for this promo for each ticket. + * Front-end shop selection of + * + * @return object containing array as sub-objects + */ + function getPromoTicketsList($promoID = false, $promoCode = false, $where = 'true') + { + + // If promoID is supplied, get only tickets listed for that promo + if ($promoID) { + $where .= " AND T.promo = $promoID"; + } + + // If promoCode is supplied, get only tickets listed for that promo + if ($promoCode) { + $where .= " AND T.promo = (SELECT id FROM eventmgt.promo_code WHERE name = '$promoCode')"; + } + + // Get list of Promo Tickets + $promoTicketsList = $this->getList($where); + + // If a Promo ID was supplied, also get the promo code use counts per ticket + If ($promoID && is_array($promoTicketsList)) { + + // If promoID is supplied, get only tickets listed for that promo + if ($promoID) { + $where = " AND P.promo = $promoID"; + } + + // Also get total Promo counts for each ticket + reset($promoTicketsList); + while (list($key, $val) = each($promoTicketsList)) { + + // Get number sold and value sold for this ticket type and promo code + $sql = " + SELECT count(P.id) as numb_sold, sum(P.amount) as value_sold + FROM eventmgt.promo_sold P, eventmgt.ticket_sold T + WHERE T.id = P.ticket_sold + AND T.ticket = ".$val['ticket']." + $where; + "; + + $stmt = $this->dbh->prepare($sql); + $stmt->execute(); + $sales = $stmt->fetch(PDO::FETCH_ASSOC); + + // Add it to the results + $promoTicketsList[$key]['numberSold'] = $sales['numb_sold']; + $promoTicketsList[$key]['valueSold'] = $sales['value_sold']; + $promoTicketsList[$key]['dollarsSold'] = $this->money($sales['value_sold']); + + } + + } + + return $promoTicketsList; + } + + /** + * Get Promo Ticket Detail + * + * @return array + */ + function getPromoTicketDetail($promoTicketID = false) + { + + // If a promo ticket has been specified + if ($promoTicketID != false) { + + $_SESSION[GLM_EVENT_SESSION]['PromoTicket'] = $promoTicketID; + + // Otherwise if there's a promo ticket ID in the request + } elseif (($promoTicketID = filter_input(INPUT_GET, 'PromoTicketID', FILTER_SANITIZE_NUMBER_INT))) { + + // There's a Promo Ticket submitted, so save that + $_SESSION[GLM_EVENT_SESSION]['PromoTicket'] = $promoTicketID; + + } elseif (isset($_SESSION[GLM_EVENT_SESSION]['PromoTicket'])) { + + // Otherwise, get the promo code ID from the session + $promoTicketID = $_SESSION[GLM_EVENT_SESSION]['PromoTicket']; + + } else { + + // Otherwise, we don't have a promo ticket id + return false; + + } + + $promoTicketDetail = $this->getEntry($promoTicketID); + + return $promoTicketDetail; + + } + + /** + * Edit Promo Ticket + * + * @return array + */ + function editPromoTicket() + { + + if (($promoTicketID = filter_input(INPUT_GET, 'PromoTicketID', FILTER_SANITIZE_NUMBER_INT))) { + + // If so then add it to the session + $_SESSION[GLM_EVENT_SESSION]['PromoTicket'] = $promoTicketID; + + } elseif (isset($_SESSION[GLM_EVENT_SESSION]['PromoTicket'])) { + + // Otherwise, get the promo ticket ID from the session + $promoTicketID = $_SESSION[GLM_EVENT_SESSION]['PromoTicket']; + + } else { + + // Otherwise, we don't have a promo ticket id + return false; + + } + + $promoTicketDetail = $this->editEntry($promoTicketID); + + return $promoTicketDetail; + + } + + /** + * Update Promo Ticket + * + * @return array + */ + function updatePromoTicket() + { + + if (($promoTicketID = filter_input(INPUT_GET, 'PromoTicketID', FILTER_SANITIZE_NUMBER_INT))) { + + // If so then add it to the session + $_SESSION[GLM_EVENT_SESSION]['PromoTicket'] = $promoTicketID; + + } elseif (isset($_SESSION[GLM_EVENT_SESSION]['PromoTicket'])) { + + // Otherwise, get the promo ticket ID from the session + $promoID = $_SESSION[GLM_EVENT_SESSION]['PromoTicket']; + + } else { + + // Otherwise, we don't have a promo ticket id + return false; + + } + + // Try to update this data + $r = $this->updateEntry($promoTicketID); + + return $r; + + } + + /** + * Add New Promo Ticket + * + * @return array + */ + function newPromoTicket() + { + + $r = $this->newEntry(); + + return $r; + + } + + /** + * Insert Promo Ticket + * + * @return array + */ + function insertPromoTicket() + { + + $r = $this->insertEntry(); + + // If succesful then set current promo ticket to the one just inserted. + if ($r['status']) { + $_SESSION[GLM_EVENT_SESSION]['PromoTicket'] = $r['insertedID']; + } + + return $r; + + } + + /** + * Delete Promo Ticket + * + * @param $confirm bool False to ask if user wants to delete and true to actually delete + * + * @return array + */ + function promoTicketDelete($confirm = false) + { + + // Is there a new promo ticket code selected? + if (($promoTicketID = filter_input(INPUT_GET, 'PromoTicketID', FILTER_SANITIZE_NUMBER_INT))) { + + // If so then add it to the session + $_SESSION[GLM_EVENT_SESSION]['PromoTicket'] = $promoTicketID; + + } elseif (isset($_SESSION[GLM_EVENT_SESSION]['PromoTicket'])) { + + // Otherwise, get the promo code ID from the session + $promoTicketID = $_SESSION[GLM_EVENT_SESSION]['PromoTicket']; + + } else { + + // Otherwise, we don't have an promo ticket id + return false; + + } + + $promoTicketDetail = $this->deleteEntry($promoTicketID, $confirm); + + return $promoTicketDetail; + + } + + + /** + * Format a number as money + * + * @param $value Value to format + * @param $option Options that control output + * NOPREFIX stops the "$" prefix + * + * @return none + * @access public + */ + private function money($value, $option = "") + { + + if ($option == "NOPREFIX") + $prefix = ""; + else + $prefix = "$"; + + // Do value sanity check + + if (!is_numeric($value)) + return ($prefix."0.00"); + + return ($prefix.number_format($value, 2, ".", ",")); + } + + + + +} + +?> \ No newline at end of file diff --git a/classes/data/dataPromos.php b/classes/data/dataPromos.php new file mode 100644 index 0000000..6773d78 --- /dev/null +++ b/classes/data/dataPromos.php @@ -0,0 +1,376 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: dataPromos.php,v 1.0 2011/01/25 19:31:47 cscott Exp $ + * @link + */ + +require_once DATA_ABSTRACT; + +/** + * EventManagementDataPromos class + * + * PHP version 5 + * + * @category Data + * @package EventManagement + * @author Chuck Scott + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: dataPromos,v 1.0 2011/01/25 19:31:47 cscott Exp $ + * @link <> + */ +class EventManagementDataPromos extends DataAbstract +{ + /** + * Tables + * + * @var $ini + * @access public + */ + public $table = 'eventmgt.promo_code'; + + /** + * Field definitions + * + * 'type' is type of field as defined by the application + * text Regular text field + * pointer Pointer to an entry in another table + * 'filters' is the filter name for a particular filter ID in PHP filter functions + * See PHP filter_id() + * + * 'use' is when to use the field + * l = List + * g = Get + * n = New + * i = Insert + * e = Edit + * u = Update + * d = Delete + * a = All + * + * @var $ini + * @access public + */ + public $fields = false; + + /** + * Constructor + * + * @param object $d database connection + * + * @return void + * @access public + */ + function __construct($dbh, $config) + { + + parent::__construct($dbh, $config); + + $this->fields = array( + + // Record ID + 'id' => array( + 'field' => 'id', + 'as' => false, + 'type' => 'integer', + 'required' => true, + 'unique' => true, + 'default' => false, + 'use' => 'lged' + ), + + // Promo Code Name + 'name' => array( + 'field' => 'name', + 'as' => false, + 'type' => 'text', + 'required' => true, + 'unique' => true, + 'default' => false, + 'use' => 'a' + ), + + // Promo Code Long Name + 'long_name' => array( + 'field' => 'long_name', + 'as' => false, + 'type' => 'text', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Description + 'descr' => array( + 'field' => 'descr', + 'as' => false, + 'type' => 'text', + 'filter' => FILTER_SANITIZE_MAGIC_QUOTES, + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Start Date + 'start_date' => array( + 'field' => 'start_date', + 'as' => false, + 'type' => 'date', + 'format' => 'm/d/Y', + 'minValue' => strtotime('1/1/'.date('Y')), // Earliest is now + 'maxValue' => strtotime('12/31/'.date('Y').' +3 years'), // This year plus 3 + 'required' => true, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // End Date + 'end_date' => array( + 'field' => 'end_date', + 'as' => false, + 'type' => 'date', + 'format' => 'm/d/Y', + 'minValue' => strtotime('1/1/'.date('Y')), // Earliest is now + 'maxValue' => strtotime('12/31/'.date('Y').' +3 years'), // This year plus 3 + 'required' => true, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Notes + 'notes' => array( + 'field' => 'notes', + 'as' => false, + 'type' => 'text', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ) + + ); + } + + /** + * Check for other field related issues + * + * Simply return $r if there's nothing to check. + * + * @return array + */ + function checkOther($r) + { + parent::checkOther($r); + + // Check that Sticky is not used with date-specific inventory + if ($r['fieldData']['date_specific']['value'] && $r['fieldData']['cart_sticky']['value']) { + $r['status'] = false; + $r['fieldFail']['cart_sticky'] = 'Sticky may not be used when "Specified Dates" is checked.'; + $r['fieldFail']['date_specific'] = 'Specified dates may not be used when "Sticky" is checked.'; + } + + return $r; + } + + /** + * Get Promo Code list + * + * @return object containing array as sub-objects + */ + function getPromosList() + { + + // Build query Where clause + $where = 'true'; + + // Get list of Promo Codes + $promosList = $this->getList($where, 'start_date, name'); + + return $promosList; + } + + /** + * Get Promo Code Detail + * + * @return array + */ + function getPromoDetail($promoID = false) + { + + // If a promo code has been specified + if ($promoID != false) { + + $_SESSION[GLM_EVENT_SESSION]['Promo'] = $promoID; + + // Otherwise if there's a promo code ID in the request + } elseif (($promoID = filter_input(INPUT_GET, 'PromoID', FILTER_SANITIZE_NUMBER_INT))) { + + // There's a Promo Code submitted, so save that + $_SESSION[GLM_EVENT_SESSION]['Promo'] = $promoID; + + } elseif (isset($_SESSION[GLM_EVENT_SESSION]['Promo'])) { + + // Otherwise, get the promo code ID from the session + $promoID = $_SESSION[GLM_EVENT_SESSION]['Promo']; + + } else { + + // Otherwise, we don't have a promo code id + return false; + + } + + $promoDetail = $this->getEntry($promoID); + + return $promoDetail; + + } + + /** + * Edit Promo Code + * + * @return array + */ + function editPromo() + { + + if (($promoID = filter_input(INPUT_GET, 'PromoID', FILTER_SANITIZE_NUMBER_INT))) { + + // If so then add it to the session + $_SESSION[GLM_EVENT_SESSION]['Promo'] = $promoID; + + } elseif (isset($_SESSION[GLM_EVENT_SESSION]['Promo'])) { + + // Otherwise, get the promo code ID from the session + $promoID = $_SESSION[GLM_EVENT_SESSION]['Promo']; + + } else { + + // Otherwise, we don't have a ticket id + return false; + + } + + $promoDetail = $this->editEntry($promoID); + + return $promoDetail; + + } + + /** + * Update Promo Code + * + * @return array + */ + function updatePromo() + { + + if (($promoID = filter_input(INPUT_GET, 'PromoID', FILTER_SANITIZE_NUMBER_INT))) { + + // If so then add it to the session + $_SESSION[GLM_EVENT_SESSION]['Promo'] = $promoID; + + } elseif (isset($_SESSION[GLM_EVENT_SESSION]['Promo'])) { + + // Otherwise, get the promo code ID from the session + $promoID = $_SESSION[GLM_EVENT_SESSION]['Promo']; + + } else { + + // Otherwise, we don't have a promo code id + return false; + + } + + // Try to update this data + $r = $this->updateEntry($promoID); + + return $r; + + } + + /** + * Add New Promo Code + * + * @return array + */ + function newPromo() + { + + $r = $this->newEntry(); + + return $r; + + } + + /** + * Insert Promo Code + * + * @return array + */ + function insertPromo() + { + + $r = $this->insertEntry(); + + // If succesful then set current promo code to the one just inserted. + if ($r['status']) { + $_SESSION[GLM_EVENT_SESSION]['Promo'] = $r['insertedID']; + } + + return $r; + + } + + /** + * Delete Promo Code + * + * @param $confirm bool False to ask if user wants to delete and true to actually delete + * + * @return array + */ + function promoDelete($confirm = false) + { + +echo "dataPromos.php - promoDelete() - need to also delete from promo_ticket table"; + + // Is there a new promo code code selected? + if (($promoID = filter_input(INPUT_GET, 'PromoID', FILTER_SANITIZE_NUMBER_INT))) { + + // If so then add it to the session + $_SESSION[GLM_EVENT_SESSION]['Promo'] = $promoID; + + } elseif (isset($_SESSION[GLM_EVENT_SESSION]['Promo'])) { + + // Otherwise, get the promo code ID from the session + $promoID = $_SESSION[GLM_EVENT_SESSION]['Promo']; + + } else { + + // Otherwise, we don't have an promo code id + return false; + + } + + $promoDetail = $this->deleteEntry($promoID, $confirm); + + return $promoDetail; + + } + + +} + +?> \ No newline at end of file diff --git a/classes/data/dataReservations.php b/classes/data/dataReservations.php new file mode 100644 index 0000000..482382b --- /dev/null +++ b/classes/data/dataReservations.php @@ -0,0 +1,830 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: dataReservations.php,v 1.0 2011/01/25 19:31:47 cscott Exp $ + * @link http://www.gaslightmedia.com/ + */ + +require_once DATA_ABSTRACT; + +/** + * EventManagementDataReservations class + * + * PHP version 5 + * + * @category Data + * @package EventManagement + * @author Chuck Scott + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: dataReservations.php,v 1.0 2011/01/25 19:31:47 cscott Exp $ + * @link http://www.gaslightmedia.com + */ +class EventManagementDataReservations extends DataAbstract +{ + /** + * Field definitions + * + * @var $ini + * @access public + */ + public $table = 'eventmgt.reservation'; + + /** + * Field definitions + * + * 'type' is type of field as defined by the application + * text Regular text field + * pointer Pointer to an entry in another table + * 'filters' is the filter name for a particular filter ID in PHP filter functions + * See PHP filter_id() + * + * 'use' is when to use the field + * l = List + * g = Get + * n = New + * i = Insert + * e = Edit + * u = Update + * d = Delete + * a = All + * + * @var $ini + * @access public + */ + public $fields = false; + + /** + * Constructor + * + * @param object $d database connection + * + * @return void + * @access public + */ + function __construct($dbh, $config) + { + + parent::__construct($dbh, $config); + + $this->fields = array( + + // Record ID + 'id' => array( + 'field' => 'id', + 'as' => false, + 'type' => 'integer', + 'required' => true, + 'unique' => true, + 'default' => false, + 'use' => 'lg' + ), + + // User Trace Info + 'user_trace_info' => array( + 'field' => 'user_trace_info', + 'as' => false, + 'type' => 'text', + 'required' => true, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // First Name + 'fname' => array( + 'field' => 'fname', + 'as' => false, + 'type' => 'text', + 'required' => true, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Last Name + 'lname' => array( + 'field' => 'lname', + 'as' => false, + 'type' => 'text', + 'required' => true, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Team name (stored as "org") - need to clean up field name + 'org' => array( + 'field' => 'org', + 'as' => false, + 'type' => 'text', + 'required' => true, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Event + 'event' => array( + 'field' => 'event', + 'as' => 'event_name', + 'type' => 'pointer', + 'p_table' => 'eventmgt.event', + 'p_field' => 'name', + 'p_id' => 'id', + 'required' => true, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Event name + 'event' => array( + 'field' => 'event', + 'as' => false, + 'type' => 'pointer', + 'p_table' => 'eventmgt.event', + 'p_field' => 'event_code', + 'p_id' => 'id', + 'required' => true, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Team + 'team' => array( + 'field' => 'team', + 'as' => 'team_name', + 'type' => 'pointer', + 'p_table' => 'eventmgt.team', + 'p_field' => 'name', + 'p_id' => 'id', + 'required' => true, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // State Rep + 'state_rep' => array( + 'field' => 'state_rep', + 'as' => false, + 'type' => 'integer', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // State Rep Code + 'state_rep_code' => array( + 'field' => 'state_rep', + 'as' => 'state_rep_code', + 'type' => 'pointer', + 'p_table' => 'eventmgt.state_rep', + 'p_field' => 'code', + 'p_id' => 'id', + 'required' => true, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Member (property) + 'member' => array( + 'field' => 'member', + 'as' => 'member_name', + 'type' => 'pointer', + 'p_table' => 'eventmgt.member', + 'p_field' => 'name', + 'p_id' => 'id', + 'required' => true, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Member (property) ID + 'member_id' => array( + 'field' => 'member', + 'as' => 'member_id', + 'type' => 'integer', + 'required' => true, + 'unique' => false, + 'default' => false, + 'use' => 'lg' + ), + + // Address Line 1 + 'addr1' => array( + 'field' => 'addr1', + 'as' => false, + 'type' => 'text', + 'required' => true, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Address Line 2 + 'addr2' => array( + 'field' => 'addr2', + 'as' => false, + 'type' => 'text', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // City + 'city' => array( + 'field' => 'city', + 'as' => false, + 'type' => 'text', + 'required' => true, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // State + 'state' => array( + 'field' => 'state', + 'as' => false, + 'type' => 'text', + 'required' => true, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Country + 'country' => array( + 'field' => 'country', + 'as' => false, + 'type' => 'text', + 'required' => true, + 'unique' => false, + 'default' => false, + 'use' => 'lnieudc' + ), + + // Country Full - Get Detail only + 'countryFull' => array( + 'field' => 'country', + 'as' => false, + 'type' => 'list', + 'list' => $this->config->countries->toArray(), + 'list_keytype' => 'text', + 'required' => true, + 'unique' => false, + 'default' => false, + 'use' => 'g' + ), + + // ZIP + 'zip' => array( + 'field' => 'zip', + 'as' => false, + 'type' => 'text', + 'required' => true, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Phone + 'phone' => array( + 'field' => 'phone', + 'as' => false, + 'type' => 'phone', + 'required' => true, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + + // Contact E-Mail + 'email' => array( + 'field' => 'email', + 'as' => false, + 'type' => 'email', + 'required' => true, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // OK to sent email + 'email_ok' => array( + 'field' => 'email_ok', + 'as' => false, + 'type' => 'checkbox', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Date reservation was entered. + 'date_entered' => array( + 'field' => 'date_entered', + 'as' => false, + 'type' => 'date', + 'required' => true, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Arrive Date + 'arrive_date' => array( + 'field' => 'arrive_date', + 'as' => false, + 'type' => 'date', + 'required' => true, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Nights + 'nights' => array( + 'field' => 'nights', + 'as' => false, + 'type' => 'integer', + 'required' => true, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Number of Rooms + 'rooms' => array( + 'field' => 'rooms', + 'as' => false, + 'type' => 'integer', + 'required' => true, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Occupants (adults) + 'adults' => array( + 'field' => 'adults', + 'as' => false, + 'type' => 'integer', + 'required' => true, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Payment method + 'payby' => array( + 'field' => 'payby', + 'as' => false, + 'type' => 'list', + 'list' => $this->config->pay_types->toArray(), + 'list_keytype' => 'int', + 'required' => true, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Credit Card Type + 'cctype' => array( + 'field' => 'cctype', + 'as' => false, + 'type' => 'text', + 'required' => true, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Credit Card Number + 'ccnumber' => array( + 'field' => 'ccnumber', + 'as' => false, + 'type' => 'text', + 'required' => true, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Credit Card Expiration + 'expire' => array( + 'field' => 'expire', + 'as' => false, + 'type' => 'text', + 'required' => true, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Name on Credit Card + 'ccname' => array( + 'field' => 'ccname', + 'as' => false, + 'type' => 'text', + 'required' => true, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Credit Card CCV + 'cccode' => array( + 'field' => 'cccode', + 'as' => false, + 'type' => 'text', + 'required' => true, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Total Room Rate for stay (formatted) + 'hotel_price' => array( + 'field' => 'hotel_price', + 'as' => false, + 'type' => 'money', + 'required' => true, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Total Room Rate for stay (number) + 'hotel_price_numb' => array( + 'field' => 'hotel_price', + 'as' => 'hotel_price_numb', + 'type' => 'float', + 'required' => true, + 'unique' => false, + 'default' => false, + 'use' => 'l' + ), + + // Total Taxes (formatted) + 'taxes' => array( + 'field' => 'taxes', + 'as' => false, + 'type' => 'money', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Total Taxes (number) + 'taxes_numb' => array( + 'field' => 'taxes', + 'as' => 'taxes_numb', + 'type' => 'float', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'l' + ), + + // Grand Total (formatted) + 'grand_total' => array( + 'field' => 'grand_total', + 'as' => false, + 'type' => 'money', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Grand Total (number) + 'grand_total_numb' => array( + 'field' => 'grand_total', + 'as' => 'grand_total_numb', + 'type' => 'float', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'l' + ), + + // Confirmed + 'confirmed' => array( + 'field' => 'confirmed', + 'as' => false, + 'type' => 'checkbox', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Declined + 'declined' => array( + 'field' => 'declined', + 'as' => false, + 'type' => 'checkbox', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // date_confirmed + 'date_confirmed' => array( + 'field' => 'date_confirmed', + 'as' => false, + 'type' => 'date', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Confirmed By + 'conf_by' => array( + 'field' => 'conf_by', + 'as' => false, + 'type' => 'text', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Confirmation Message + 'conf_message' => array( + 'field' => 'conf_message', + 'as' => false, + 'type' => 'text', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Reservation Detail (serialized array) + 'res_detail' => array( + 'field' => 'res_detail', + 'as' => false, + 'type' => 'text', + 'required' => false, + 'unique' => false, + 'default' => false, + 'no_stripslashes' => true, + 'use' => 'a' + ), + + // HTML Summary of Reservation + 'summary' => array( + 'field' => 'summary', + 'as' => false, + 'type' => 'text', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ) + + ); + } + + /** + * Get Reservations list + * + * @return object containing array as sub-objects + */ + function getReservationsList() + { + + // Get event ID from session - if available + $eventID = $_SESSION[GLM_EVENT_SESSION]['Event']; + + // Get member ID from session - if available + $memberID = $_SESSION[GLM_EVENT_SESSION]['Member']; + + // Get accommodation ID from session - if available + $accomID = $_SESSION[GLM_EVENT_SESSION]['Accom']; + + // Get team ID from session - if available + $teamID = $_SESSION[GLM_EVENT_SESSION]['Team']; + + // Get any specified reservation listing option - default to event + $option = 'event'; + if (($resListOption = filter_input(INPUT_GET, 'ReservationsListOption', FILTER_SANITIZE_STRING))) { + $option = $resListOption; + } + $status = 'all'; + if (($resListStatus = filter_input(INPUT_GET, 'ReservationsListStatus', FILTER_SANITIZE_STRING))) { + $status = $resListStatus; + } + + // Select type of list + $where = ''; + switch ($option) { + case 'all': + $where = 'TRUE'; + break; + case 'event': + if (!$eventID) { + return false; + } + $where = "T.event = $eventID"; + break; + case 'member': + if (!$memberID) { + return false; + } + $where = "T.member = $memberID"; + break; + case 'accom': + if (!$accomID) { + return false; + } + $where = "T.accommodation = $accomID"; + break; + case 'team': + if (!$teamID) { + return false; + } + $where = "T.team_id = $memberID"; + break; + default: + echo "Option not set"; + break; + } + + // Select by status + switch ($status) { + case 'pending': + $where .= ($where!=''?' AND ':'')." NOT T.confirmed AND NOT T.declined"; + break; + case 'confirmed': + $where .= ($where!=''?' AND ':'')." T.confirmed AND NOT T.declined"; + break; + case 'declined': + $where .= ($where!=''?' AND ':'')." T.declined"; + break; + case 'all': + default: + break; + } + + // Get list of Reservations + $resList = $this->getList($where); + return $resList; + } + + /** + * Get Reservation Detail + * + * @return array + */ + function getReservationDetail() + { + + // Is there a new reservation code selected? + if (($resID = filter_input(INPUT_GET, 'ReservationID', FILTER_SANITIZE_NUMBER_INT))) { + + // If so then add it to the session + $_SESSION[GLM_EVENT_SESSION]['Reservation'] = $resID; + + } elseif (isset($_SESSION[GLM_EVENT_SESSION]['Reservation'])) { + + // Otherwise, get the team ID from the session + $resID = $_SESSION[GLM_EVENT_SESSION]['Reservation']; + + } else { + + // Otherwise, we don't have a team id + return false; + + } + + $resDetail = $this->getEntry($resID); + + // NEED TO PUT THIS CAPABILITY INTO ABSTRACT AS AN OPTION + $resDetail['summary'] = html_entity_decode($resDetail['summary']); + + // echo "
".print_r($resDetail,1)."
"; + return $resDetail; + + } + + + /** + * Edit Reservation + * + * @return array + */ + function editReservation() + { + + if (($resID = filter_input(INPUT_GET, 'ReservationID', FILTER_SANITIZE_NUMBER_INT))) { + + // If so then add it to the session + $_SESSION[GLM_EVENT_SESSION]['Reservation'] = $resID; + + } elseif (isset($_SESSION[GLM_EVENT_SESSION]['Reservation'])) { + + // Otherwise, get the team ID from the session + $teamID = $_SESSION[GLM_EVENT_SESSION]['Reservation']; + + } else { + + // Otherwise, we don't have a team id + return false; + + } + + $resDetail = $this->editEntry($resID); + + return $resDetail; + + } + + /** + * Check for other field related issues + * + * This function must be here because it's called from a function + * in dataAbstract. Simply return $r if there's nothing to check. + * + * @return array + */ + function checkOther($r) + { + parent::checkOther($r); + + // Nothing here for now + + return $r; + } + + /** + * Update Reservation + * + * @return array + */ + function updateReservation() + { + + if (($resID = filter_input(INPUT_GET, 'ReservationID', FILTER_SANITIZE_NUMBER_INT))) { + + // If so then add it to the session + $_SESSION[GLM_EVENT_SESSION]['Reservation'] = $resID; + + } elseif (isset($_SESSION[GLM_EVENT_SESSION]['Reservation'])) { + + // Otherwise, get the reservation ID from the session + $resID = $_SESSION[GLM_EVENT_SESSION]['Reservation']; + + } else { + + // Otherwise, we don't have a reservation id + return false; + + } + + // Try to update this data + $r = $this->updateEntry($resID); + + return $r; + + } + + /** + * Insert Reservation + * + * @return array + */ + function insertReservation() + { + + echo "INSERT NOT SUPPORTED FOR RESERVATIONS IN EVENT MANAGEMENT ADMIN AREA!"; + exit; + + } + +} + + + + +?> \ No newline at end of file diff --git a/classes/data/dataRooms.php b/classes/data/dataRooms.php new file mode 100644 index 0000000..650e8ac --- /dev/null +++ b/classes/data/dataRooms.php @@ -0,0 +1,457 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: dataRooms.php,v 1.0 2011/01/25 19:31:47 cscott Exp $ + * @link http://www.gaslightmedia.com/ + */ + +require_once DATA_ABSTRACT; + +/** + * EventManagementDataRooms class + * + * PHP version 5 + * + * @category Data + * @package EventManagement + * @author Chuck Scott + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: dataRooms.php,v 1.0 2011/01/25 19:31:47 cscott Exp $ + * @link http://www.gaslightmedia.com + */ +class EventManagementDataRooms extends DataAbstract +{ + /** + * Field definitions + * + * @var $ini + * @access public + */ + public $table = 'eventmgt.room_detail'; + + /** + * Field definitions + * + * 'type' is type of field as defined by the application + * text Regular text field + * pointer Pointer to an entry in another table + * 'filters' is the filter name for a particular filter ID in PHP filter functions + * See PHP filter_id() + * + * 'use' is when to use the field + * l = List + * g = Get + * n = New + * i = Insert + * e = Edit + * u = Update + * d = Delete + * a = All + * + * @var $ini + * @access public + */ + public $fields = false; + + /** + * Constructor + * + * @param object $d database connection + * + * @return void + * @access public + */ + function __construct($dbh, $config) + { + + parent::__construct($dbh, $config); + + $this->fields = array( + + // Record ID + 'id' => array( + 'field' => 'id', + 'as' => false, + 'type' => 'integer', + 'required' => true, + 'unique' => true, + 'default' => false, + 'use' => 'lg' + ), + + // Member + 'member' => array( + 'field' => 'member', + 'as' => false, + 'type' => 'integer', + 'required' => true, + 'unique' => false, + 'default' => false, + 'use' => 'i' + ), + + // Accommodation + 'accommodation' => array( + 'field' => 'accommodation', + 'as' => false, + 'type' => 'integer', + 'required' => true, + 'unique' => false, + 'default' => false, + 'use' => 'i' + ), + + // Occupants + 'occupants' => array( + 'field' => 'occupants', + 'as' => false, + 'type' => 'integer', + 'required' => true, + 'unique' => false, + 'default' => 0, + 'use' => 'a' + ), + + // Room Type - Needs to be moved to a separate admin table + 'room_type' => array( + 'field' => 'room_type', + 'as' => false, + 'type' => 'list', + 'list' => $this->config->room_types->toArray(), + 'list_keytype' => 'int', + 'required' => true, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Bath Type - Needs to be moved to a separate admin table + 'bath_type' => array( + 'field' => 'bath_type', + 'as' => false, + 'type' => 'list', + 'list' => $this->config->bath_types->toArray(), + 'list_keytype' => 'int', + 'required' => true, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Pull-out Beds + 'pullout_beds' => array( + 'field' => 'pullout_beds', + 'as' => false, + 'type' => 'integer', + 'required' => true, + 'unique' => false, + 'default' => 0, + 'use' => 'a' + ), + + // Single Beds + 'single_beds' => array( + 'field' => 'single_beds', + 'as' => false, + 'type' => 'integer', + 'required' => true, + 'unique' => false, + 'default' => 0, + 'use' => 'a' + ), + + // Double Beds + 'double_beds' => array( + 'field' => 'double_beds', + 'as' => false, + 'type' => 'integer', + 'required' => true, + 'unique' => false, + 'default' => 0, + 'use' => 'a' + ), + + // Queen Beds + 'queen_beds' => array( + 'field' => 'queen_beds', + 'as' => false, + 'type' => 'integer', + 'required' => true, + 'unique' => false, + 'default' => 0, + 'use' => 'a' + ), + + // King Beds + 'king_beds' => array( + 'field' => 'king_beds', + 'as' => false, + 'type' => 'integer', + 'required' => true, + 'unique' => false, + 'default' => 0, + 'use' => 'a' + ), + + // TV + 'tv' => array( + 'field' => 'tv', + 'as' => false, + 'type' => 'checkbox', + 'required' => false, + 'unique' => false, + 'default' => 0, + 'use' => 'a' + ), + + // Fridge + 'fridge' => array( + 'field' => 'fridge', + 'as' => false, + 'type' => 'checkbox', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Safe + 'safe' => array( + 'field' => 'safe', + 'as' => false, + 'type' => 'checkbox', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Description + 'descr' => array( + 'field' => 'descr', + 'as' => false, + 'type' => 'text', + 'filter' => FILTER_SANITIZE_MAGIC_QUOTES, + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Image + 'image' => array( + 'field' => 'image', + 'as' => false, + 'type' => 'image', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Display Order (sort) + 'sort' => array( + 'field' => 'sort', + 'as' => false, + 'type' => 'integer', + 'required' => false, + 'unique' => false, + 'default' => 0, + 'use' => 'a' + ) + + ); + } + + /** + * Get Rooms list + * + * @return object containing array as sub-objects + */ + function getRoomsList() + { + + // Get accommodation ID from session - if available + $accomID = $_SESSION[GLM_EVENT_SESSION]['Accom']; + + if (!$accomID) { + return false; + } + + // Select type of list + $where = "T.accommodation = $accomID"; + + // Get list of States + $roomsList = $this->getList($where, 'sort'); + + // Build Beds summary + if ($roomsList && count($roomsList) > 0) { + reset($roomsList); + while( list($key, $val) = each( $roomsList ) ) { + $beds_summary = ''; + $sep = ''; + if ($val['pullout_beds'] > 0) { + $beds_summary .= $val['pullout_beds']." Pullout"; + $sep = ', '; + } + if ($val['single_beds'] > 0) { + $beds_summary .= $sep.$val['single_beds']." Single"; + $sep = ', '; + } + if ($val['double_beds'] > 0) { + $beds_summary .= $sep.$val['double_beds']." Double"; + $sep = ', '; + } + if ($val['queen_beds'] > 0) { + $beds_summary .= $val['queen_beds']." Queen"; + $sep = ', '; + } + if ($val['king_beds'] > 0) { + $beds_summary .= $val['king_beds']." King"; + $sep = ', '; + } + $roomsList[$key]['beds_summary'] = $beds_summary; + } + } + + return $roomsList; + } + + /** + * Get Room Detail + * + * @return array + */ + function getRoomDetail() + { + + // Is there a new State Rep code selected? + if (!($roomID = filter_input(INPUT_GET, 'RoomID', FILTER_SANITIZE_NUMBER_INT))) { + + return false; + + } + + $roomDetail = $this->getEntry($roomID); + + return $roomDetail; + + } + + + /** + * Edit Room + * + * @return array + */ + function editRoom() + { + if (!($roomID = filter_input(INPUT_GET, 'RoomID', FILTER_SANITIZE_NUMBER_INT))) { + + // Otherwise, we don't have a state rep id + return false; + + } + + $roomDetail = $this->editEntry($roomID); + + $roomDetail['RoomID'] = $roomID; + + // echo "
".print_r($roomDetail,1)."
"; + return $roomDetail; + + } + + /** + * Check for other field related issues + * + * This function must be here because it's called from a function + * in dataAbstract. Simply return $r if there's nothing to check. + * + * @return array + */ + function checkOther($r) + { + parent::checkOther($r); + return $r; + } + + /** + * Update Room + * + * @return array + */ + function updateRoom() + { + + if (!($roomID = filter_input(INPUT_POST, 'RoomID', FILTER_SANITIZE_NUMBER_INT))) { + return false; + } + + // Try to update this data + $r = $this->updateEntry($roomID); + + $r['fieldData']['RoomID'] = $roomID; + + return $r; + + } + + + /** + * Add New Room + * + * @return array + */ + function newRoom() + { + // Get member and accommodation ID from session - if available + $membID = $_SESSION[GLM_EVENT_SESSION]['Member']; + $accomID = $_SESSION[GLM_EVENT_SESSION]['Accom']; + + if (!$accomID) { + return false; + } + + $r = $this->newEntry(); + + $r['fieldData']['member'] = $membID; + $r['fieldData']['accommodation'] = $accomID; + + return $r; + + } + + /** + * Insert Room + * + * @return array + */ + function insertRoom() + { + + $r = $this->insertEntry(); + + // If succesful then set current state rep to the one just inserted. + if ($r['status']) { + $_SESSION[GLM_EVENT_SESSION]['State'] = $r['insertedID']; + } + + return $r; + + } + +} + + + + +?> \ No newline at end of file diff --git a/classes/data/dataSections.php b/classes/data/dataSections.php new file mode 100644 index 0000000..ae768c4 --- /dev/null +++ b/classes/data/dataSections.php @@ -0,0 +1,450 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: dataSections.php,v 1.0 2011/01/25 19:31:47 cscott Exp $ + * @link http://www.gaslightmedia.com/ + */ + +require_once DATA_ABSTRACT; + +/** + * EventManagementDataSections class + * + * PHP version 5 + * + * @category Data + * @package EventManagement + * @author Chuck Scott + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: dataSections.php,v 1.0 2011/01/25 19:31:47 cscott Exp $ + * @link http://www.gaslightmedia.com + */ +class EventManagementDataSections extends DataAbstract +{ + /** + * Field definitions + * + * @var $ini + * @access public + */ + public $table = 'eventmgt.section'; + + /** + * Field definitions + * + * 'type' is type of field as defined by the application + * text Regular text field + * pointer Pointer to an entry in another table + * 'filters' is the filter name for a particular filter ID in PHP filter functions + * See PHP filter_id() + * + * 'use' is when to use the field + * l = List + * g = Get + * n = New + * i = Insert + * e = Edit + * u = Update + * d = Delete + * a = All + * + * @var $ini + * @access public + */ + public $fields = false; + + /** + * Constructor + * + * @param object $d database connection + * + * @return void + * @access public + */ + function __construct($dbh, $config) + { + + parent::__construct($dbh, $config); + + $this->fields = array( + + // Record ID + 'id' => array( + 'field' => 'id', + 'as' => false, + 'type' => 'integer', + 'required' => true, + 'unique' => true, + 'default' => false, + 'use' => 'lg' + ), + + // Member ID for adding sections + 'member' => array( + 'field' => 'member', + 'as' => false, + 'type' => 'integer', + 'required' => true, + 'unique' => false, + 'default' => $_SESSION[GLM_EVENT_SESSION]['Member'], + 'use' => 'nid' + ), + + // Member Name display + 'member_view' => array( + 'field' => 'member', + 'as' => 'member_name', + 'type' => 'pointer', + 'p_table' => 'eventmgt.member', + 'p_field' => 'name', + 'p_id' => 'id', + 'p_static' => true, + 'required' => true, + 'unique' => false, + 'default' => false, + 'view_only' => true, + 'use' => 'gleu' + ), + + // Section Name + 'name' => array( + 'field' => 'name', + 'as' => false, + 'type' => 'text', + 'required' => true, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Description + 'descr' => array( + 'field' => 'descr', + 'as' => false, + 'type' => 'text', + 'filter' => FILTER_SANITIZE_MAGIC_QUOTES, + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Image + 'image' => array( + 'field' => 'image', + 'as' => false, + 'type' => 'image', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Entrance + 'entrance' => array( + 'field' => 'entrance', + 'as' => false, + 'type' => 'pointer', + 'p_table' => 'eventmgt.entrance', + 'p_field' => 'name', + 'p_id' => 'id', + 'p_where' => 'member = '.$_SESSION[GLM_EVENT_SESSION]['Member'], + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'nideu' + ), + + // Entrance_view + 'entrance_view' => array( + 'field' => 'entrance', + 'as' => false, + 'type' => 'pointer', + 'p_table' => 'eventmgt.entrance', + 'p_field' => 'name', + 'p_id' => 'id', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'gl' + ), + + // Entrance_id + 'entrance_id' => array( + 'field' => 'entrance', + 'as' => false, + 'type' => 'integer', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'gl' + ), + + // Sort order + 'sort' => array( + 'field' => 'sort', + 'as' => false, + 'type' => 'integer', + 'required' => true, + 'unique' => false, + 'default' => 999, + 'use' => 'a' + ), + + // Notes + 'notes' => array( + 'field' => 'notes', + 'as' => false, + 'type' => 'text', + 'filter' => FILTER_SANITIZE_MAGIC_QUOTES, + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ) + + + ); + } + + /** + * Get Sections list + * + * @return object containing array as sub-objects + */ + function getSectionsList($memberID = false, $where = false) + { + + // If a where clause has not been supplied + if (!$where) { + + $where = 'true'; + + // Check if there's a member ID and filter by that member if there is + $memberID = ($memberID - 0); // Make sure it's number + if ($memberID > 0) { + $where .= " AND T.member = $memberID"; + } elseif ($_SESSION[GLM_EVENT_MGT_ADMIN]['Member'] > 0) { + $where .= " AND T.member = ".$_SESSION[GLM_EVENT_MGT_ADMIN]['Member']; + } + + } + + // Get list of Sections + $sectionsList = $this->getList($where, 'sort, name'); + + return $sectionsList; + } + + /** + * Get Section Detail + * + * @return array + */ + function getSectionDetail($sectionID = false) + { + + // If a section ID has been supplied + if ($sectionID != false) { + + $_SESSION[GLM_EVENT_SESSION]['Section'] = $sectionID; + + } elseif (($sectionID = filter_input(INPUT_GET, 'SectionID', FILTER_SANITIZE_NUMBER_INT))) { + + // Otherwise if there a new section ID supplied via the request + $_SESSION[GLM_EVENT_SESSION]['Section'] = $sectionID; + + } elseif (isset($_SESSION[GLM_EVENT_SESSION]['Section'])) { + + // Otherwise, get the event ID from the session + $sectionID = $_SESSION[GLM_EVENT_SESSION]['Section']; + + } else { + + // Otherwise, we don't have an event id + return false; + + } + + $sectionDetail = $this->getEntry($sectionID); + + return $sectionDetail; + + } + + + /** + * Edit Section + * + * @return array + */ + function editSection() + { + + if (($sectionID = filter_input(INPUT_GET, 'SectionID', FILTER_SANITIZE_NUMBER_INT))) { + + // If so then add it to the session + $_SESSION[GLM_EVENT_SESSION]['Section'] = $sectionID; + + } elseif (isset($_SESSION[GLM_EVENT_SESSION]['Section'])) { + + // Otherwise, get the section ID from the session + $sectionID = $_SESSION[GLM_EVENT_SESSION]['Section']; + + } else { + + // Otherwise, we don't have a section id + return false; + + } + + $sectionDetail = $this->editEntry($sectionID); + + return $sectionDetail; + + } + + /** + * Check for other field related issues + * + * This function must be here because it's called from a function + * in dataAbstract. Simply return $r if there's nothing to check. + * + * @return array + */ + function checkOther($r) + { + parent::checkOther($r); + return $r; + } + + /** + * Update Section + * + * @return array + */ + function updateSection() + { + + if (($sectionID = filter_input(INPUT_GET, 'SectionID', FILTER_SANITIZE_NUMBER_INT))) { + + // If so then add it to the session + $_SESSION[GLM_EVENT_SESSION]['Section'] = $sectionID; + + } elseif (isset($_SESSION[GLM_EVENT_SESSION]['Section'])) { + + // Otherwise, get the section ID from the session + $sectionID = $_SESSION[GLM_EVENT_SESSION]['Section']; + + } else { + + // Otherwise, we don't have a section id + return false; + + } + + // Try to update this data + $r = $this->updateEntry($sectionID); + + return $r; + + } + + + /** + * Add New Section + * + * @return array + */ + function newSection() + { + + $r = $this->newEntry(); + + return $r; + + } + + /** + * Insert Section + * + * @return array + */ + function insertSection() + { + + $r = $this->insertEntry(); + + // If succesful then set current section to the one just inserted. + if ($r['status']) { + $_SESSION[GLM_EVENT_SESSION]['Section'] = $r['insertedID']; + } + + return $r; + + } + + + /** + * Delete Section + * + * @param $confirm bool False to ask if user wants to delete and true to actually delete + * + * @return array + */ + function sectionDelete($confirm = false) + { + + // Is there a new section code selected? + if (($sectionID = filter_input(INPUT_GET, 'SectionID', FILTER_SANITIZE_NUMBER_INT))) { + + // If so then add it to the session + $_SESSION[GLM_EVENT_SESSION]['Section'] = $sectionID; + + } elseif (isset($_SESSION[GLM_EVENT_SESSION]['Section'])) { + + // Otherwise, get the section ID from the session + $sectionID = $_SESSION[GLM_EVENT_SESSION]['Section']; + + } else { + + // Otherwise, we don't have an section id + return false; + + } + + $sectionDetail = $this->deleteEntry($sectionID, $confirm); + + return $sectionDetail; + + } + + /** + * Get Sections Stats + * + * @return object containing array as sub-objects + */ + function getSectionsStats($where = 'true') + { + + $sectionsStats = $this->getStats($where); + + return $sectionsStats; + } + + + +} + + + + +?> \ No newline at end of file diff --git a/classes/data/dataSold.php b/classes/data/dataSold.php new file mode 100644 index 0000000..ebad123 --- /dev/null +++ b/classes/data/dataSold.php @@ -0,0 +1,804 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: dataSold.php,v 1.0 2011/01/25 19:31:47 cscott Exp $ + * @link <> + */ + +require_once DATA_ABSTRACT; + +/** + * EventManagementDataSold class + * + * PHP version 5 + * + * @category Data + * @package EventManagement + * @author Chuck Scott + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: dataSold,v 1.0 2011/01/25 19:31:47 cscott Exp $ + * @link <> + */ +class EventManagementDataSold extends DataAbstract +{ + /** + * Tables + * + * @var $ini + * @access public + */ + public $table = 'eventmgt.ticket_sold'; + + /** + * Field definitions + * + * 'type' is type of field as defined by the application + * text Regular text field + * pointer Pointer to an entry in another table + * 'filters' is the filter name for a particular filter ID in PHP filter functions + * See PHP filter_id() + * + * 'use' is when to use the field + * l = List + * g = Get + * n = New + * i = Insert + * e = Edit + * u = Update + * d = Delete + * a = All + * + * @var $ini + * @access public + */ + public $fields = false; + + /** + * Constructor + * + * @param object $d database connection + * + * @return void + * @access public + */ + function __construct($dbh, $config) + { + + parent::__construct($dbh, $config); + + $this->fields = array( + + // Ticket Sold (Voucher) ID + 'id' => array( + 'field' => 'id', + 'as' => false, + 'type' => 'integer', + 'required' => true, + 'unique' => true, + 'default' => false, + 'use' => 'lged' + ), + + // Order ID + 'ticket_order' => array( + 'field' => 'ticket_order', + 'as' => false, + 'type' => 'integer', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'lged' + ), + + // Member ID + 'member' => array( + 'field' => 'member', + 'as' => false, + 'type' => 'integer', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'lged' + ), + + // Member Name + 'member_name' => array( + 'field' => 'member_name', + 'as' => false, + 'type' => 'text', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'lged' + ), + + // Ticket Voucher Left End Text + 'real_member_name' => array( + 'field' => 'member', + 'as' => 'real_member_name', + 'type' => 'pointer', + 'p_table' => 'eventmgt.member', + 'p_field' => 'name', + 'p_id' => 'id', + 'p_static' => true, + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'lged' + ), + + // Assigned (consignment to another venue) + 'assigned' => array( + 'field' => 'assigned', + 'as' => false, + 'type' => 'checkbox', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'lgd' + ), + + // Assigned From ID + 'assigned_from' => array( + 'field' => 'assigned_from', + 'as' => false, + 'type' => 'integer', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'lgd' + ), + + // Assigned from name + 'assigned_from_name' => array( + 'field' => 'assigned_from_name', + 'as' => false, + 'type' => 'text', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'lgd' + ), + + // Performance ID + 'performance' => array( + 'field' => 'performance', + 'as' => false, + 'type' => 'integer', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'lged' + ), + + // Performance Name + 'performance_name' => array( + 'field' => 'performance_name', + 'as' => false, + 'type' => 'text', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'lged' + ), + + // Entrance ID + 'entrance' => array( + 'field' => 'entrance', + 'as' => false, + 'type' => 'integer', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'lgd' + ), + + // Entrance Name + 'entrance_name' => array( + 'field' => 'entrance_name', + 'as' => false, + 'type' => 'text', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'lged' + ), + + // Entrance Color + 'entrance_color' => array( + 'field' => 'entrance_color', + 'as' => false, + 'type' => 'text', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'lged' + ), + + // Section ID + 'section' => array( + 'field' => 'section', + 'as' => false, + 'type' => 'integer', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'lged' + ), + + // Section Name + 'section_name' => array( + 'field' => 'section_name', + 'as' => false, + 'type' => 'text', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'lged' + ), + + // Ticket ID + 'ticket' => array( + 'field' => 'ticket', + 'as' => false, + 'type' => 'integer', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'lged' + ), + + // Ticket Name + 'ticket_name' => array( + 'field' => 'ticket_name', + 'as' => false, + 'type' => 'text', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'lged' + ), + + // Is Package + 'is_package' => array( + 'field' => 'is_package', + 'as' => false, + 'type' => 'checkbox', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'lgd' + ), + + // Ticket Package - points to ticket that is a package that includes this ticket - 0 if not part of a package + 'ticket_package' => array( + 'field' => 'ticket_package', + 'as' => false, + 'type' => 'integer', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'lged' + ), + + // Package Sold ID + 'package_sold_id' => array( + 'field' => 'package_sold_id', + 'as' => false, + 'type' => 'text', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'lged' + ), + + // Package Name + 'package_name' => array( + 'field' => 'package_name', + 'as' => false, + 'type' => 'text', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'lged' + ), + + // Ticket Voucher Text + 'ticket_voucher_text' => array( + 'field' => 'ticket', + 'as' => 'ticket_voucher_text', + 'type' => 'pointer', + 'p_table' => 'eventmgt.ticket', + 'p_field' => 'voucher_text', + 'p_id' => 'id', + 'p_static' => true, + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'lged' + ), + + // Ticket Voucher Type + 'ticket_voucher_type' => array( + 'field' => 'ticket', + 'as' => 'ticket_voucher_type', + 'type' => 'pointer', + 'p_table' => 'eventmgt.ticket', + 'p_field' => 'voucher_type', + 'p_id' => 'id', + 'p_static' => true, + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'lged' + ), + + // Ticket Voucher Left End Text + 'ticket_voucher_leftend_text' => array( + 'field' => 'ticket', + 'as' => 'ticket_voucher_leftend_text', + 'type' => 'pointer', + 'p_table' => 'eventmgt.ticket', + 'p_field' => 'voucher_leftend_text', + 'p_id' => 'id', + 'p_static' => true, + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'lged' + ), + + // Date Specific flag + 'date_specific' => array( + 'field' => 'date_specific', + 'as' => false, + 'type' => 'checkbox', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'lgd' + ), + + // Ticket Date + 'ticket_date' => array( + 'field' => 'ticket_date', + 'as' => false, + 'type' => 'date', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'lged' + ), + + // Time Specific flag + 'time_specific' => array( + 'field' => 'time_specific', + 'as' => false, + 'type' => 'checkbox', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'lgd' + ), + + // Ticket Time + 'ticket_time' => array( + 'field' => 'ticket_time', + 'as' => false, + 'type' => 'time', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'lged' + ), + + // Start Date for non-date-specific tickets + 'start_date' => array( + 'field' => 'start_date', + 'as' => false, + 'type' => 'date', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'lgd' + ), + + // End Date for non-date-specific tickets + 'end_date' => array( + 'field' => 'end_date', + 'as' => false, + 'type' => 'date', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'lgd' + ), + + // Date customer will likely use this ticket + 'likely_date' => array( + 'field' => 'likely_date', + 'as' => false, + 'type' => 'date', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'lgd' + ), + + // Price Paid + 'price_paid' => array( + 'field' => 'price_paid', + 'as' => false, + 'type' => 'money', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'lged' + ), + + // Policies at time of order + 'policies' => array( + 'field' => 'policies', + 'as' => false, + 'type' => 'text', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'lgd' + ), + + // Unlimited Use flag + 'unlimited_use' => array( + 'field' => 'unlimited_use', + 'as' => false, + 'type' => 'checkbox', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'lgd' + ), + + // Number of uses + 'numb_uses' => array( + 'field' => 'numb_uses', + 'as' => false, + 'type' => 'integer', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'lged' + ), + + // Number of times claimed + 'numb_claimed' => array( + 'field' => 'numb_claimed', + 'as' => false, + 'type' => 'integer', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'lgd' + ), + + // Time Claimed + 'time_claimed' => array( + 'field' => 'time_claimed', + 'as' => false, + 'type' => 'date', + 'format' => 'm/d/Y h:i:s A', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'lged' + ) + + ); + } + + + /** + * Get Orders list + * + * @return object containing array as sub-objects + */ + function getSoldList($orderID = false, $memberID = false) + { + + // If a order has been specified + if ($orderID != false) { + + $_SESSION[GLM_EVENT_SESSION]['Order'] = $orderID; + + // Otherwise if there's a order ID in the request + } elseif (($orderID = filter_input(INPUT_GET, 'OrderID', FILTER_SANITIZE_NUMBER_INT))) { + + $_SESSION[GLM_EVENT_SESSION]['Order'] = $orderID; + + } elseif (isset($_SESSION[GLM_EVENT_SESSION]['Order'])) { + + $orderID = $_SESSION[GLM_EVENT_SESSION]['Order']; + + } else { + + // Otherwise, we don't have an order id + return false; + + } + + $where = ''; + if ($memberID) { + $where = "AND T.member = $memberID"; + } + + // Get list of Tickets Sold + $soldList = $this->getList("T.ticket_order = $orderID $where", 'T.ticket_order, T.package_sold_id, T.id'); + + // Load addonsSold class + require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/addonsSold.php'; + $addonsSold = new EventManagementAdminAddonsSold($this->dbh, $this->config); + + // For each ticket, check for any add-ons that have been sold with it + if ($soldList != false) { + reset($soldList); + while (list($key, $val) = each($soldList)) { + // Get any add-ons included with this ticket + $addonsSoldList = $addonsSold->getAddonsSoldList($val['id']); + if ($addonsSoldList) { + $soldList[$key]['addons_sold'] = $addonsSoldList; + } + } + } + + return $soldList; + } + + /** + * Get Ticket Sold Detail + * + * @return array + */ + function getSoldDetail($soldID = false, $memberID = false) + { + // Test Check character + $testCheck = false; + + // If a order has been specified + if ($soldID != false) { + + $_SESSION[GLM_EVENT_SESSION]['Sold'] = $soldID; + + // Otherwise if there's a sold ID in the request + } elseif (($soldID = filter_input(INPUT_GET, 'SoldID', FILTER_SANITIZE_STRING))) { + + // Do a check character test if input from form. + $testCheck = true; + + $_SESSION[GLM_EVENT_SESSION]['Sold'] = $soldID; + + } elseif (isset($_SESSION[GLM_EVENT_SESSION]['Sold'])) { + + $soldID = $_SESSION[GLM_EVENT_SESSION]['Sold']; + + } else { + + // Otherwise, we don't have an ticket sold id + return false; + + } + + $checkBypass = filter_input(INPUT_GET, 'checkBypass', FILTER_SANITIZE_STRING); + if ( $checkBypass == 'true') { + $testCheck = false; + } + + + $where = ''; + if ($memberID) { + $where = "AND T.member = $memberID"; + } + + // If input came from form, then test the check char + $voucherNumb = $soldID; + if ($testCheck) { + // Separate check character from voucher number + $voucherNumb = substr($soldID, 0, -2); + $checkChar = substr($soldID, -2); + + // Check if check character + $c = $this->getCheckCode($voucherNumb); + if ($c != strtoupper($checkChar)) { + + return false; + } + } + + // If number has + $soldDetail = $this->getEntry($voucherNumb, 'id', $where); + + // If we have a member ID then make sure the sold ticket is for that member + if ($memberID && $soldDetail['member'] != $memberID) { + return false; + } + + return $soldDetail; + + } + + + /** + * Edit Sold + * + * @return array + */ + function editSold() + { +echo "editSold() not competed"; +/* + if (($ticketID = filter_input(INPUT_GET, 'TicketID', FILTER_SANITIZE_NUMBER_INT))) { + + // If so then add it to the session + $_SESSION[GLM_EVENT_SESSION]['Ticket'] = $ticketID; + + } elseif (isset($_SESSION[GLM_EVENT_SESSION]['Ticket'])) { + + // Otherwise, get the ticket ID from the session + $ticketID = $_SESSION[GLM_EVENT_SESSION]['Ticket']; + + } else { + + // Otherwise, we don't have a ticket id + return false; + + } + + $ticketDetail = $this->editEntry($ticketID); + + return $ticketDetail; +*/ + } + + /** + * Check for other field related issues + * + * This function must be here because it's called from a function + * in dataAbstract. Simply return $r if there's nothing to check. + * + * @return array + */ + function checkOther($r) + { + parent::checkOther($r); + return $r; + } + + /** + * Update Ticket Sold + * + * @return array + */ + function updateSold() + { + +echo "updateSold() not competed"; +/* + if (($ticketID = filter_input(INPUT_GET, 'TicketID', FILTER_SANITIZE_NUMBER_INT))) { + + // If so then add it to the session + $_SESSION[GLM_EVENT_SESSION]['Ticket'] = $ticketID; + + } elseif (isset($_SESSION[GLM_EVENT_SESSION]['Ticket'])) { + + // Otherwise, get the ticket ID from the session + $ticketID = $_SESSION[GLM_EVENT_SESSION]['Ticket']; + + } else { + + // Otherwise, we don't have a ticket id + return false; + + } + + // Try to update this data + $r = $this->updateEntry($ticketID); + + return $r; +*/ + } + + /** + * Delete Ticket Sold + * + * @param $confirm bool False to ask if user wants to delete and true to actually delete + * + * @return array + */ + function soldDelete($confirm = false) + { +echo "soldDelete() not competed"; +/* + + // Is there a new ticket code selected? + if (($ticketID = filter_input(INPUT_GET, 'TicketID', FILTER_SANITIZE_NUMBER_INT))) { + + // If so then add it to the session + $_SESSION[GLM_EVENT_SESSION]['Ticket'] = $ticketID; + + } elseif (isset($_SESSION[GLM_EVENT_SESSION]['Ticket'])) { + + // Otherwise, get the ticket ID from the session + $ticketID = $_SESSION[GLM_EVENT_SESSION]['Ticket']; + + } else { + + // Otherwise, we don't have an ticket id + return false; + + } + + $ticketDetail = $this->deleteEntry($ticketID, $confirm); + + return $ticketDetail; +*/ + } + + + /* + * Function to add check character to end of voucher number + * + * Uses config->voucher_check_secret and voucher # to create MD5 string + * then takes last hex character off of that string and shifts it up to + * always be a character (adds 16 to numbers and 10 to the upper-case + * version of the character). + * i.e. 0 = A, 9 = J, A = K, F = + * + */ + public function getCheckCode($voucherNumb) + { + + // Create MD5 string using voucher number and secret + $md5 = md5($voucherNumb.$this->config->voucher_check_secret); + + // Get last character code of the last character in the MD5 + $cc = strtoupper(substr($md5, -2)); + $cc[0] = $this->shiftCheckCodeCharacter($cc[0]); + $cc[1] = $this->shiftCheckCodeCharacter($cc[1]); + + // Return check code + return $cc; + + } + + private function shiftCheckCodeCharacter($c) { + + $x = ord($c); + + // If it's a digit, add 16 + if ($x < 65) { + $x += 17; + // otherwise, add 10 + } else { + $x += 10; + } + + // Also skip the letter O + if (x >= ord('O')) { + $x += 1; + } + + return chr($x); + } + +} + + + + +?> diff --git a/classes/data/dataStates.php b/classes/data/dataStates.php new file mode 100644 index 0000000..7fe8857 --- /dev/null +++ b/classes/data/dataStates.php @@ -0,0 +1,363 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: dataStates.php,v 1.0 2011/01/25 19:31:47 cscott Exp $ + * @link http://www.gaslightmedia.com/ + */ + +require_once DATA_ABSTRACT; + +/** + * EventManagementDataStates class + * + * PHP version 5 + * + * @category Data + * @package EventManagement + * @author Chuck Scott + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: dataStates.php,v 1.0 2011/01/25 19:31:47 cscott Exp $ + * @link http://www.gaslightmedia.com + */ +class EventManagementDataStates extends DataAbstract +{ + /** + * Field definitions + * + * @var $ini + * @access public + */ + public $table = 'eventmgt.state_rep'; + + /** + * Field definitions + * + * 'type' is type of field as defined by the application + * text Regular text field + * pointer Pointer to an entry in another table + * 'filters' is the filter name for a particular filter ID in PHP filter functions + * See PHP filter_id() + * + * 'use' is when to use the field + * l = List + * g = Get + * n = New + * i = Insert + * e = Edit + * u = Update + * d = Delete + * a = All + * + * @var $ini + * @access public + */ + public $fields = false; + + /** + * Constructor + * + * @param object $d database connection + * + * @return void + * @access public + */ + function __construct($dbh, $config) + { + + parent::__construct($dbh, $config); + + $this->fields = array( + + // Record ID + 'id' => array( + 'field' => 'id', + 'as' => false, + 'type' => 'integer', + 'required' => true, + 'unique' => true, + 'default' => false, + 'use' => 'lg' + ), + + // Event selection + 'conv' => array( + 'field' => 'conv', + 'as' => 'event_name', + 'type' => 'pointer', + 'p_table' => 'eventmgt.event', + 'p_field' => 'name', + 'p_id' => 'id', + 'required' => true, + 'unique' => false, + 'default' => false, + 'use' => 'nid' + ), + + // Event Name display + 'conv_view' => array( + 'field' => 'conv', + 'as' => 'event_name', + 'type' => 'pointer', + 'p_table' => 'eventmgt.event', + 'p_field' => 'name', + 'p_id' => 'id', + 'p_static' => true, + 'required' => true, + 'unique' => false, + 'default' => false, + 'view_only' => true, + 'use' => 'gleu' + ), + + // State Rep Code + 'code' => array( + 'field' => 'code', + 'as' => false, + 'type' => 'text', + 'required' => true, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Password + 'password' => array( + 'field' => 'password', + 'as' => false, + 'type' => 'text', + 'required' => true, + 'unique' => true, + 'default' => false, + 'use' => 'a' + ), + + // Description + 'descr' => array( + 'field' => 'descr', + 'as' => false, + 'type' => 'text', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Notes + 'notes' => array( + 'field' => 'notes', + 'as' => false, + 'type' => 'text', + 'filter' => FILTER_SANITIZE_MAGIC_QUOTES, + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ) + + ); + } + + /** + * Get States list + * + * @return object containing array as sub-objects + */ + function getStatesList() + { + + // Get event ID from session - if available + $eventID = $_SESSION[GLM_EVENT_SESSION]['Event']; + + // Get any specified state rep listing option - default to event + $option = 'event'; + if (($statesListOption = filter_input(INPUT_GET, 'StatesListOption', FILTER_SANITIZE_STRING))) { + $option = $statesListOption; + } + + // Select type of list + $where = ''; + switch ($option) { + case 'all': + $where = 'TRUE'; + break; + case 'event': + if (!$eventID) { + return false; + } + $where = "T.conv = $eventID"; + break; + default: + echo "Option not set"; + break; + } + + // Get list of States + $statesList = $this->getList($where, 'code'); + + return $statesList; + } + + /** + * Get State Rep Detail + * + * @return array + */ + function getStateDetail() + { + + // Is there a new State Rep code selected? + if (($stateID = filter_input(INPUT_GET, 'StateID', FILTER_SANITIZE_NUMBER_INT))) { + + // If so then add it to the session + $_SESSION[GLM_EVENT_SESSION]['State'] = $stateID; + + } elseif (isset($_SESSION[GLM_EVENT_SESSION]['State'])) { + + // Otherwise, get the state rep ID from the session + $stateID = $_SESSION[GLM_EVENT_SESSION]['State']; + + } else { + + // Otherwise, we don't have a state rep id + return false; + + } + + $stateDetail = $this->getEntry($stateID); + + return $stateDetail; + + } + + + /** + * Edit State Rep + * + * @return array + */ + function editState() + { + + if (($stateID = filter_input(INPUT_GET, 'StateID', FILTER_SANITIZE_NUMBER_INT))) { + + // If so then add it to the session + $_SESSION[GLM_EVENT_SESSION]['State'] = $stateID; + + } elseif (isset($_SESSION[GLM_EVENT_SESSION]['State'])) { + + // Otherwise, get the state rep ID from the session + $stateID = $_SESSION[GLM_EVENT_SESSION]['State']; + + } else { + + // Otherwise, we don't have a state rep id + return false; + + } + + $stateDetail = $this->editEntry($stateID); + + return $stateDetail; + + } + + /** + * Check for other field related issues + * + * This function must be here because it's called from a function + * in dataAbstract. Simply return $r if there's nothing to check. + * + * @return array + */ + function checkOther($r) + { + parent::checkOther($r); + return $r; + } + + /** + * Update State Rep + * + * @return array + */ + function updateState() + { + + if (($stateID = filter_input(INPUT_GET, 'StateID', FILTER_SANITIZE_NUMBER_INT))) { + + // If so then add it to the session + $_SESSION[GLM_EVENT_SESSION]['State'] = $stateID; + + } elseif (isset($_SESSION[GLM_EVENT_SESSION]['State'])) { + + // Otherwise, get the state rep ID from the session + $stateID = $_SESSION[GLM_EVENT_SESSION]['State']; + + } else { + + // Otherwise, we don't have a state rep id + return false; + + } + + // Try to update this data + $r = $this->updateEntry($stateID); + + return $r; + + } + + + /** + * Add New State Rep + * + * @return array + */ + function newState() + { + + $r = $this->newEntry(); + + // If there's a currently selected Event, set that as default + if (isset($_SESSION[GLM_EVENT_SESSION]['Event']) && $_SESSION[GLM_EVENT_SESSION]['Event'] != false) { + $event = isset($_SESSION[GLM_EVENT_SESSION]['Event']); + $r['fieldData']['event_name']['pick_list'][$event]['default'] = true; + } + + return $r; + + } + + /** + * Insert State Rep + * + * @return array + */ + function insertState() + { + + $r = $this->insertEntry(); + + // If succesful then set current state rep to the one just inserted. + if ($r['status']) { + $_SESSION[GLM_EVENT_SESSION]['State'] = $r['insertedID']; + } + + return $r; + + } + +} + + + + +?> \ No newline at end of file diff --git a/classes/data/dataTeams.php b/classes/data/dataTeams.php new file mode 100644 index 0000000..73e8e51 --- /dev/null +++ b/classes/data/dataTeams.php @@ -0,0 +1,735 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: dataTeams.php,v 1.0 2011/01/25 19:31:47 cscott Exp $ + * @link http://www.gaslightmedia.com/ + */ + +require_once DATA_ABSTRACT; + +/** + * EventManagementDataTeams class + * + * PHP version 5 + * + * @category Data + * @package EventManagement + * @author Chuck Scott + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: dataTeams.php,v 1.0 2011/01/25 19:31:47 cscott Exp $ + * @link http://www.gaslightmedia.com + */ +class EventManagementDataTeams extends DataAbstract +{ + /** + * Field definitions + * + * @var $ini + * @access public + */ + public $table = 'eventmgt.team'; + + /** + * Field definitions + * + * 'type' is type of field as defined by the application + * text Regular text field + * pointer Pointer to an entry in another table + * 'filters' is the filter name for a particular filter ID in PHP filter functions + * See PHP filter_id() + * + * 'use' is when to use the field + * l = List + * g = Get + * n = New + * i = Insert + * e = Edit + * u = Update + * d = Delete + * a = All + * + * @var $ini + * @access public + */ + public $fields = false; + + /** + * Constructor + * + * @param object $d database connection + * + * @return void + * @access public + */ + function __construct($dbh, $config) + { + + parent::__construct($dbh, $config); + + $this->fields = array( + + // Record ID + 'id' => array( + 'field' => 'id', + 'as' => false, + 'type' => 'integer', + 'required' => true, + 'unique' => true, + 'default' => false, + 'use' => 'lg' + ), + + // Event selection + 'event' => array( + 'field' => 'event', + 'as' => false, + 'type' => 'pointer', + 'p_table' => 'eventmgt.event', + 'p_field' => 'name', + 'p_id' => 'id', + 'required' => true, + 'unique' => false, + 'default' => false, + 'use' => 'nid' + ), + + // Event Name display + 'event_view' => array( + 'field' => 'event', + 'as' => 'event_name', + 'type' => 'pointer', + 'p_table' => 'eventmgt.event', + 'p_field' => 'event_code', + 'p_id' => 'id', + 'p_static' => true, + 'required' => true, + 'unique' => false, + 'default' => false, + 'view_only' => true, + 'use' => 'gleu' + ), + + // State (rep) selection + 'state' => array( + 'field' => 'state', + 'as' => false, + 'type' => 'pointer', + 'p_table' => 'eventmgt.state_rep', + 'p_field' => 'code', + 'p_id' => 'id', + 'required' => true, + 'unique' => false, + 'default' => false, + 'use' => 'ni' + ), + + // State (rep) Name display + 'state_view' => array( + 'field' => 'state', + 'as' => 'state_name', + 'type' => 'pointer', + 'p_table' => 'eventmgt.state_rep', + 'p_field' => 'code', + 'p_id' => 'id', + 'p_static' => true, + 'required' => true, + 'unique' => false, + 'default' => false, + 'view_only' => true, + 'use' => 'gleu' + ), + + // Division selection + 'division' => array( + 'field' => 'division', + 'as' => false, + 'type' => 'pointer', + 'p_table' => 'eventmgt.division', + 'p_field' => 'name', + 'p_id' => 'id', + 'required' => true, + 'unique' => false, + 'default' => false, + 'use' => 'nid' + ), + + // Division Name display + 'division_view' => array( + 'field' => 'division', + 'as' => 'division_name', + 'type' => 'pointer', + 'p_table' => 'eventmgt.division', + 'p_field' => 'name', + 'p_id' => 'id', + 'p_static' => true, + 'required' => true, + 'unique' => false, + 'default' => false, + 'view_only' => true, + 'use' => 'gleu' + ), + + // Team name + 'name' => array( + 'field' => 'name', + 'as' => false, + 'type' => 'text', + 'required' => true, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Team Code + 'team_code' => array( + 'field' => 'team_code', + 'as' => false, + 'type' => 'text', + 'required' => true, + 'unique' => true, + 'default' => false, + 'use' => 'a' + ), + + // Participants + 'participants' => array( + 'field' => 'participants', + 'as' => false, + 'type' => 'integer', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Notes + 'notes' => array( + 'field' => 'notes', + 'as' => false, + 'type' => 'text', + 'filter' => FILTER_SANITIZE_MAGIC_QUOTES, + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ) + + ); + } + + /** + * Get Teams list + * + * @return object containing array as sub-objects + */ + function getTeamsList() + { + + // Get event ID from session - if available + $eventID = $_SESSION[GLM_EVENT_SESSION]['Event']; + + // Get member ID from session - if available + $memberID = $_SESSION[GLM_EVENT_SESSION]['Member']; + + // Clear Session Team Selection +// $_SESSION[GLM_EVENT_SESSION]['Team'] = false; + + // Get any specified team listing option - default to event + $option = 'event'; + if (($teamsListOption = filter_input(INPUT_GET, 'TeamsListOption', FILTER_SANITIZE_STRING))) { + $option = $teamsListOption; + } + + // Select type of list + $where = ''; + switch ($option) { + case 'all': + $where = 'TRUE'; + break; + case 'member': + if (!$memberID) { + return false; + } + $where = " + T.id in ( + SELECT team + FROM team_property + WHERE property = $memberID + ) + "; + break; + case 'event': + if (!$eventID) { + return false; + } + $where = "T.event = $eventID"; + break; + default: + echo "Option not set"; + break; + } + + // Get list of Teams + $teamsList = $this->getList($where, 'event_name,state_name,division_name,name'); + + return $teamsList; + } + + /** + * Get Team Detail + * + * @return array + */ + function getTeamDetail() + { + + // Is there a new team code selected? + if (($teamID = filter_input(INPUT_GET, 'TeamID', FILTER_SANITIZE_NUMBER_INT))) { + + // If so then add it to the session + $_SESSION[GLM_EVENT_SESSION]['Team'] = $teamID; + + } elseif (isset($_SESSION[GLM_EVENT_SESSION]['Team'])) { + + // Otherwise, get the team ID from the session + $teamID = $_SESSION[GLM_EVENT_SESSION]['Team']; + + } else { + + // Otherwise, we don't have a team id + return false; + + } + + $teamDetail = $this->getEntry($teamID); + $teamRoster = $this->getTeamRoster($teamID, $teamDetail['participants']); + + $r = array( + 'teamDetail' => $teamDetail, + 'teamRoster' => $teamRoster + ); + + return $r; + + } + + /** + * Get Team Roster + * + * @return array + */ + function getTeamRoster($teamID, $participants) + { + // Try to get team roster + $sql = "SELECT * + FROM team_roster + WHERE team = $teamID + ORDER BY + CASE lname WHEN '' THEN 'ZZZZZZZ' ELSE lname END, + CASE fname WHEN '' THEN 'ZZZZZZZ' ELSE fname END;"; + + $stmt = $this->dbh->prepare($sql); + $stmt->execute(); + $teamRoster = $stmt->fetchAll(PDO::FETCH_ASSOC); + + // Did we get less entries than team members listed? + if (count($teamRoster) < $participants) { + // Add number of additional participant slots to roster + $sql2 = array(); + for ($i=count($teamRoster) ; $i<$participants ; $i++ ) { + $sql2[] = "INSERT INTO eventmgt.team_roster (team) values ($teamID);"; + } + + try { + $this->dbh->beginTransaction(); + foreach ($sql2 as $s) { + $this->dbh->exec($s); + } + $this->dbh->commit(); + } catch (Exception $e) { + $this->dbh->rollBack(); + } + + // Get the team roster again + $stmt = $this->dbh->prepare($sql); + $stmt->execute(); + $teamRoster = $stmt->fetchAll(PDO::FETCH_ASSOC); + } + + // Convert to array that has the roster ids as the index + $tr = array(); + foreach($teamRoster as $r) { + $tr[$r['id']] = $r; + } + + return $tr; + } + + + /** + * Edit Team + * + * @return array + */ + function editTeam() + { + + if (($teamID = filter_input(INPUT_GET, 'TeamID', FILTER_SANITIZE_NUMBER_INT))) { + + // If so then add it to the session + $_SESSION[GLM_EVENT_SESSION]['Team'] = $teamID; + + } elseif (isset($_SESSION[GLM_EVENT_SESSION]['Team'])) { + + // Otherwise, get the team ID from the session + $teamID = $_SESSION[GLM_EVENT_SESSION]['Team']; + + } else { + + // Otherwise, we don't have a team id + return false; + + } + + $teamDetail = $this->editEntry($teamID); + + // echo "
".print_r($teamDetail,1)."
"; + return $teamDetail; + + } + + /** + * Check for other field related issues + * + * This function must be here because it's called from a function + * in dataAbstract. Simply return $r if there's nothing to check. + * + * @return array + */ + function checkOther($r) + { + parent::checkOther($r); +/* + $fd = $r['fieldData']; + + // Is Start date is later than End date + if (strtotime($fd['start_date']) > strtotime($fd['end_date'])) { + $r['fieldFail']['start_date'] = 'Start date is later than end date.'; + $r['status'] = false; + } + + // Is cutoff date is later than end date + if (strtotime($fd['cutoff_date']) > strtotime($fd['end_date'])) { + $r['fieldFail']['cutoff_date'] = 'Cutoff date is later than end date.'; + $r['status'] = false; + } +*/ + return $r; + } + + /** + * Update Team + * + * @return array + */ + function updateTeam() + { + + if (($teamID = filter_input(INPUT_GET, 'TeamID', FILTER_SANITIZE_NUMBER_INT))) { + + // If so then add it to the session + $_SESSION[GLM_EVENT_SESSION]['Team'] = $teamID; + + } elseif (isset($_SESSION[GLM_EVENT_SESSION]['Team'])) { + + // Otherwise, get the team ID from the session + $teamID = $_SESSION[GLM_EVENT_SESSION]['Team']; + + } else { + + // Otherwise, we don't have a team id + return false; + + } + + // Try to update this data + $r = $this->updateEntry($teamID); + + return $r; + + } + + + /** + * Add New Team + * + * @return array + */ + function newTeam() + { + + // If there's a currently selected Event, set that as default + if (isset($_SESSION[GLM_EVENT_SESSION]['Event']) && $_SESSION[GLM_EVENT_SESSION]['Event'] != false) { + $eventID = $_SESSION[GLM_EVENT_SESSION]['Event']; + } else { + // Don't have a selected Event, so can't add a team. + return false; + } + + // Set the p_where values for State Rep and Division picklists to only display ones associated + // with the selected event. + $this->fields['state']['p_where'] = "event = $eventID"; + $this->fields['division']['p_where'] = "event = $eventID"; + + $r = $this->newEntry(); + + // Add selected event id and name for display in new team form + $r['fieldData']['event']['value'] = $eventID; + $r['fieldData']['event']['name'] = $r['fieldData']['event']['pick_list'][$eventID]['name']; + + // Set selected event - Note that the template should actally not be using the event pick_list + // for new team entry unless we get the page to reload with the correct State Rep and Division lists. + $r['fieldData']['event']['pick_list'][$eventID]['default'] = true; + + // If there's a currently selected State, set that as default + if (isset($_SESSION[GLM_EVENT_SESSION]['State']) && $_SESSION[GLM_EVENT_SESSION]['State'] != false) { + $stateID = isset($_SESSION[GLM_EVENT_SESSION]['State']); + $r['fieldData']['state']['pick_list'][$stateID]['default'] = true; + } + + // If there's a currently selected Division, set that as default + if (isset($_SESSION[GLM_EVENT_SESSION]['Division']) && $_SESSION[GLM_EVENT_SESSION]['Division'] != false) { + $divisionID = isset($_SESSION[GLM_EVENT_SESSION]['Division']); + $r['fieldData']['division']['pick_list'][$divisionID]['default'] = true; + } + + // echo "
".print_r($r,1)."
"; + return $r; + + } + + /** + * Insert Team + * + * @return array + */ + function insertTeam() + { + + // If there's a currently selected Event, set that as default + if (isset($_SESSION[GLM_EVENT_SESSION]['Event']) && $_SESSION[GLM_EVENT_SESSION]['Event'] != false) { + $eventID = $_SESSION[GLM_EVENT_SESSION]['Event']; + } else { + // Don't have a selected Event, so can't add a team. + return false; + } + + // Set the p_where values for State Rep and Division picklists to only display ones associated + // with the selected event. + $this->fields['state']['p_where'] = "event = $eventID"; + $this->fields['division']['p_where'] = "event = $eventID"; + + $r = $this->insertEntry(); + + // If succesful then set current team to the one just inserted. + if ($r['status']) { + $_SESSION[GLM_EVENT_SESSION]['Team'] = $r['insertedID']; + } + + // Add selected event name and value for display in new team form + $r['fieldData']['event']['name'] = $r['fieldData']['event']['pick_list'][$eventID]['name']; + $r['fieldData']['event']['value'] = $eventID; + + // Set selected event - Note that the template should actally not be using the event pick_list + // for new team entry unless we get the page to reload with the correct State Rep and Division lists. + $r['fieldData']['event']['pick_list'][$eventID]['default'] = true; + + // If there's a currently selected State, set that as default + if (isset($_SESSION[GLM_EVENT_SESSION]['State']) && $_SESSION[GLM_EVENT_SESSION]['State'] != false) { + $stateID = $_SESSION[GLM_EVENT_SESSION]['State']; + $r['fieldData']['state']['pick_list'][$stateID]['default'] = true; + } + + // If there's a currently selected Division, set that as default + if (isset($_SESSION[GLM_EVENT_SESSION]['Division']) && $_SESSION[GLM_EVENT_SESSION]['Division'] != false) { + $divisionID = $_SESSION[GLM_EVENT_SESSION]['Division']; + $r['fieldData']['division']['pick_list'][$divisionID]['default'] = true; + } + + // echo "
".print_r($r,1)."
"; + return $r; + + } + + /** + * Edit Team Roster + * + * @return array + */ + function editTeamRoster() + { + + if (($teamID = filter_input(INPUT_GET, 'TeamID', FILTER_SANITIZE_NUMBER_INT))) { + + // If so then add it to the session + $_SESSION[GLM_EVENT_SESSION]['Team'] = $teamID; + + } elseif (isset($_SESSION[GLM_EVENT_SESSION]['Team'])) { + + // Otherwise, get the team ID from the session + $teamID = $_SESSION[GLM_EVENT_SESSION]['Team']; + + } else { + + // Otherwise, we don't have a team id + return false; + + } + + // Get team detail for reference + $teamDetail = $this->getEntry($teamID); + + $teamRoster = $this->getTeamRoster($teamID, $teamDetail['participants']); + + $r = array( + 'teamDetail' => $teamDetail, + 'teamRoster' => $teamRoster + ); + + return $r; + + } + + /** + * Update Team Roster + * + * @return array + */ + function updateTeamRoster() + { + + if (($teamID = filter_input(INPUT_GET, 'TeamID', FILTER_SANITIZE_NUMBER_INT))) { + + // If so then add it to the session + $_SESSION[GLM_EVENT_SESSION]['Team'] = $teamID; + + } elseif (isset($_SESSION[GLM_EVENT_SESSION]['Team'])) { + + // Otherwise, get the team ID from the session + $teamID = $_SESSION[GLM_EVENT_SESSION]['Team']; + + } else { + + // Otherwise, we don't have a team id + return false; + + } + + // Get team detail for reference + $teamDetail = $this->getEntry($teamID); + + $teamRoster = $this->getTeamRoster($teamID, $teamDetail['participants']); + + $fieldFail = array(); + $status = true; + + // Filter and sanitize all input arrays + $lname_in = filter_input(INPUT_POST, "lname", FILTER_SANITIZE_STRING, FILTER_FLAG_NO_ENCODE_QUOTES|FILTER_REQUIRE_ARRAY); + $fname_in = filter_input(INPUT_POST, "fname", FILTER_SANITIZE_STRING, FILTER_FLAG_NO_ENCODE_QUOTES|FILTER_REQUIRE_ARRAY); + $pos_in = filter_input(INPUT_POST, "pos", FILTER_SANITIZE_STRING, FILTER_FLAG_NO_ENCODE_QUOTES|FILTER_REQUIRE_ARRAY); + $notes_in = filter_input(INPUT_POST, "notes", FILTER_SANITIZE_STRING, FILTER_FLAG_NO_ENCODE_QUOTES|FILTER_REQUIRE_ARRAY); + + // For each participant + while (list($key, $val) = each($lname_in)) { + + // Last Name + if ($lname_in[$key] || $lname_in[$key] == '') { + $teamRoster[$key]['lname'] = $lname_in[$key]; + $fieldFail[$key]['lname'] = false; + } else { + $fieldFail[$key]['lname'] = 'Provided input was not a valid string.'; + $status = false; + } + + // First Name + if ($fname_in[$key] || $fname_in[$key] == '') { + $teamRoster[$key]['fname'] = $fname_in[$key]; + $fieldFail[$key]['fname'] = false; + } else { + $fieldFail[$key]['fname'] = 'Provided input was not a valid string.'; + $status = false; + } + + // Position + if ($pos_in[$key] || $pos_in[$key] == '') { + $teamRoster[$key]['pos'] = $pos_in[$key]; + $fieldFail[$key]['pos'] = false; + } else { + $fieldFail[$key]['pos'] = 'Provided input was not a valid string.'; + $status = false; + } + + // Notes + if ($notes_in[$key] || $notes_in[$key] == '') { + $teamRoster[$key]['notes'] = $notes_in[$key]; + $fieldFail[$key]['notes'] = false; + } else { + $fieldFail[$key]['notes'] = 'Provided input was not a valid string.'; + $status = false; + } + } + + // If submission is safe, then update the roster table + if ($status) { + $sql = array(); + foreach ($teamRoster as $r) { + $sql[] = "UPDATE team_roster + SET lname = '".addslashes($r['lname'])."', + fname = '".addslashes($r['fname'])."', + pos = '".addslashes($r['pos'])."', + notes = '".addslashes($r['notes'])."' + WHERE id = ".$r['id'].";"; + } + + try { + $this->dbh->beginTransaction(); + foreach ($sql as $s) { + $this->dbh->exec($s); + } + $this->dbh->commit(); + } catch (Exception $e) { + $this->dbh->rollBack(); + } + + // Get team roster again so it's propety ordered + $teamRoster = $this->getTeamRoster($teamID, $teamDetail['participants']); + + } + + $r = array( + 'status' => $status, + 'teamDetail' => $teamDetail, + 'teamRoster' => $teamRoster, + 'fieldFail' => $fieldFail + ); + + return $r; + + } + + + +} + + + + +?> diff --git a/classes/data/dataTicketClaimTracking.php b/classes/data/dataTicketClaimTracking.php new file mode 100644 index 0000000..bbc8ed0 --- /dev/null +++ b/classes/data/dataTicketClaimTracking.php @@ -0,0 +1,216 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: dataTicketClaimTtracking.php,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +require_once DATA_ABSTRACT; + +/** + * EventManagementDataTicketClaimTracking class + * + * PHP version 5 + * + * @category Data + * @package EventManagement + * @author Chuck Scott + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: dataTicketClaimTracking,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ +class EventManagementDataTicketClaimTracking extends DataAbstract +{ + /** + * Tables + * + * @var $ini + * @access public + */ + public $table = 'eventmgt.ticket_claim_tracking'; + + /** + * Field definitions + * + * 'type' is type of field as defined by the application + * text Regular text field + * pointer Pointer to an entry in another table + * 'filters' is the filter name for a particular filter ID in PHP filter functions + * See PHP filter_id() + * + * 'use' is when to use the field + * l = List + * g = Get + * n = New + * i = Insert + * e = Edit + * u = Update + * d = Delete + * a = All + * + * @var $ini + * @access public + */ + public $fields = false; + + /** + * Constructor + * + * @param object $d database connection + * + * @return void + * @access public + */ + function __construct($dbh, $config) + { + + parent::__construct($dbh, $config); + + $this->fields = array( + + // Record ID + 'id' => array( + 'field' => 'id', + 'as' => false, + 'type' => 'integer', + 'required' => true, + 'unique' => true, + 'default' => false, + 'use' => 'lged' + ), + + // Ticket Order + 'ticket_order' => array( + 'field' => 'ticket_order', + 'as' => false, + 'type' => 'integer', + 'required' => true, + 'unique' => false, + 'use' => 'a' + ), + + // Ticket Sold + 'ticket_sold' => array( + 'field' => 'ticket_sold', + 'as' => false, + 'type' => 'integer', + 'required' => true, + 'unique' => false, + 'use' => 'a' + ), + + // Time of scan (timestamp) + 'time_of_action' => array( + 'field' => 'time_of_action', + 'as' => false, + 'type' => 'integer', + 'required' => true, + 'unique' => false, + 'use' => 'a' + ), + + // Action Type + 'action_type' => array( + 'field' => 'action_type', + 'as' => false, + 'type' => 'list', + 'list' => $this->config->member_type->toArray(), + 'required' => false, + 'unique' => false, + 'default' => 1, + 'use' => 'a' + ), + + // Quantity + 'quant' => array( + 'field' => 'quant', + 'as' => false, + 'type' => 'integer', + 'required' => true, + 'unique' => false, + 'use' => 'a' + ), + + // Scan User + 'scan_user' => array( + 'field' => 'scan_user', + 'as' => false, + 'type' => 'integer', + 'required' => true, + 'unique' => false, + 'use' => 'a' + ), + + // Scan Name + 'scan_name' => array( + 'field' => 'scan_name', + 'as' => false, + 'type' => 'text', + 'required' => true, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Attendance Entry + 'attendance' => array( + 'field' => 'attendance', + 'as' => false, + 'type' => 'integer', + 'required' => true, + 'unique' => false, + 'use' => 'a' + ), + + // Attendee Name + 'attendee_name' => array( + 'field' => 'attendee_name', + 'as' => false, + 'type' => 'text', + 'required' => true, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Attendee Notes + 'attendee_notes' => array( + 'field' => 'attendee_notes', + 'as' => false, + 'type' => 'text', + 'required' => true, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ) + + ); + } + + /** + * Check for other field related issues + * + * Simply return $r if there's nothing to check. + * + * @return array + */ + function checkOther($r) + { + parent::checkOther($r); + + return $r; + } + + +} + + + + +?> \ No newline at end of file diff --git a/classes/data/dataTicketInventory.php b/classes/data/dataTicketInventory.php new file mode 100644 index 0000000..65e0a02 --- /dev/null +++ b/classes/data/dataTicketInventory.php @@ -0,0 +1,683 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: dataTicketInventory.php,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +require_once DATA_ABSTRACT; + +/** + * EventManagementDataTickets class + * + * PHP version 5 + * + * @category Data + * @package EventManagement + * @author Chuck Scott + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: dataTickets,v 1.0 2011/01/25 19:31:47 cscott Exp $ + * @link <> + */ +class EventManagementDataTicketInventory extends DataAbstract +{ + /** + * Tables + * + * @var $ini + * @access public + */ + public $table = 'eventmgt.ticket_inventory'; + + /** + * Field definitions + * + * 'type' is type of field as defined by the application + * text Regular text field + * pointer Pointer to an entry in another table + * 'filters' is the filter name for a particular filter ID in PHP filter functions + * See PHP filter_id() + * + * 'use' is when to use the field + * l = List + * g = Get + * n = New + * i = Insert + * e = Edit + * u = Update + * d = Delete + * a = All + * + * @var $ini + * @access public + */ + public $fields = false; + + /** + * Constructor + * + * @param object $d database connection + * + * @return void + * @access public + */ + function __construct($dbh, $config) + { + + parent::__construct($dbh, $config); + + $this->fields = array( + + // Record ID + 'id' => array( + 'field' => 'id', + 'as' => false, + 'type' => 'integer', + 'required' => true, + 'unique' => true, + 'default' => false, + 'use' => 'lged' + ), + + // Ticket ID + 'ticket' => array( + 'field' => 'ticket', + 'as' => false, + 'type' => 'integer', + 'required' => true, + 'unique' => false, + 'default' => $_SESSION[GLM_EVENT_SESSION]['Ticket'], + 'use' => 'nid' + ), + + // Member ID + 'member' => array( + 'field' => 'member', + 'as' => false, + 'type' => 'integer', + 'required' => true, + 'unique' => false, + 'default' => $_SESSION[GLM_EVENT_SESSION]['Member'], + 'use' => 'lged' + ), + + // Member Name + 'member_view' => array( + 'field' => 'member', + 'as' => 'member_name', + 'type' => 'pointer', + 'p_table' => 'eventmgt.member', + 'p_field' => 'name', + 'p_id' => 'id', + 'p_static' => true, + 'required' => true, + 'unique' => false, + 'default' => false, + 'view_only' => true, + 'use' => 'gleu' + ), + + // Ticket Name Display + 'ticket_view' => array( + 'field' => 'ticket', + 'as' => 'ticket_name', + 'type' => 'pointer', + 'p_table' => 'eventmgt.ticket', + 'p_field' => 'name', + 'p_id' => 'id', + 'p_static' => true, + 'required' => true, + 'unique' => false, + 'default' => false, + 'view_only' => true, + 'use' => 'gleu' + ), + + // Ticket ID + 'ticket_id' => array( + 'field' => 'ticket', + 'as' => 'ticket_id', + 'type' => 'integer', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'gl' + ), + + // Date + 'ticket_date' => array( + 'field' => 'ticket_date', + 'as' => false, + 'type' => 'date', + 'format' => 'm/d/Y', + 'minValue' => strtotime('1/1/'.date('Y')), // Earliest is now + 'maxValue' => strtotime('12/31/'.date('Y').' +3 years'), // This year plus 3 + 'required' => true, + 'unique' => false, + 'default' => time(), + 'use' => 'lgnid' + ), + + // Ticket time + 'ticket_time' => array( + 'field' => 'ticket_time', + 'as' => false, + 'type' => 'time', +// 'format' => 'm/d/Y', +// 'minValue' => strtotime('1/1/'.date('Y')), // Earliest is now +// 'maxValue' => strtotime('12/31/'.date('Y').' +3 years'), // This year plus 3 + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'lgnid' + ), + + // Ticket Unlimited Quantity + 'unlimited_quant' => array( + 'field' => 'ticket', + 'as' => 'unlimited_quant', + 'type' => 'pointer', + 'p_table' => 'eventmgt.ticket', + 'p_field' => 'unlimited_quant', + 'p_id' => 'id', + 'p_static' => true, + 'required' => true, + 'unique' => false, + 'default' => false, + 'view_only' => true, + 'use' => 'gleu' + ), + + // Ticket is Cart Sticky + 'cart_sticky' => array( + 'field' => 'ticket', + 'as' => 'cart_sticky', + 'type' => 'pointer', + 'p_table' => 'eventmgt.ticket', + 'p_field' => 'cart_sticky', + 'p_id' => 'id', + 'p_static' => true, + 'required' => true, + 'unique' => false, + 'default' => false, + 'view_only' => true, + 'use' => 'gleu' + ), + + // Quantity Allotted + 'quant' => array( + 'field' => 'quant', + 'as' => false, + 'type' => 'integer', + 'required' => true, + 'unique' => false, + 'default' => 0, + 'use' => 'a' + ), + + // Available + 'available' => array( + 'field' => 'available', + 'as' => false, + 'type' => 'integer', + 'required' => true, + 'unique' => false, + 'default' => 0, + 'use' => 'a' + ), + + // Available + 'sold' => array( + 'field' => 'sold', + 'as' => false, + 'type' => 'integer', + 'required' => true, + 'unique' => false, + 'default' => 0, + 'use' => 'a' + ), + + // On Hold + 'on_hold' => array( + 'field' => 'id', + 'as' => 'on_hold', + 'type' => 'pointer', + 'p_table' => 'eventmgt.inven_hold', + 'p_field' => 'quant', + 'p_id' => 'inventory', + 'p_where' => " + hold_type = ".$this->config->hold_types->ticket." AND + expire_time > '".date('r')."' AND + inventory = T.id", + 'p_sum' => true, + 'p_static' => true, + 'required' => false, + 'unique' => false, + 'default' => false, + 'view_only' => true, + 'use' => 'lg' + ), + + // Active + 'active' => array( + 'field' => 'active', + 'as' => false, + 'type' => 'checkbox', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Ticket sort order + 'ticket_sort' => array( + 'field' => 'ticket', + 'as' => 'ticket_sort', + 'type' => 'pointer', + 'p_table' => 'eventmgt.ticket', + 'p_field' => 'sort', + 'p_id' => 'id', + 'p_static' => true, + 'required' => true, + 'unique' => false, + 'default' => false, + 'view_only' => true, + 'use' => 'gleu' + ), + + // Section ID - retrieval only + 'section' => array( + 'field' => 'ticket', + 'as' => 'section', + 'type' => 'pointer', + 'p_table' => 'eventmgt.ticket', + 'p_field' => 'section', + 'p_id' => 'id', + 'p_static' => true, + 'required' => false, + 'unique' => false, + 'default' => false, + 'view_only' => true, + 'use' => 'g' + ) + + + ); + } + + + /** + * Get Ticket Inventory + * + * @return object containing array as sub-objects + */ + function getTicketInventoryList($ticketID = false, $where = false, $dateKey = false) + { + + // If ticket ID is -1, then don't use ticket ID in search. + if ($ticketID == -1) { + + $ticketID = false; + + // If a ticket ID is specified + } elseif ($ticketID != false) { + + $_SESSION[GLM_EVENT_SESSION]['Ticket'] = $ticketID; + + } elseif (($ticketID = filter_input(INPUT_GET, 'TicketID', FILTER_SANITIZE_NUMBER_INT))) { + + // If there's a new ticket code submitted then add it to the session + $_SESSION[GLM_EVENT_SESSION]['Ticket'] = $ticketID; + + } elseif (isset($_SESSION[GLM_EVENT_SESSION]['Ticket'])) { + + // Otherwise, get the ticket ID from the session + $ticketID = $_SESSION[GLM_EVENT_SESSION]['Ticket']; + + } else { + + // Otherwise, we don't have a ticket id - This should not be a problem + + } + + // If we have a ticket id, use that for inventory selection + $ticketWhere = 'true '; + if ($ticketID) { + $ticketWhere = "T.ticket = $ticketID "; + } + + // Check for Where clause supplied + if ($where) { + $where = "AND $where "; + } + + // Get list of Inventory + $invData = $this->getList($ticketWhere.$where, 'ticket_date'); + + // Convert to array with timestamp or ID as index + $inventoryData = array(); + if ($invData != false) { + foreach ($invData as $i) { + + // If the inventory item has a date and we're getting inventory for a specific ticketID + if (trim($i['ticket_date']['date']) != '' && $ticketID) { + + // Use ticket timestamp for index + $inventoryData[$i['ticket_date']['timestamp']] = $i; + + // Otherwise just use inventory ID (it's a non-date specific ticket) + } else { + $inventoryData[$i['id']] = $i; + } + } + } + + return $inventoryData; + } + + /** + * Get Ticket Inventory Calendar Data + * + * @return object containing array as sub-objects + */ + function getTicketInventoryCalendarData() + { + + // Is there a new Ticket code selected? + if (($ticketID = filter_input(INPUT_GET, 'TicketID', FILTER_SANITIZE_NUMBER_INT))) { + + // If so then add it to the session + $_SESSION[GLM_EVENT_SESSION]['Ticket'] = $ticketID; + + } elseif (isset($_SESSION[GLM_EVENT_SESSION]['Ticket'])) { + + // Otherwise, get the ticket ID from the session + $ticketID = $_SESSION[GLM_EVENT_SESSION]['Ticket']; + + } else { + + // Otherwise, we don't have a ticket id + return false; + + } + + // Get peformance ID from ticket + require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/tickets.php'; + $Tickets = new EventManagementAdminTickets($this->dbh, $this->config); + $ticketDetail = $Tickets->getTicketDetail(); + $_SESSION[GLM_EVENT_SESSION]['Performance'] = $ticketDetail['performance_id']; + + // Get performance data to get start and end date for the performance + require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/performances.php'; + $Performances = new EventManagementAdminPerformances($this->dbh, $this->config); + $performanceDetail = $Performances->getPerformanceDetail(); + + $invData = $this->getTicketInventoryList(false, "ticket_date is not null"); + + // If this ticket is date specific by inventory + // If not, there's only one inventory item, so we don't build a calendar + if ($ticketDetail['date_specific']['value']) { + + $start = $ticketDetail['start_date']['timestamp']; + $end = $ticketDetail['end_date']['timestamp']; + + /* + * Build output organized as calendar months + */ + + // Create calendars for the months covered by the performance + $calData = array(); + $startMonth = strtotime(date('m/1/Y', $start)); + $endMonth = strtotime(date('m/1/Y', $end)); + + // For each month of the performance + $newInventoryAdded = false; + for ($month = $startMonth; $month <= $endMonth; $month = strtotime(date('m/d/Y',$month).' +1 Month')) { + + $offset = date('w', $month); // Number of days start of month is offset from Sunday + $monthDays = date('t', $month); // Number of days in the month + + $calData[$month] = array( + 'month' => date('F', $month), + 'year' => date('Y', $month) + ); + + // For each week of the month + for ($week = 1; $week <= 6; $week++) { + + $weekUsed = false; + + // For each day of the week + for ($day = 1; $day <= 7; $day++) { + + $cellNumb = ($week-1) * 7 + $day; // Calendar cell number - 6 week rows = 42 cells + + // If this is a real date cell, then add the date info and any inventory data + $dateData = array('isDate' => false); + if ($cellNumb > $offset && ($cellNumb-$offset) <= $monthDays) { + + $date = $cellNumb - $offset; // Day of the month + $dateTime = strtotime(date('m/d/Y', $month)." + ".($date-1)." Days"); // Timestamp for this date + + $dow = date('w', $dateTime); + + // Create base cell data + $dateData = array( + 'isDate' => true, + 'time' => $dateTime, + 'dom' => date('j', $dateTime), + 'date' => date('m/d/Y',$dateTime), + 'selectable' => ($dateTime >= $start && $dateTime <= $end && $ticketDetail['days_of_week']['bitmap'][$dow]['default']), + 'selected' => false + ); + + + if ($ticketDetail['days_of_week']['bitmap'][$dow]['default']) { + + + $weekUsed = true; + + // Check if there's no inventory for this date and there should be + if (($dateTime >= $start && $dateTime <= $end) && !isset($invData[$dateTime])) { + + // Create a new inventory item + $quant = $ticketDetail['quant']; + $time = trim($ticketDetail['ticket_time']['time']); + $dateText = date('m/d/Y', $dateTime); + + $sql = " + INSERT INTO eventmgt.ticket_inventory + (ticket, quant, available, ticket_date, ticket_time, sold, active) + VALUES + ($ticketID, $quant, $quant, '$dateText', '$time', 0, true) + ;"; + $this->dbh->exec($sql); + $newInventoryAdded = true; + + } + + } + + // If there's data for this date, add that to the cell data + if (isset($invData[$dateTime])) { + + $dateData = array_merge($dateData, $invData[$dateTime]); + unset($dateData['ticket_date']); // Don't need this here + unset($dateData['ticket_name']); // Don't need this here + + } + + } + $calData[$month]['weeks'][$week]['weekUsed'] = $weekUsed; + $calData[$month]['weeks'][$week]['days'][$cellNumb] = $dateData; + + } + } + } + + // If new inventory was added, go back and reload all the data again + if ($newInventoryAdded) { + $calData = $this->getTicketInventoryCalendarData(); + } + + } else { + + // If not date specific, we'll just pass on the current inventory data item + $calData = $invData; + } + + return $calData; + } + + + /** + * Get Ticket Inventory Detail + * + * @return array + */ + function getTicketInventoryDetail($ticketInventoryID = false, $extended = false) + { + + // If an ID was supplied + if ($ticketInventoryID > 0) { + + $_SESSION[GLM_EVENT_SESSION]['TicketInventory'] = $ticketInventoryID; + + // Otherwise is there a new Ticket code submitted? + } elseif (($ticketInventoryID = filter_input(INPUT_GET, 'TicketInventoryID', FILTER_SANITIZE_NUMBER_INT))) { + + // If so then add it to the session + $_SESSION[GLM_EVENT_SESSION]['TicketInventory'] = $ticketInventoryID; + + } elseif (isset($_SESSION[GLM_EVENT_SESSION]['TicketInventory'])) { + + // Otherwise, get the ticket ID from the session + $ticketInventoryID = $_SESSION[GLM_EVENT_SESSION]['TicketInventory']; + + } else { + + // Otherwise, we don't have a ticket id + return false; + + } + + $detail = $this->getEntry($ticketInventoryID); + + // If $extended, then get detail on Section and Entrance + if ($extended) { + + require_once EVENT_MANAGEMENT_APP_BASE.'classes/data/dataSections.php'; + $Sections = new EventManagementDataSections($this->dbh, $this->config); + $Sections->optionIncludeSelectListData = false; + $sectionDetail = $Sections->getSectionDetail($detail['section']); + + } + + return $detail; + + } + + + /** + * Edit Ticket Inventory + * + * @return array + */ + function editTicketInventory() + { + + if (($ticketInventoryID = filter_input(INPUT_GET, 'TicketInventoryID', FILTER_SANITIZE_NUMBER_INT))) { + + // If so then add it to the session + $_SESSION[GLM_EVENT_SESSION]['TicketInventory'] = $ticketInventoryID; + + } elseif (isset($_SESSION[GLM_EVENT_SESSION]['TicketInventory'])) { + + // Otherwise, get the ticket ID from the session + $ticketInventoryID = $_SESSION[GLM_EVENT_SESSION]['TicketInventory']; + + } else { + + // Otherwise, we don't have a ticket id + return false; + + } + + $ticketDetail = $this->editEntry($ticketInventoryID); + + return $ticketInventoryDetail; + + } + + /** + * Check for other field related issues + * + * This function must be here because it's called from a function + * in dataAbstract. Simply return $r if there's nothing to check. + * + * @return array + */ + function checkOther($r) + { + parent::checkOther($r); + return $r; + } + + /** + * Update Ticket + * + * @return array + */ + function updateTicketInventory() + { + + // Removing "active" field to keep inventory update from messing with active flag + $saveActive = $this->fields['active']; + unset($this->fields['active']); + + if (($ticketInventoryID = filter_input(INPUT_GET, 'TicketInventoryID', FILTER_SANITIZE_NUMBER_INT))) { + + // If so then add it to the session + $_SESSION[GLM_EVENT_SESSION]['TicketInventory'] = $ticketInventoryID; + + } elseif (isset($_SESSION[GLM_EVENT_SESSION]['TicketInventory'])) { + + // Otherwise, get the ticket ID from the session + $ticketInventoryID = $_SESSION[GLM_EVENT_SESSION]['TicketInventory']; + + } else { + + // Otherwise, we don't have a ticket id + return false; + + } + + // Check if there's existing inventory data + + + // Try to update this data + $r = $this->updateEntry($ticketInventoryID); + + // Restore "active" field + $this->fields['active'] = $saveActive; + + return $r; + + } + + + + +} + + + + +?> diff --git a/classes/data/dataTicketPackages.php b/classes/data/dataTicketPackages.php new file mode 100644 index 0000000..dfb3f44 --- /dev/null +++ b/classes/data/dataTicketPackages.php @@ -0,0 +1,347 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: dataTicketPackage.php,v 1.0 2011/01/25 19:31:47 cscott Exp $ + * @link http://www.gaslightmedia.com + */ + +require_once DATA_ABSTRACT; + +/** + * EventManagementDataTicketPackage class + * + * PHP version 5 + * + * @category Data + * @package EventManagement + * @author Chuck Scott + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: dataTickets,v 1.0 2011/01/25 19:31:47 cscott Exp $ + * @link <> + */ +class EventManagementDataTicketPackages extends DataAbstract +{ + /** + * Tables + * + * @var $ini + * @access public + */ + public $table = 'eventmgt.ticket_package'; + + /** + * Field definitions + * + * 'type' is type of field as defined by the application + * text Regular text field + * pointer Pointer to an entry in another table + * 'filters' is the filter name for a particular filter ID in PHP filter functions + * See PHP filter_id() + * + * 'use' is when to use the field + * l = List + * g = Get + * n = New + * i = Insert + * e = Edit + * u = Update + * d = Delete + * a = All + * + * @var $ini + * @access public + */ + public $fields = false; + + /** + * Constructor + * + * @param object $d database connection + * + * @return void + * @access public + */ + function __construct($dbh, $config) + { + + parent::__construct($dbh, $config); + + $this->fields = array( + + // Record ID + 'id' => array( + 'field' => 'id', + 'as' => false, + 'type' => 'integer', + 'required' => true, + 'unique' => true, + 'default' => false, + 'use' => 'lged' + ), + + // Pointer to ticket that is acting as a package container + 'ticket_package' => array( + 'field' => 'package', + 'as' => false, + 'type' => 'integer', + 'required' => true, + 'unique' => false, + 'use' => 'a' + ), + + // Pointer to ticket that is contained in the package + 'ticket' => array( + 'field' => 'ticket', + 'as' => false, + 'type' => 'integer', + 'required' => true, + 'unique' => false, + 'use' => 'a' + ), + + // Quantity + 'quant' => array( + 'field' => 'quant', + 'as' => false, + 'type' => 'integer', + 'required' => true, + 'unique' => false, + 'use' => 'a' + ), + + // Separate Voucher Flag + 'separate_voucher' => array( + 'field' => 'separate_voucher', + 'as' => false, + 'type' => 'checkbox', + 'required' => false, + 'unique' => false, + 'use' => 'a' + ), + + // Package Name + 'package_name' => array( + 'field' => 'package', + 'as' => 'package_name', + 'type' => 'pointer', + 'p_table' => 'eventmgt.ticket', + 'p_field' => 'title', + 'p_id' => 'id', + 'p_static' => true, + 'required' => false, + 'unique' => false, + 'default' => false, + 'view_only' => true, + 'use' => 'gleu' + ), + + // Member Name + 'member_name' => array( + 'field' => 'member', + 'as' => 'member_name', + 'type' => 'pointer', + 'p_table' => 'eventmgt.member', + 'p_field' => 'name', + 'p_id' => 'id', + 'p_static' => true, + 'required' => false, + 'unique' => false, + 'default' => false, + 'view_only' => true, + 'use' => 'gleu' + ), + + // Performance Name + 'performance_name' => array( + 'field' => 'performance', + 'as' => 'performance_name', + 'type' => 'pointer', + 'p_table' => 'eventmgt.performance', + 'p_field' => 'name', + 'p_id' => 'id', + 'p_static' => true, + 'required' => false, + 'unique' => false, + 'default' => false, + 'view_only' => true, + 'use' => 'gleu' + ), + + // Ticket Title + 'ticket_title' => array( + 'field' => 'ticket', + 'as' => 'title', + 'type' => 'pointer', + 'p_table' => 'eventmgt.ticket', + 'p_field' => 'title', + 'p_id' => 'id', + 'p_static' => true, + 'required' => false, + 'unique' => false, + 'default' => false, + 'view_only' => true, + 'use' => 'gleu' + ), + + // Ticket Active + 'active' => array( + 'field' => 'ticket', + 'as' => 'active', + 'type' => 'pointer', + 'p_table' => 'eventmgt.ticket', + 'p_field' => 'active', + 'p_id' => 'id', + 'p_static' => true, + 'required' => false, + 'unique' => false, + 'default' => false, + 'view_only' => true, + 'use' => 'gleu' + ), + + // Display Order (sort) + 'sort' => array( + 'field' => 'sort', + 'as' => false, + 'type' => 'integer', + 'required' => false, + 'unique' => false, + 'default' => 999, + 'use' => 'a' + ) + + + ); + } + + /** + * Get Package Tickets list + * + * + * @return object containing array as sub-objects + */ + public function getPackageList($where) + { + + // Get the package contents + $packageData = $this->getList($where); + if (count($packageData) == 0) { + return false; + } + + // Build output array with package ticket as key + $outData = array(); + if ($packageData && count($packageData) > 0) { + foreach ($packageData as $p) { + $outData[$p['ticket']] = $p; + } + } + return $outData; + + } + + /** + * Update package tickets list + * + * Expects request input "selected_ticket_quant[id]" array. + */ + public function updatePackageTicketsList($packageID = false) + { + // Check for good package ID + $pID = $packageID - 0; + if ($pID <= 0) { + return false; + } + + // Try to retrieve package to make sure it exists and is a package + $sql = " + SELECT id + FROM eventmgt.ticket + WHERE id = $pID + AND ticket_type = 20 + ;"; + $stmt = $this->dbh->prepare($sql); + $stmt->execute(); + $packageData = $stmt->fetchAll(PDO::FETCH_ASSOC); + if (count($packageData) != 1) { + return false; + } + + // Query to delete all for selected package + $sql = " + BEGIN; + DELETE FROM eventmgt.ticket_package + WHERE package = $packageID; + "; + + // Now add in any tickets in request + require_once EVENT_MANAGEMENT_APP_BASE.'classes/data/dataTickets.php'; + $Tickets = new EventManagementDataTickets($this->dbh, $this->config); + $newTickets = $_REQUEST['selected_ticket_quant']; + + if ($newTickets) { + + foreach ($newTickets as $k=>$v) { + + // Get ticket data + $ticketData = $Tickets->getEntry($k); + if (is_array($ticketData)) { + + // Check for separate vouchers + $separateVoucher = 'false'; + if (isset($_REQUEST['selected_ticket_separatevoucher'][$k])) { + $separateVoucher = 'true'; + } + + $sql .= " + INSERT INTO eventmgt.ticket_package + (package, ticket, member, performance, quant, sort, separate_voucher) + VALUES ($packageID, $k, ".$ticketData['member'].", ".$ticketData['performance_id'].", $v, 99, $separateVoucher) + ;"; + } + + } + } + $sql .= "COMMIT;"; + $this->dbh->exec($sql); + + return $this->getPackageList("package = $packageID"); + + } + + /** + * Clear package tickets list + */ + public function clearPackageTicketsList($packageID = false) + { + + // Check for good package ID + $pID = $packageID - 0; + if ($pID <= 0) { + return false; + } + + $sql = " + DELETE FROM eventmgt.ticket_package + WHERE package = $packageID; + "; + $this->dbh->exec($sql); + + return; + + } + +} + + + + +?> \ No newline at end of file diff --git a/classes/data/dataTickets.php b/classes/data/dataTickets.php new file mode 100644 index 0000000..1a5a3b8 --- /dev/null +++ b/classes/data/dataTickets.php @@ -0,0 +1,923 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: dataTickets.php,v 1.0 2011/01/25 19:31:47 cscott Exp $ + * @link http://www.gaslightmedia.com + */ + +require_once DATA_ABSTRACT; + +/** + * EventManagementDataTickets class + * + * PHP version 5 + * + * @category Data + * @package EventManagement + * @author Chuck Scott + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: dataTickets,v 1.0 2011/01/25 19:31:47 cscott Exp $ + * @link <> + */ +class EventManagementDataTickets extends DataAbstract +{ + /** + * Tables + * + * @var $ini + * @access public + */ + public $table = 'eventmgt.ticket'; + + /** + * Field definitions + * + * 'type' is type of field as defined by the application + * text Regular text field + * pointer Pointer to an entry in another table + * 'filters' is the filter name for a particular filter ID in PHP filter functions + * See PHP filter_id() + * + * 'use' is when to use the field + * l = List + * g = Get + * n = New + * i = Insert + * e = Edit + * u = Update + * d = Delete + * a = All + * + * @var $ini + * @access public + */ + public $fields = false; + + /** + * Constructor + * + * @param object $d database connection + * + * @return void + * @access public + */ + function __construct($dbh, $config) + { + + parent::__construct($dbh, $config); + + $this->fields = array( + + // Record ID + 'id' => array( + 'field' => 'id', + 'as' => false, + 'type' => 'integer', + 'required' => true, + 'unique' => true, + 'default' => false, + 'use' => 'lged' + ), + + // Admin Only Flag + 'admin_only' => array( + 'field' => 'admin_only', + 'as' => false, + 'type' => 'checkbox', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Ticket Type + 'ticket_type' => array( + 'field' => 'ticket_type', + 'as' => false, + 'type' => 'list', + 'list' => $this->config->ticket_type->toArray(), + 'required' => false, + 'unique' => false, + 'default' => 10, + 'use' => 'a' + ), + + // Member ID for adding tickets + 'member' => array( + 'field' => 'member', + 'as' => false, + 'type' => 'integer', + 'required' => true, + 'unique' => false, + 'default' => $_SESSION[GLM_EVENT_SESSION]['Member'], + 'use' => 'a' + ), + + // Member Name display + 'member_view' => array( + 'field' => 'member', + 'as' => 'member_name', + 'type' => 'pointer', + 'p_table' => 'eventmgt.member', + 'p_field' => 'name', + 'p_id' => 'id', + 'p_static' => true, + 'required' => true, + 'unique' => false, + 'default' => false, + 'view_only' => true, + 'use' => 'gleu' + ), + + // Ticket Name (internal use) + 'name' => array( + 'field' => 'name', + 'as' => false, + 'type' => 'text', + 'required' => true, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Active + 'active' => array( + 'field' => 'active', + 'as' => false, + 'type' => 'checkbox', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Ticket Title (for display to users) + 'title' => array( + 'field' => 'title', + 'as' => false, + 'type' => 'text', + 'required' => true, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Performance + 'performance' => array( + 'field' => 'performance', + 'as' => false, + 'type' => 'pointer', + 'p_table' => 'eventmgt.performance', + 'p_field' => 'name', + 'p_id' => 'id', + 'p_where' => 'member = '.$_SESSION[GLM_EVENT_SESSION]['Member'], + 'required' => true, + 'unique' => false, + 'default' => $_SESSION[GLM_EVENT_SESSION]['Performance'], + 'use' => 'nideu' + ), + + // Performance_view + 'performance_view' => array( + 'field' => 'performance', + 'as' => false, + 'type' => 'pointer', + 'p_table' => 'eventmgt.performance', + 'p_field' => 'name', + 'p_id' => 'id', + 'required' => true, + 'unique' => false, + 'default' => false, + 'use' => 'gl' + ), + + // Performance ID + 'performance_id' => array( + 'field' => 'performance', + 'as' => 'performance_id', + 'type' => 'integer', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'gl' + ), + + // Section + 'section' => array( + 'field' => 'section', + 'as' => false, + 'type' => 'pointer', + 'p_table' => 'eventmgt.section', + 'p_field' => 'name', + 'p_id' => 'id', + 'p_where' => 'member = '.$_SESSION[GLM_EVENT_SESSION]['Member'], + 'required' => true, + 'unique' => false, + 'default' => false, + 'use' => 'nideu' + ), + + // Section View + 'section_view' => array( + 'field' => 'section', + 'as' => false, + 'type' => 'pointer', + 'p_table' => 'eventmgt.section', + 'p_field' => 'name', + 'p_id' => 'id', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'gl' + ), + + // Section ID + 'section_id' => array( + 'field' => 'section', + 'as' => 'section_id', + 'type' => 'integer', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'gl' + ), + + // Available for Sale Start Date + 'for_sale_start_date' => array( + 'field' => 'for_sale_start_date', + 'as' => false, + 'type' => 'date', + 'format' => 'm/d/Y', + 'minValue' => strtotime('1/1/'.date('Y').' -1 year'), // Earliest is now less 1 year + 'maxValue' => strtotime('12/31/'.date('Y').' +3 years'), // This year plus 3 + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Available for Sale End Date + 'for_sale_end_date' => array( + 'field' => 'for_sale_end_date', + 'as' => false, + 'type' => 'date', + 'format' => 'm/d/Y', + 'minValue' => strtotime('1/1/'.date('Y').' -1 year'), // Earliest is now less 1 year + 'maxValue' => strtotime('12/31/'.date('Y').' +3 years'), // This year plus 3 + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Date Specific - use single or multiple inventory + 'date_specific' => array( + 'field' => 'date_specific', + 'as' => false, + 'type' => 'checkbox', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Days of the week to create default inventory - multi-pick + 'days_of_week' => array( + 'field' => 'days_of_week', + 'as' => false, + 'type' => 'bitmap', + 'bitmap' => $this->config->days->toArray(), + 'required' => false, + 'unique' => false, + 'default' => 0, // Note that this is a bitmap of card indexes + 'use' => 'a' + ), + + // Start Date + 'start_date' => array( + 'field' => 'start_date', + 'as' => false, + 'type' => 'date', + 'format' => 'm/d/Y', + 'minValue' => strtotime('1/1/'.date('Y')), // Earliest is now + 'maxValue' => strtotime('12/31/'.date('Y').' +3 years'), // This year plus 3 + 'required' => true, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // End Date + 'end_date' => array( + 'field' => 'end_date', + 'as' => false, + 'type' => 'date', + 'format' => 'm/d/Y', + 'minValue' => strtotime('1/1/'.date('Y')), // Earliest is now + 'maxValue' => strtotime('12/31/'.date('Y').' +3 years'), // This year plus 3 + 'required' => true, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Time Specific + 'time_specific' => array( + 'field' => 'time_specific', + 'as' => false, + 'type' => 'checkbox', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Ticket Time + 'ticket_time' => array( + 'field' => 'ticket_time', + 'as' => false, + 'type' => 'time', + 'required' => true, + 'unique' => false, + 'default' => '12:00 PM', + 'use' => 'a' + ), + + // Ticket Timestamp + 'ticket_timestamp' => array( + 'field' => 'ticket_time', + 'as' => 'ticket_timestamp', + 'type' => 'integer', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'gl' + ), + + // Unlimited Use + 'unlimited_use' => array( + 'field' => 'unlimited_use', + 'as' => false, + 'type' => 'checkbox', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Number of uses + 'uses' => array( + 'field' => 'uses', + 'as' => false, + 'type' => 'integer', + 'required' => false, + 'unique' => false, + 'default' => 1, + 'use' => 'a' + ), + + // Unlimited Quantity + 'unlimited_quant' => array( + 'field' => 'unlimited_quant', + 'as' => false, + 'type' => 'checkbox', + 'required' => false, + 'unique' => false, + 'default' => true, + 'use' => 'a' + ), + + // Quantity - Number of these tickets in the section + 'quant' => array( + 'field' => 'quant', + 'as' => false, + 'type' => 'integer', + 'required' => true, + 'unique' => false, + 'default' => 1, + 'use' => 'lgnieud' + ), + + // Price + 'price' => array( + 'field' => 'price', + 'as' => false, + 'type' => 'money', + 'required' => true, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Consignment Type + 'consignment_type' => array( + 'field' => 'consignment_type', + 'as' => false, + 'type' => 'list', + 'list' => $this->config->ticket_consignment_type->toArray(), + 'required' => false, + 'unique' => false, + 'default' => 1, + 'use' => 'a' + ), + + // Cart Sticky (Always displayed on cart - even with no quant) + 'cart_sticky' => array( + 'field' => 'cart_sticky', + 'as' => false, + 'type' => 'checkbox', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a', + 'callback' => function ($r) { + $r['status'] = false; + return $r; + } + ), + + // Show ticket on Start Page + 'show_on_start' => array( + 'field' => 'show_on_start', + 'as' => false, + 'type' => 'checkbox', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Add-on Selection Required + 'addon_required' => array( + 'field' => 'addon_required', + 'as' => false, + 'type' => 'checkbox', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Price + 'price_numb' => array( + 'field' => 'price', + 'as' => 'price_numb', + 'type' => 'float', + 'required' => true, + 'unique' => false, + 'default' => false, + 'use' => 'lg' + ), + + // Description + 'descr' => array( + 'field' => 'descr', + 'as' => false, + 'type' => 'text', + 'filter' => FILTER_SANITIZE_MAGIC_QUOTES, + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Image + 'image' => array( + 'field' => 'image', + 'as' => false, + 'type' => 'image', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Voucher Text + 'voucher_text' => array( + 'field' => 'voucher_text', + 'as' => false, + 'type' => 'text', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Voucher LeftEnd Text - overrides other text for that area if set + 'voucher_leftend_text' => array( + 'field' => 'voucher_leftend_text', + 'as' => false, + 'type' => 'text', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Voucher Type + 'voucher_type' => array( + 'field' => 'voucher_type', + 'as' => false, + 'type' => 'list', + 'list' => $this->config->ticket_voucher_type->toArray(), + 'required' => true, + 'unique' => false, + 'default' => 1, + 'use' => 'a' + ), + + // Display Order (sort) + 'sort' => array( + 'field' => 'sort', + 'as' => false, + 'type' => 'integer', + 'required' => false, + 'unique' => false, + 'default' => 999, + 'use' => 'a' + ) + + + ); + } + + /** + * Check for other field related issues + * + * Simply return $r if there's nothing to check. + * + * @return array + */ + function checkOther($r) + { + parent::checkOther($r); + + // Check that Sticky is not used with date-specific inventory + if ($r['fieldData']['date_specific']['value'] && $r['fieldData']['cart_sticky']['value']) { + $r['status'] = false; + $r['fieldFail']['cart_sticky'] = 'Sticky may not be used when "Specified Dates" is checked.'; + $r['fieldFail']['date_specific'] = 'Specified dates may not be used when "Sticky" is checked.'; + } + + return $r; + } + + /** + * Get Tickets list + * + * @param integer $memberID Specifies tickets for a Member ID + * @param integer $performanceID Specifies tickets for a Performance ID + * @param integer $sectionID Specifies tickets for a Section ID + * @param string $listType Type of list to generate + * "norm" Standard list output with detail + * 'all' List all and ignore member, performance, section ID + * 'packageSelect' List package selection with only ID, Name, Member, Performance, Section, active + * Optional specify $notTicketID to not include the current ticket by ID + * Sorts by Member, Performance, Section, then Ticket + * + * @return object containing array as sub-objects + */ + function getTicketsList($memberID = false, $performanceID = false, $sectionID = false, $listType = false, $activeOnly = false, $where = false, $includeAdminOnly = false, $notTicketID = false, $packages = true) + { + // Get member ID - But don't use it if performance or section IDs are supplied. + if ($memberID == false && !$performanceID && !$sectionID) { + $memberID = $_SESSION[GLM_EVENT_SESSION]['Member']; + } + + // Get performance ID + if ($performanceID == false) { + $performanceID = $_SESSION[GLM_EVENT_SESSION]['Performance']; + } + + // Get section ID + if ($sectionID == false) { + $sectionID = $_SESSION[GLM_EVENT_SESSION]['Section']; + } + + // Get URI search type + if (!$listType && isset($_REQUEST['listType'])) { + $listType = $_REQUEST['listType']; + } + + // Build query Where clause + if ($where == false) { + $where = 'true'; + } + + // Check for active only request + if ($activeOnly) { + $where .= ' AND T.active'; + } + + // Check if adminUser + if (!$includeAdminOnly) { + $where .= ' AND NOT T.admin_only'; + } + + // Check if packages aren't enabled + if (!$packages) { + $where .= ' AND T.ticket_type != 20'; + } + + $fieldsSave = false; + + switch ($listType) { + + case 'packageSelect': + + // Save current field list + $fieldsSave = $this->fields; + $this->fields = array( + 'id' => $this->fields['id'], + 'name' => $this->fields['name'], + 'title' => $this->fields['title'], + 'member_name' => $this->fields['member_view'], + 'performance_view' => $this->fields['performance_view'], + 'section_view' => $this->fields['section_view'], + 'active' => $this->fields['active'] + ); + + $where = ' + T.ticket_type != 20 + AND T.addon_required = false + '.($notTicketID ? ' AND T.id != '.$notTicketID : '').' + '; + if ($memberID) { + $where .= " AND ( T.member = $memberID OR T.consignment_type > 1)"; + } else { + $where .= 'AND T.consignment_type > 1'; + } + + $sort = ''; + + break; + + case 'norm': + default: + if ($memberID) { + $where .= " AND T.member = $memberID"; + } + if ($performanceID) { + $where .= " AND T.performance = $performanceID"; + } + if ($sectionID) { + $where .= " AND T.section = $sectionID"; + } + $sort = 'sort, name'; + break; + + case 'all': + $sort = 'sort, name'; + break; + + } + + // Get list of Tickets + $ticketsList = $this->getList($where, 'sort, name'); + + if ($fieldsSave != false) { + $this->fields = $fieldsSave; + } + + // If type packageSelect + if ($listType == 'packageSelect') { + + // Sort by member, performance, section, ticket names. + function packageSelectSort($a, $b) { + if ($a['member_name'] == $b['member_name'] && $a['performance'] == $b['performance'] && $a['section'] == $b['section'] && $a['title'] == $b['title'] ) { + return 0; + } + if ($a['member_name'] < $b['member_name']) { return -1; } + if ($a['member_name'] > $b['member_name']) { return 1; } + if ($a['performance'] < $b['performance']) { return -1; } + if ($a['performance'] > $b['performance']) { return 1; } + if ($a['section'] < $b['section']) {return -1;} + if ($a['section'] > $b['section']) {return 1;} + if ($a['title'] < $b['title']) {return -1;} + return 1; + } + uasort($ticketsList, 'packageSelectSort'); + + // Save names, Remove subsequent member, performance, section until change + $memberName = ''; + $performanceName = ''; + $sectionName = ''; + while (list($k, $v) = each($ticketsList)) { + + // Also provide active as Yes/No + $ticketsList[$k]['active_name'] = ($v['active'] ? 'Yes' : 'No'); + + // Save names for adding to selected list + $ticketsList[$k]['member_save'] = $v['member_name']; + $ticketsList[$k]['performance_save'] = $v['performance']; + $ticketsList[$k]['section_save'] = $v['section']; + + // Remove duplicate names for ordered picklist + if ($v['member_name'] != $memberName) { + $memberName = $v['member_name']; + $performanceName = ''; + $sectionName = ''; + } else { + $ticketsList[$k]['member_name'] = ''; + } + if ($v['performance'] != $performanceName) { + $performanceName = $v['performance']; + $sectionName = ''; + } else { + $ticketsList[$k]['performance'] = ''; + } + if ($v['section'] != $sectionName) { + $sectionName = $v['section']; + } else { + $ticketsList[$k]['performance'] = ''; + } + + } + + } + + return $ticketsList; + } + + /** + * Get Ticket Detail + * + * @return array + */ + function getTicketDetail($ticketID = false) + { + + // If a ticket has been specified + if ($ticketID != false) { + + $_SESSION[GLM_EVENT_SESSION]['Ticket'] = $ticketID; + + // Otherwise if there's a ticket ID in the request + } elseif (($ticketID = filter_input(INPUT_GET, 'TicketID', FILTER_SANITIZE_NUMBER_INT))) { + + // There's a + $_SESSION[GLM_EVENT_SESSION]['Ticket'] = $ticketID; + + } elseif (isset($_SESSION[GLM_EVENT_SESSION]['Ticket'])) { + + // Otherwise, get the ticket ID from the session + $ticketID = $_SESSION[GLM_EVENT_SESSION]['Ticket']; + + } else { + + // Otherwise, we don't have a ticket id + return false; + + } + + $ticketDetail = $this->getEntry($ticketID); + + return $ticketDetail; + + } + + /** + * Edit Ticket + * + * @return array + */ + function editTicket() + { + + if (($ticketID = filter_input(INPUT_GET, 'TicketID', FILTER_SANITIZE_NUMBER_INT))) { + + // If so then add it to the session + $_SESSION[GLM_EVENT_SESSION]['Ticket'] = $ticketID; + + } elseif (isset($_SESSION[GLM_EVENT_SESSION]['Ticket'])) { + + // Otherwise, get the ticket ID from the session + $ticketID = $_SESSION[GLM_EVENT_SESSION]['Ticket']; + + } else { + + // Otherwise, we don't have a ticket id + return false; + + } + + $ticketDetail = $this->editEntry($ticketID); + + return $ticketDetail; + + } + + /** + * Update Ticket + * + * @return array + */ + function updateTicket() + { + + if (($ticketID = filter_input(INPUT_GET, 'TicketID', FILTER_SANITIZE_NUMBER_INT))) { + + // If so then add it to the session + $_SESSION[GLM_EVENT_SESSION]['Ticket'] = $ticketID; + + } elseif (isset($_SESSION[GLM_EVENT_SESSION]['Ticket'])) { + + // Otherwise, get the ticket ID from the session + $ticketID = $_SESSION[GLM_EVENT_SESSION]['Ticket']; + + } else { + + // Otherwise, we don't have a ticket id + return false; + + } + + // Try to update this data + $r = $this->updateEntry($ticketID); + + return $r; + + } + + /** + * Add New Ticket + * + * @return array + */ + function newTicket() + { + + $r = $this->newEntry(); + + return $r; + + } + + /** + * Insert Ticket + * + * @return array + */ + function insertTicket() + { + + $r = $this->insertEntry(); + + // If succesful then set current ticket to the one just inserted. + if ($r['status']) { + $_SESSION[GLM_EVENT_SESSION]['Ticket'] = $r['insertedID']; + } + + return $r; + + } + + /** + * Delete Ticket + * + * @param $confirm bool False to ask if user wants to delete and true to actually delete + * + * @return array + */ + function ticketDelete($confirm = false) + { + + // Is there a new ticket code selected? + if (($ticketID = filter_input(INPUT_GET, 'TicketID', FILTER_SANITIZE_NUMBER_INT))) { + + // If so then add it to the session + $_SESSION[GLM_EVENT_SESSION]['Ticket'] = $ticketID; + + } elseif (isset($_SESSION[GLM_EVENT_SESSION]['Ticket'])) { + + // Otherwise, get the ticket ID from the session + $ticketID = $_SESSION[GLM_EVENT_SESSION]['Ticket']; + + } else { + + // Otherwise, we don't have an ticket id + return false; + + } + + $ticketDetail = $this->deleteEntry($ticketID, $confirm); + + return $ticketDetail; + + } + + +} + + + + +?> \ No newline at end of file diff --git a/classes/data/dataVoucherCoupons.php b/classes/data/dataVoucherCoupons.php new file mode 100644 index 0000000..a4f0850 --- /dev/null +++ b/classes/data/dataVoucherCoupons.php @@ -0,0 +1,472 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: dataVoucherCoupons.php,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +require_once DATA_ABSTRACT; + +/** + * EventManagementDataVoucherCoupons class + * + * PHP version 5 + * + * @category Data + * @package EventManagement + * @author Chuck Scott + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: dataVoucherCoupons,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ +class EventManagementDataVoucherCoupons extends DataAbstract +{ + /** + * Tables + * + * @var $ini + * @access public + */ + public $table = 'eventmgt.voucher_coupons'; + + /** + * Field definitions + * + * 'type' is type of field as defined by the application + * text Regular text field + * pointer Pointer to an entry in another table + * 'filters' is the filter name for a particular filter ID in PHP filter functions + * See PHP filter_id() + * + * 'use' is when to use the field + * l = List + * g = Get + * n = New + * i = Insert + * e = Edit + * u = Update + * d = Delete + * a = All + * + * @var $ini + * @access public + */ + public $fields = false; + + /** + * Constructor + * + * @param object $d database connection + * + * @return void + * @access public + */ + function __construct($dbh, $config) + { + + parent::__construct($dbh, $config); + + $this->fields = array( + + // Record ID + 'id' => array( + 'field' => 'id', + 'as' => false, + 'type' => 'integer', + 'required' => true, + 'unique' => true, + 'default' => false, + 'use' => 'lged' + ), + + // Voucher Coupon Name + 'name' => array( + 'field' => 'name', + 'as' => false, + 'type' => 'text', + 'required' => true, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Active + 'active' => array( + 'field' => 'active', + 'as' => false, + 'type' => 'checkbox', + 'required' => false, + 'unique' => false, + 'default' => true, + 'use' => 'a' + ), + + // Coupon Type + 'coupon_type' => array( + 'field' => 'coupon_type', + 'as' => false, + 'type' => 'list', + 'list' => $this->config->coupon_type->toArray(), + 'list_keytype' => 'int', + 'required' => true, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Coupon Position + 'coupon_position' => array( + 'field' => 'coupon_position', + 'as' => false, + 'type' => 'list', + 'list' => $this->config->coupon_position->toArray(), + 'list_keytype' => 'int', + 'required' => true, + 'unique' => false, + 'default' => 0, + 'use' => 'a' + ), + + // Display From Date + 'display_from' => array( + 'field' => 'display_from', + 'as' => false, + 'type' => 'date', + 'required' => true, + 'unique' => false, + 'default' => time(), + 'use' => 'a' + ), + + // Display To Date + 'display_to' => array( + 'field' => 'display_to', + 'as' => false, + 'type' => 'date', + 'required' => true, + 'unique' => false, + 'default' => strtotime('12/31/'.date('Y').' +4 years'), + 'use' => 'a' + ), + + // Stretch to Fit + 'stretch_to_fit' => array( + 'field' => 'stretch_to_fit', + 'as' => false, + 'type' => 'checkbox', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Image Padding + 'padding' => array( + 'field' => 'padding', + 'as' => false, + 'type' => 'integer', + 'required' => true, + 'unique' => false, + 'default' => 0, + 'use' => 'a' + ), + + // Show Border + 'show_border' => array( + 'field' => 'show_border', + 'as' => false, + 'type' => 'checkbox', + 'required' => false, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Coupon Image + 'coupon_image' => array( + 'field' => 'coupon_image', + 'as' => false, + 'type' => 'image', + 'required' => true, + 'unique' => false, + 'default' => false, + 'use' => 'a' + ), + + // Maximum Display Count (-1 = unlimited) + 'max_display_count' => array( + 'field' => 'max_display_count', + 'as' => false, + 'type' => 'integer', + 'required' => true, + 'unique' => false, + 'default' => -1, + 'use' => 'a' + ), + + // Display Count + 'display_count' => array( + 'field' => 'display_count', + 'as' => false, + 'type' => 'integer', + 'required' => true, + 'unique' => false, + 'default' => 0, + 'use' => 'a' + ) + + ); + } + + /** + * Check for other field related issues + * + * Simply return $r if there's nothing to check. + * + * @return array + */ + function checkOther($r) + { + parent::checkOther($r); + + return $r; + } + + + /** + * Get Voucher Coupon list + * + * @return object containing array as sub-objects + */ + function getVoucherCouponList($where = '') + { + + // Build query Where clause + if ($where == '') { + $where = 'true'; + } + + // Get list of Voucher Coupons + $voucherCouponsList = $this->getList($where, 'name'); + + return $voucherCouponsList; + } + + /** + * Get Voucher Coupon Detail + * + * @return array + */ + function getVoucherCouponDetail($voucherCouponID = false) + { + + // If a voucher coupon has been specified + if ($voucherCouponID != false) { + + $_SESSION[GLM_EVENT_SESSION]['VoucherCoupon'] = $voucherCouponID; + + // Otherwise if there's a voucher coupon ID in the request + } elseif (($voucherCouponID = filter_input(INPUT_GET, 'VoucherCouponID', FILTER_SANITIZE_NUMBER_INT))) { + + // There's a Voucher Coupon submitted, so save that + $_SESSION[GLM_EVENT_SESSION]['VoucherCoupon'] = $voucherCouponID; + + } elseif (isset($_SESSION[GLM_EVENT_SESSION]['VoucherCoupon'])) { + + // Otherwise, get the voucher coupon ID from the session + $voucherCouponID = $_SESSION[GLM_EVENT_SESSION]['VoucherCoupon']; + + } else { + + // Otherwise, we don't have a voucher coupon id + return false; + + } + + $voucherCouponDetail = $this->getEntry($voucherCouponID); + + return $voucherCouponDetail; + + } + + /** + * Edit Voucher Coupon + * + * @return array + */ + function editVoucherCoupon() + { + + if (($voucherCouponID = filter_input(INPUT_GET, 'VoucherCouponID', FILTER_SANITIZE_NUMBER_INT))) { + + // If so then add it to the session + $_SESSION[GLM_EVENT_SESSION]['VoucherCoupon'] = $voucherCouponID; + + } elseif (isset($_SESSION[GLM_EVENT_SESSION]['VoucherCoupon'])) { + + // Otherwise, get the voucher coupon ID from the session + $voucherCouponID = $_SESSION[GLM_EVENT_SESSION]['VoucherCoupon']; + + } else { + + // Otherwise, we don't have a voucher coupon id + return false; + + } + + $voucherCouponDetail = $this->editEntry($voucherCouponID); + + return $voucherCouponDetail; + + } + + /** + * Update Voucher Coupon + * + * @return array + */ + function updateVoucherCoupon() + { + + if (($voucherCouponID = filter_input(INPUT_GET, 'VoucherCouponID', FILTER_SANITIZE_NUMBER_INT))) { + + // If so then add it to the session + $_SESSION[GLM_EVENT_SESSION]['VoucherCoupon'] = $voucherCouponID; + + } elseif (isset($_SESSION[GLM_EVENT_SESSION]['VoucherCoupon'])) { + + // Otherwise, get the voucher coupon ID from the session + $voucherCouponID = $_SESSION[GLM_EVENT_SESSION]['VoucherCoupon']; + + } else { + + // Otherwise, we don't have a voucher coupon id + return false; + + } + + // Try to update this data + $r = $this->updateEntry($voucherCouponID); + + return $r; + + } + + /** + * Add New Voucher Coupon + * + * @return array + */ + function newVoucherCoupon() + { + + $r = $this->newEntry(); + + return $r; + + } + + /** + * Insert Voucher Coupon + * + * @return array + */ + function insertVoucherCoupon() + { + + $r = $this->insertEntry(); + + // If succesful then set current voucher coupone to the one just inserted. + if ($r['status']) { + $_SESSION[GLM_EVENT_SESSION]['VoucherCoupon'] = $r['insertedID']; + } + + return $r; + + } + + /** + * Delete Voucher Coupon + * + * @param $confirm bool False to ask if user wants to delete and true to actually delete + * + * @return array + */ + function voucherCouponDelete($confirm = false) + { + + // Is there a new voucher coupon code selected? + if (($voucherCouponID = filter_input(INPUT_GET, 'VoucherCouponID', FILTER_SANITIZE_NUMBER_INT))) { + + // If so then add it to the session + $_SESSION[GLM_EVENT_SESSION]['VoucherCoupon'] = $voucherCouponID; + + } elseif (isset($_SESSION[GLM_EVENT_SESSION]['VoucherCoupon'])) { + + // Otherwise, get the voucher coupon ID from the session + $voucherCouponID = $_SESSION[GLM_EVENT_SESSION]['VoucherCoupon']; + + } else { + + // Otherwise, we don't have an voucher coupon id + return false; + + } + + $voucherCouponDetail = $this->deleteEntry($voucherCouponID, $confirm); + + return $voucherCouponDetail; + + } + + /** + * Get Voucher Coupon List for Display + * + * @param $date string Date to use for selection (usually today unless testing) + * + * @return array + */ + function getCouponsForDisplay($date = false) + { + + $where = ''; + + // If no date (time) has been supplied + if (!$date) { + $date = date('m/d/Y', time()); + } + $where = "T.active AND '$date' >= T.display_from AND '$date' <= T.display_to"; + + $coupons = $this->getVoucherCouponList($where); + + if (!is_array($coupons) || count($coupons) == 0) { + return false; + } + + // Convert to array organized by location + $cr = array(); + foreach ($coupons as $c) { + $cr[$c['coupon_position']['value']][] = $c; + } + + // Shuffle order of coupons in each location (randomize) + foreach ($cr as $k => $v) { + shuffle($cr[$k]); + } + + return $cr; + + } + +} + + + + +?> \ No newline at end of file diff --git a/configs/common.ini b/configs/common.ini new file mode 100644 index 0000000..deb1b9b --- /dev/null +++ b/configs/common.ini @@ -0,0 +1,807 @@ +; Configuration File for Event Management System - V3 +; +; This file contains common configuration for all sites using this Event Management +; System on this server. Each site also has local configuration for this application +; in a config/applications/EventManagement.ini file in the site. +; +; Custom configurations for development and developer configuration at bottom of file. + +[common] + +applicationName = "Event Management" +applicationVersion = "EventManagement/V3" +dataAbstractLocation = "Database/V0" +pdfAbstractLocation = "PDF/V0" +paymentProcessorsLocation = "PaymentProcessors/V0" +imageServerAbstractLocation = "ImageServer/V0" +internalReportingAddress = "cscott@gaslightmedia.com" + +orderVerificationSecret = "GLMOrder2secreT" + +; +; ********** NEED TO VERIFY EVERYTHING BELOW ************** +; + +; Base URL/paths for front-end of this application +url.members = CURRENT_BASE_URL "members-only-area/?page_id=122" +path.front_end = BASE_PATH "" +path.admin = BASE_PATH "admin/Event_Housing/" +path.common = "/var/www/server/CommonApps/" + +; Admin Interface Selection +default_admin_interface = "tickets" +admin_interface.selectable = false; +admin_interface.tickets = "tickets" +admin_interface_type.tickets = "flexy" ;Options are "flexy" and "smarty" (smarty not working yet) + +; Front End Interface Selection +; default_front_interface (set in customer configuration) +front_interface.selectable = false; + +; Front End Interfaces +; "tickets" +front_interface.tickets = "tickets" +front_interface_type.tickets = "flexy" ;Options are "flexy" and "smarty" (smarty not working yet) +; "TicketsFoundation" +front_interface.TicketsFoundation = "TicketsFoundation" +front_interface_type.TicketsFoundation = "flexy" ;Options are "flexy" and "smarty" (smarty not working yet) +; "FoundationStandAlone" - Used for foundation with tickets when Foundation is not loaded for the site +front_interface.FoundationStandAlone = "TicketsFoundation" +front_interface_type.FoundationStandAlone = "flexy" ;Options are "flexy" and "smarty" (smarty not working yet) +; "SaultSteMarie" +front_interface.SaultSteMarie = "SaultSteMarie" +front_interface_type.SaultSteMarie = "flexy" ;Options are "flexy" and "smarty" (smarty not working yet) +; "Gaslight" +front_interface.Gaslight = "Gaslight" +front_interface_type.Gaslight = "flexy" ;Options are "flexy" and "smarty" (smarty not working yet) +; "MMM" +front_interface.MMM = "MMM" +front_interface_type.MMM = "flexy" ;Options are "flexy" and "smarty" (smarty not working yet) +; "PointerBoat" +front_interface.PointerBoat = "PointerBoat" +front_interface_type.PointerBoat = "flexy" ;Options are "flexy" and "smarty" (smarty not working yet) + +; Set Database Date Style - uncomment desired style +;misc.datestyle = "SET DATESTYLE TO 'ISO';" ;ISO example: 1997-12-17 07:37:16-08';\n" +misc.datestyle = "SET DATESTYLE TO 'SQL';" ;SQL example: 12/17/1997 07:37:16.00 PST';\n" +;misc.datestyle = "SET DATESTYLE TO 'Postgres';" ;Postgres example: Wed Dec 17 07:37:16 1997 PST';\n" +;misc.datestyle = "SET DATESTYLE TO 'European';" ;European example: 17/12/1997 15:37:16.00 MET';\n" +;misc.datestyle = "SET DATESTYLE TO 'US';" ;US example: 12/17/1997 07:37:16.00 PST';\n" +;misc.datestyle = "SET DATESTYLE TO 'German';" ;German example: 17.12.1997 07:37:16.00 PST';\n" + +; Standard arrays + +; Member Types +member_type.1 = "Standard" +member_type.2 = "Standard + Sells other's items" +member_type.3 = "Vendor of items only sold through others" +member_type.10 = "Other - neither vendor nor sales" + +; Ticket consignment types +ticket_consignment_type.1 = "Not sold by other locations" +ticket_consignment_type.2 = "Available for sale by other locations" +ticket_consignment_type.3 = "Sold only by other locations" + +; Ticket voucher types - Note types < 80 are tickets, > 80 are things sold +ticket_voucher_type.1 = "Standard Voucher/Ticket with Barcode" +ticket_voucher_type.11 = "Voucher/Ticket for Pickup - no Barcode" +ticket_voucher_type.12 = "Voucher/Ticket to be mailed Mailed - no Barcode" +ticket_voucher_type.81 = "Object Sold (i.e. books) to be claimed - with Barcode" +ticket_voucher_type.82 = "Object Sold (i.e. books) to be mailed - no Barcode" + +; Ticket Types +ticket_type.10 = 'Standard' +ticket_type.20 = 'Package' + +; Ticket Add-On Types +ticket_add_on_type.1 = 'Checkbox' +ticket_add_on_type.2 = 'Quantity' + +; Promo Ticket Types +promo_ticket_type.1 = '$ Amount' +promo_ticket_type.2 = 'Percentage' + +; Permissions +permissions.10 = "Full Venue Access" +permissions.20 = "Ticket Orders and Claims" +permissions.30 = "Ticket Claims Only" +permissions.99 = "No Access" + +; Permissions References +permissions_numb.full = 10 +permissions_numb.orders_and_claims = 20 +permissions_numb.claims = 30 +permissions_numb.none = 99 + +; Pending cart hold types +hold_types.reservation = 1 +hold_types.ticket = 2 + +; Claim Tracking Types by Name +claim_tracking_types_numb.claim = 1 +claim_tracking_types_numb.clear = 2 + +; Claim Tracking Types +claim_tracking_types.1 = "Claimed" +claim_tracking_types.2 = "Claim Cleared" + +; Processing Methods +proc_method.1 = merchant ;Merchant processes cards +proc_method.2 = processed ;Processed by a card processor + +; Card Processors by number +ccard_processor.0 = "(none - select processor)" +ccard_processor.3 = "No Payment Processing at Checkout" +ccard_processor.99 = "Card Processing Test" +ccard_processor.1 = "Authorize.net" +ccard_processor.2 = "Merchant Solutions" + +; Card Processors by name +ccard_processor_numb.none = 0 +ccard_processor_numb.authorize_net = 1 +ccard_processor_numb.merchant_solutions = 2 +ccard_processor_numb.no_payment = 3 +ccard_processor_numb.test = 99 + +; Card processing mode options +cc_mode.1 = "Local Transaction Approval Test" +cc_mode.2 = "Local Transaction Decline Test" +cc_mode.3 = "On-Line Transaction Test" +cc_mode.0 = "Production Mode" + +; PayPal processing mode options +paypal_mode.3 = "On-Line Transaction Test" +paypal_mode.0 = "Production Mode" + +; Processing Status +proc_status.new = 0 +proc_status.descr.0 = "New Registration Record" +proc_status.unpaid = 1 +proc_status.descr.1 = "Not Paid" +proc_status.cc_pend = 2 +proc_status.descr.2 = "Credit Card Pending" +proc_status.cc_paid = 3 +proc_status.descr.3 = "Paid by Credit Card" +proc_status.cc_decl = 4 +proc_status.descr.4 = "Credit Card Declined" +proc_status.check_pend = 5 +proc_status.descr.5 = "Check Pending" +proc_status.check_paid = 6 +proc_status.descr.6 = "Paid by Check" +proc_status.comp = 7 +proc_status.descr.7 = "Complimentary" +proc_status.failed = 98 +proc_status.descr.98 = "Submission Failed" +proc_status.canceled = 99 +proc_status.descr.99 = "Canceled" + +; Payment Types +pay_types.1 = "Credit Card" +pay_types.2 = "Check" +pay_types.3 = "Direct" +pay_types.4 = "PayPal" + +; Credit Cards - numbers are an exponent of 2 that represent the bit position +ccard.0 = "Visa" +ccard.1 = "MasterCard" +ccard.2 = "American Express" +ccard.3 = "Discover" +ccard.4 = "Diners Club" + +; Credit Card validation strings (regular expression) +ccverify.0 = "^4.{15}$|^4.{12}$" +ccverify.1 = "^5[1-5].{14}$" +ccverify.2 = "^3[47].{13}$" +ccverify.3 = "^6011.{12}$" +ccverify.4 = "^30[0-5].{11}$|^3[68].{12}$" + +; Confirmation Methods +conf_methods.1 = "US Mail" +conf_methods.2 = "E-Mail" + +; Reference Types +reference_type.misc = 0 +reference_type.event = 1 +reference_type.member = 2 +reference_type.state = 3 +reference_type.team = 4 + +; Voucher Check Character Secret +voucher_check_secret = "emVoucherCheck1" + +; Reference Type Numbers +reference_type_numb.0 = "Misc" +reference_type_numb.1 = "Event" +reference_type_numb.2 = "Member/Venue" +reference_type_numb.3 = "State Rep" +reference_type_numb.4 = "Team" + +; Fee Method +fee_method.fixed_stay = 1 +fee_method.fixed_accom = 2 +fee_method.fixed_accomnight = 3 +fee_method.percent_stay = 10 + +; Fee Method Numbers +fee_method_numb.1 = "Per Reservation" +fee_method_numb.2 = "Per Room" +fee_method_numb.3 = "Per Night" +fee_method_numb.10 = "Percent of Room Rate" + +; Member/Venue Amenities +; Static amenitities set system-wide +; Only 10 fields in member records for these at this time +; Needs to be replaced with managed amenities list +memb_amen.1 = "Air-Conditioning" +memb_amen.2 = "Barrier Free" +memb_amen.3 = "Coffee Pot" +memb_amen.4 = "Hair Dryer" +memb_amen.5 = "Interior Corridor" +memb_amen.6 = "Microwave" +memb_amen.7 = "Refrigerator" +;memb_amen.8 = "Shopping nearby" +;memb_amen.9 = "Indoor pool" +;memb_amen.10 = "Outdoor pool" +;memb_amen.? = "Sauna" +;memb_amen.? = "Whirlpool" +;memb_amen.? = "Valet/Charge Parking" +;memb_amen.? = "Self-operated coin laundry" +;memb_amen.? = "Free parking" +;memb_amen.? = "Fitness area" +;memb_amen.? = "Room service" +;memb_amen.? = "Conference/Meeting facilities" +;memb_amen.? = "Restaurant nearby" +;memb_amen.? = "Restaurant on site" +;memb_amen.? = "Barrier free guest rooms available" +;memb_amen.? = "Pets" +;memb_amen.? = "Golf nearby" + +; Accommodatation Amenitities +; NOT USED AT THIS TIME +;accom_amen.1 = "Cable TV" +;accom_amen.2 = "Movies in Room" +;accom_amen.3 = "Barrier Free Access" +;accom_amen.4 = "Smoke Free Room" +;accom_amen.5 = "Jacuzzi in Room" +;accom_amen.6 = "Iron and Ironing Board" +;accom_amen.7 = "Coffee Pot in Room" +;accom_amen.8 = "Refrigerator in Room" +;accom_amen.9 = "Microwave in Room" +;accom_amen.10 = "Safe" +;accom_amen.11 = "Hair Dryer" + +; Accommodation Room Categories +room_category.0 = "n/a" +room_category.1 = "Bed" +room_category.2 = "Room" +room_category.3 = "Suite" + +; Accommodation Room Types +room_types.0 = "n/a" +room_types.1 = "Main" +room_types.2 = "Bedroom" +room_types.3 = "Kitchen" +room_types.4 = "Living Room" + +; Accommodation Bath Types +bath_types.0 = "None" +bath_types.1 = "Full" +bath_types.2 = "Half" +bath_types.3 = "Sink" + +; Voucher Coupon Types +coupon_type.0 = "Image" +; coupon_type.1 = "PDF" +; coupon_type.2 = "Text" + +; Days of the week - numbers are an exponent of 2 that represent the bit position +days.0 = "Sunday" +days.1 = "Monday" +days.2 = "Tuesday" +days.3 = "Wednesday" +days.4 = "Thursday" +days.5 = "Friday" +days.6 = "Saturday" + +; States +states.AL = "Alabama" +states.AK = "Alaska" +states.AB = "Alberta" +states.AZ = "Arizona" +states.AR = "Arkansas" +states.BC = "British Columbia" +states.CA = "California" +states.CO = "Colorado" +states.CT = "Connecticut" +states.DE = "Delaware" +states.DC = "District of Columbia" +states.FL = "Florida" +states.GA = "Georgia" +states.GU = "Guam" +states.HI = "Hawaii" +states.ID = "Idaho" +states.IL = "Illinois" +states.IN = "Indiana" +states.IA = "Iowa" +states.KS = "Kansas" +states.KY = "Kentucky" +states.LA = "Louisiana" +states.ME = "Maine" +states.MB = "Manitoba" +states.MD = "Maryland" +states.MA = "Massachusetts" +states.MI = "Michigan" +states.MN = "Minnesota" +states.MS = "Mississppi" +states.MO = "Missouri" +states.MT = "Montana" +states.NE = "Nebraska" +states.NV = "Nevada" +states.NB = "New Brunswick" +states.NF = "Newfoundland" +states.NH = "New Hampshire" +states.NJ = "New Jersey" +states.NM = "New Mexico" +states.NY = "New York" +states.NC = "North Carolina" +states.ND = "North Dakota" +states.NT = "Northwest Territories" +states.NS = "Nova Scotia" +states.OH = "Ohio" +states.OK = "Oklahoma" +states.ON = "Ontario" +states.OR = "Oregon" +states.PA = "Pennsylvania" +states.PE = "Prince Edward Island" +states.PR = "Puerto Rico" +states.QC = "Quebec" +states.RI = "Rhode Island" +states.SK = "Saskatchewan" +states.SC = "South Carolina" +states.SD = "South Dakota" +states.TN = "Tennessee" +states.TX = "Texas" +states.UT = "Utah" +states.VT = "Vermont" +states.VI = "Virgin Islands" +states.VA = "Virginia" +states.WA = "Washington" +states.WV = "West Virginia" +states.WI = "Wisconsin" +states.WY = "Wyoming" +states.YT = "Yukon" + +; Countries +countries.US = "United States" +countries.CA = "Canada" +countries.AF = "Afghanistan" +countries.AX = "Land Islands" +countries.AL = "Albania" +countries.DZ = "Algeria" +countries.AS = "American Samoa" +countries.AD = "Andorra" +countries.AO = "Angola" +countries.AI = "Anguilla" +countries.AQ = "Antarctica" +countries.AG = "Antigua and Barbuda" +countries.AR = "Argentina" +countries.AM = "Armenia" +countries.AW = "Aruba" +countries.AU = "Australia" +countries.AT = "Austria" +countries.AZ = "Azerbaijan" +countries.BS = "Bahamas" +countries.BH = "Bahrain" +countries.BD = "Bangladesh" +countries.BB = "Barbados" +countries.BY = "Belarus" +countries.BE = "Belgium" +countries.BZ = "Belize" +countries.BJ = "Benin" +countries.BM = "Bermuda" +countries.BT = "Bhutan" +countries.BO = "Bolivia" +countries.BA = "Bosnia and Herzegovina" +countries.BW = "Botswana" +countries.BV = "Bouvet Island" +countries.BR = "Brazil" +countries.IO = "British Indian Ocean Territory" +countries.BN = "Brunei Darussalam" +countries.BG = "Bulgaria" +countries.BF = "Burkina Faso" +countries.BI = "Burundi" +countries.KH = "Cambodia" +countries.CM = "Cameroon" +countries.CV = "Cape Verde" +countries.KY = "Cayman Islands" +countries.CF = "Central African Republic" +countries.TD = "Chad" +countries.CL = "Chile" +countries.CN = "China" +countries.CX = "Christmas Island" +countries.CC = "Cocos (Keeling) Islands" +countries.CO = "Colombia" +countries.KM = "Comoros" +countries.CG = "Congo" +countries.CD = "Congo, the Democratic Rep. of" +countries.CK = "Cook Islands" +countries.CR = "Costa Rica" +countries.CI = "Cote D'Ivoire" +countries.HR = "Croatia" +countries.CU = "Cuba" +countries.CY = "Cyprus" +countries.CZ = "Czech Republic" +countries.DK = "Denmark" +countries.DJ = "Djibouti" +countries.DM = "Dominica" +countries.DO = "Dominican Republic" +countries.EC = "Ecuador" +countries.EG = "Egypt" +countries.SV = "El Salvador" +countries.GQ = "Equatorial Guinea" +countries.ER = "Eritrea" +countries.EE = "Estonia" +countries.ET = "Ethiopia" +countries.FK = "Falkland Islands (Malvinas)" +countries.FO = "Faroe Islands" +countries.FJ = "Fiji" +countries.FI = "Finland" +countries.FR = "France" +countries.GF = "French Guiana" +countries.PF = "French Polynesia" +countries.TF = "French Southern Territories" +countries.GA = "Gabon" +countries.GM = "Gambia" +countries.GE = "Georgia" +countries.DE = "Germany" +countries.GH = "Ghana" +countries.GI = "Gibraltar" +countries.GR = "Greece" +countries.GL = "Greenland" +countries.GD = "Grenada" +countries.GP = "Guadeloupe" +countries.GU = "Guam" +countries.GT = "Guatemala" +countries.GN = "Guinea" +countries.GW = "Guinea-Bissau" +countries.GY = "Guyana" +countries.HT = "Haiti" +countries.HM = "Heard Island, McDonald Islands" +countries.VA = "Holy see (Vatican City State)" +countries.HN = "Honduras" +countries.HK = "Hong Kong" +countries.HU = "Hungary" +countries.IS = "Iceland" +countries.IN = "India" +countries.ID = "Indonesia" +countries.IR = "Iran, Islamic Republic of" +countries.IQ = "Iraq" +countries.IE = "Ireland" +countries.IL = "Israel" +countries.IT = "Italy" +countries.JM = "Jamaica" +countries.JP = "Japan" +countries.JO = "Jordan" +countries.KZ = "Kazakhstan" +countries.KE = "Kenya" +countries.KI = "Kiribati" +countries.KP = "Korea, Democratic People's Rep. of" +countries.KR = "Korea, Republic of" +countries.KW = "Kuwait" +countries.KG = "Kyrgyzstan" +countries.LA = "Lao People's Democratic Republic" +countries.LV = "Latvia" +countries.LB = "Lebanon" +countries.LS = "Lesotho" +countries.LR = "Liberia" +countries.LY = "Libyan Arab Jamahiriya" +countries.LI = "Liechtenstein" +countries.LT = "Lithuania" +countries.LU = "Luxembourg" +countries.MO = "Macao" +countries.MK = "Macedonia, the Former Yugoslav Rep." +countries.MG = "Madagascar" +countries.MW = "Malawi" +countries.MY = "Malaysia" +countries.MV = "Maldives" +countries.ML = "Mali" +countries.MT = "Malta" +countries.MH = "Marshall Islands" +countries.MQ = "Martinique" +countries.MR = "Mauritania" +countries.MU = "Mauritius" +countries.YT = "Mayotte" +countries.MX = "Mexico" +countries.FM = "Micronesia, Federated States of" +countries.MD = "Moldova, Republic of" +countries.MC = "Monaco" +countries.MN = "Mongolia" +countries.MS = "Montserrat" +countries.MA = "Morocco" +countries.MZ = "Mozambique" +countries.MM = "Myanmar" +countries.NA = "Namibia" +countries.NR = "Nauru" +countries.NP = "Nepal" +countries.NL = "Netherlands" +countries.AN = "Netherlands Antilles" +countries.NC = "New Caledonia" +countries.NZ = "New Zealand" +countries.NI = "Nicaragua" +countries.NE = "Niger" +countries.NG = "Nigeria" +countries.NU = "Niue" +countries.NF = "Norfolk Island" +countries.MP = "Northern Mariana Islands" +countries.NO = "Norway" +countries.OM = "Oman" +countries.PK = "Pakistan" +countries.PW = "Palau" +countries.PS = "Palestinian Territory, Occupied" +countries.PA = "Panama" +countries.PG = "Papua New Guinea" +countries.PY = "Paraguay" +countries.PE = "Peru" +countries.PH = "Philippines" +countries.PN = "Pitcairn" +countries.PL = "Poland" +countries.PT = "Portugal" +countries.PR = "Puerto Rico" +countries.QA = "Qatar" +countries.RE = "Reunion" +countries.RO = "Romania" +countries.RU = "Russian Federation" +countries.RW = "Rwanda" +countries.SH = "Saint Helena" +countries.KN = "Saint Kitts and Nevis" +countries.LC = "Saint Lucia" +countries.PM = "Saint Pierre and Miquelon" +countries.VC = "Saint Vincent and the Grenadines" +countries.WS = "Samoa" +countries.SM = "San Marino" +countries.ST = "Sao Tome and Principe" +countries.SA = "Saudi Arabia" +countries.SN = "Senegal" +countries.CS = "Serbia and Montenegro" +countries.SC = "Seychelles" +countries.SL = "Sierra Leone" +countries.SG = "Singapore" +countries.SK = "Slovakia" +countries.SI = "Slovenia" +countries.SB = "Solomon Islands" +countries.SO = "Somalia" +countries.ZA = "South Africa" +countries.GS = "South Georgia, South Sandwich Islands" +countries.ES = "Spain" +countries.LK = "Sri Lanka" +countries.SD = "Sudan" +countries.SR = "Suriname" +countries.SJ = "Svalbard and Jan Mayen" +countries.SZ = "Swaziland" +countries.SE = "Sweden" +countries.CH = "Switzerland" +countries.SY = "Syrian Arab Republic" +countries.TW = "Taiwan, Province of China" +countries.TJ = "Tajikistan" +countries.TZ = "Tanzania, United Republic of" +countries.TH = "Thailand" +countries.TL = "Timor-Leste" +countries.TG = "Togo" +countries.TK = "Tokelau" +countries.TO = "Tonga" +countries.TT = "Trinidad and Tobago" +countries.TN = "Tunisia" +countries.TR = "Turkey" +countries.TM = "Turkmenistan" +countries.TC = "Turks and Caicos Islands" +countries.TV = "Tuvalu" +countries.UG = "Uganda" +countries.UA = "Ukraine" +countries.AE = "United Arab Emirates" +countries.GB = "United Kingdom" +countries.UM = "United States minor outlying islands" +countries.UY = "Uruguay" +countries.UZ = "Uzbekistan" +countries.VU = "Vanuatu" +countries.VE = "Venezuela" +countries.VN = "Viet Nam" +countries.VG = "Virgin Islands, British" +countries.VI = "Virgin Islands, U.S." +countries.WF = "Wallis and Futuna" +countries.EH = "Western Sahara" +countries.YE = "Yemen" +countries.ZM = "Zambia" +countries.ZW = "Zimbabwe" + +; Standard color names and codes +color.800000 = 'maroon' +color.8B0000 = 'darkred' +color.FF0000 = 'red' +color.FFB6C1 = 'lightpink' +color.DC143C = 'crimson' +color.DB7093 = 'palevioletred' +color.FF69B4 = 'hotpink' +color.FF1493 = 'deeppink' +color.C71585 = 'mediumvioletred' +color.800080 = 'purple' +color.8B008B = 'darkmagenta' +color.DA70D6 = 'orchid' +color.D8BFD8 = 'thistle' +color.DDA0DD = 'plum' +color.EE82EE = 'violet' +color.FF00FF = 'fuchsia' +color.FF00FF = 'magenta' +color.BA55D3 = 'mediumorchid' +color.9400D3 = 'darkviolet' +color.9932CC = 'darkorchid' +color.8A2BE2 = 'blueviolet' +color.4B0082 = 'indigo' +color.9370DB = 'mediumpurple' +color.6A5ACD = 'slateblue' +color.7B68EE = 'mediumslateblue' +color.00008B = 'darkblue' +color.05367D = 'mackinawblue' +color.0000CD = 'mediumblue' +color.0000FF = 'blue' +color.000080 = 'navy' +color.191970 = 'midnightblue' +color.483D8B = 'darkslateblue' +color.4169E1 = 'royalblue' +color.6495ED = 'cornflowerblue' +color.B0C4DE = 'lightsteelblue' +color.F0F8FF = 'aliceblue' +color.F8F8FF = 'ghostwhite' +color.E6E6FA = 'lavender' +color.1E90FF = 'dodgerblue' +color.4682B4 = 'steelblue' +color.00BFFF = 'deepskyblue' +color.708090 = 'slategray' +color.778899 = 'lightslategray' +color.87CEFA = 'lightskyblue' +color.87CEEB = 'skyblue' +color.ADD8E6 = 'lightblue' +color.008080 = 'teal' +color.008B8B = 'darkcyan' +color.00CED1 = 'darkturquoise' +color.00FFFF = 'aqua' +color.48D1CC = 'mediumturquoise' +color.5F9EA0 = 'cadetblue' +color.AFEEEE = 'paleturquoise' +color.E0FFFF = 'lightcyan' +color.F0FFFF = 'azure' +color.20B2AA = 'lightseagreen' +color.40E0D0 = 'turquoise' +color.B0E0E6 = 'powderblue' +color.2F4F4F = 'darkslategray' +color.7FFFD4 = 'aquamarine' +color.00FA9A = 'mediumspringgreen' +color.66CDAA = 'mediumaquamarine' +color.00FF7F = 'springgreen' +color.3CB371 = 'mediumseagreen' +color.2E8B57 = 'seagreen' +color.32CD32 = 'limegreen' +color.006400 = 'darkgreen' +color.008000 = 'green' +color.00FF00 = 'lime' +color.228B22 = 'forestgreen' +color.8FBC8F = 'darkseagreen' +color.90EE90 = 'lightgreen' +color.98FB98 = 'palegreen' +color.F5FFFA = 'mintcream' +color.F0FFF0 = 'honeydew' +color.7FFF00 = 'chartreuse' +color.7CFC00 = 'lawngreen' +color.6B8E23 = 'olivedrab' +color.556B2F = 'darkolivegreen' +color.9ACD32 = 'yellowgreen' +color.ADFF2F = 'greenyellow' +color.F5F5DC = 'beige' +color.FAF0E6 = 'linen' +color.FAFAD2 = 'lightgoldenrodyellow' +color.808000 = 'olive' +color.FFFF00 = 'yellow' +color.FFFFE0 = 'lightyellow' +color.FFFFF0 = 'ivory' +color.BDB76B = 'darkkhaki' +color.F0E68C = 'khaki' +color.EEE8AA = 'palegoldenrod' +color.F5DEB3 = 'wheat' +color.FFD700 = 'gold' +color.FFFACD = 'lemonchiffon' +color.FFEFD5 = 'papayawhip' +color.B8860B = 'darkgoldenrod' +color.DAA520 = 'goldenrod' +color.FAEBD7 = 'antiquewhite' +color.FFF8DC = 'cornsilk' +color.FDF5E6 = 'oldlace' +color.FFE4B5 = 'moccasin' +color.FFDEAD = 'navajowhite' +color.FFA500 = 'orange' +color.FFE4C4 = 'bisque' +color.D2B48C = 'tan' +color.FF8C00 = 'darkorange' +color.DEB887 = 'burlywood' +color.8B4513 = 'saddlebrown' +color.F4A460 = 'sandybrown' +color.FFEBCD = 'blanchedalmond' +color.FFF0F5 = 'lavenderblush' +color.FFF5EE = 'seashell' +color.FFFAF0 = 'floralwhite' +color.FFFAFA = 'snow' +color.CD853F = 'peru' +color.FFDAB9 = 'peachpuff' +color.D2691E = 'chocolate' +color.A0522D = 'sienna' +color.FFA07A = 'lightsalmon' +color.FF7F50 = 'coral' +color.E9967A = 'darksalmon' +color.FFE4E1 = 'mistyrose' +color.FF4500 = 'orangered' +color.FA8072 = 'salmon' +color.FF6347 = 'tomato' +color.BC8F8F = 'rosybrown' +color.FFC0CB = 'pink' +color.CD5C5C = 'indianred' +color.F08080 = 'lightcoral' +color.A52A2A = 'brown' +color.B22222 = 'firebrick' +color.000000 = 'black' +color.696969 = 'dimgray' +color.808080 = 'gray' +color.A9A9A9 = 'darkgray' +color.C0C0C0 = 'silver' +color.D3D3D3 = 'lightgrey' +color.DCDCDC = 'gainsboro' +color.F5F5F5 = 'whitesmoke' +color.FFFFFF = 'white' + +[production : common] +; Debugging and Testing parameters +option.development = false ;Tells templates that this is a production server +option.admin_debug = false ;If true causes system to dump diagnostic data to a separate window +option.admin_debug_size = 800 ;Width in pixels of front debug window +option.front_debug = false ;If true causes system to dump diagnostic data to a separate window +option.front_debug_size = 800 ;Width in pixels of front debug window +option.preview = true ;Use "preview=1" in links to support preview feature +option.checkout_pre_fill = false ;Use for testing, prefills checkout data for convenience +debug.level = 0 ;Debug level - 0=off +debug.view_parameters = false ;Display all View tags and information +debug.housing_query = false ;Display main housing query +debug.pricing = false ;Detailed information on pricing and cost calculations +debug.checkout = false ;Display checkout processing steps and data +debug.mail = false ;Display mail rather than send it +debug.glmpdf = false ;Display calibration grids in PDFs + +[development : common] +; Debugging and Testing parameters +option.development = true ;Tells templates that this is a development server +option.admin_debug = false ;If true causes system to dump diagnostic data to a separate window +option.admin_debug_size = 800 ;Width in pixels of front debug window +option.front_debug = false ;If true causes system to dump diagnostic data to a separate window +option.front_debug_size = 800 ;Width in pixels of front debug window +option.preview = true ;Use "preview=1" in links to support preview feature +option.checkout_pre_fill = false ;Use for testing, prefills checkout data for convenience +debug.level = 0 ;Debug level - 0=off +debug.view_parameters = false ;Display all View tags and information +debug.housing_query = false ;Display main housing query +debug.pricing = false ;Detailed information on pricing and cost calculations +debug.checkout = false ;Display checkout processing steps and data +debug.mail = false ;Display mail rather than send it +debug.glmpdf = false ;Display calibration grids in PDFs + +[chuck : common] +; Debugging and Testing parameters +option.development = true ;Tells templates that this is a development server +option.admin_debug = true ;If true causes system to dump diagnostic data to a separate window +option.admin_debug_size = 800 ;Width in pixels of front debug window +option.front_debug = true ;If true causes system to dump diagnostic data to a separate window +option.front_debug_size = 800 ;Width in pixels of front debug window +option.preview = false ;Use "preview=1" in links to support preview feature +option.checkout_pre_fill = true ;Use for testing, prefills checkout data for convenience +debug.level = 1 ;Debug level - 0=off, 1=Show Function Calls +debug.view_parameters = true ;Display all View tags and information +debug.housing_query = true ;Display main housing query +debug.pricing = true ;Detailed information on pricing and cost calculations +debug.checkout = true ;Display checkout processing steps and data +debug.mail = true ;Display mail rather than send it +debug.glmpdf = true ;Display calibration grids in PDFs diff --git a/controllers/AdminController.php b/controllers/AdminController.php new file mode 100644 index 0000000..69d2c94 --- /dev/null +++ b/controllers/AdminController.php @@ -0,0 +1,1051 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: EventManagement.php,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +/* + * Need to explain all this + */ +class EventManagementPage +{ + + public $level; + + function setUserLevel($level) + { + $this->level = $level; + } + + function checkPermission($userPermissionLevel) + { + if ($userPermissionLevel >= $this->level) { + return true; + } + return false; + } + +} + + +/** + * EventManagementAdminIndexController class + * + * Event Management System - Admin main index + * + * PHP version 5 + * + * @category Reservations_Front_End + * @package EventManagement + * @author Chuck Scott + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: EventManagement.php,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ +class EventManagementAdminIndexController +{ + + /** + * Debug Information + * @var $adminDebug + * @access public + */ + private $adminDebug = ''; + private $adminDebugMenu = ''; + /** + * Configuration information object + * @var $ini + * @access public + */ + public $config; + private $applicationConfig; + private $serverConfig; + private $siteConfig; + /** + * Database Object + * @var $dbh + * @access public + */ + public $dbh; + /** + * File/Image server adapter + * @var $isa + * @var $imageServer + * @access public + */ + public $isa; + public $imageServer; + /** + * Reason for any problems that come up + * @var unknown + * @access public + */ + public $reason = array(); + /** + * Current Action + * Default is set to SelectConv + * @var $Action + * @access public + */ + public $Action = 'SelectConv'; + /** + * Template to use for output + * @var unknown + * @access public + */ + public $flexyOptions; + public $template; + public $page; + /** + * User Level + * @var unknown + * @access public + */ + public $userLevel = false; + /** + * User Interface + * @var unknown + * @access public + */ + public $interface = false; + public $userInterface = false; + public $userInterfaces = false; + public $userInterfacesSelectable = false; + + public $customFeatures = false; + public $userMemberID = false; + public $memberName = false; + public $userMemberVenueName = false; + public $MemberUser = false; + public $MemberUserValid = false; + public $AdminUser = false; + public $tabList = false; + public $blockTab = false; + + /** + * Constructor + * + * @param object $d database connection + * + * @return void + * @access public + */ + public function __construct($applicationConfig, $serverConfig, $siteConfig) + { + + // Save config data and build a common config object + $this->applicationConfig = $applicationConfig; + $this->serverConfig = $serverConfig; + $this->siteConfig = $siteConfig; + $this->buildIntegratedConfig(); + + // Setup some required defines for this application + $this->setupDefines(); + + // Create database connection + $this->dbh = Toolkit_Database::getInstance(); + + // Set debug file name that includes remote address to keep users separate + if ($this->config->option->admin_debug) { + define('DEBUG_DATA_FILENAME', '/tmp/EventManagement.'.$_SERVER['REMOTE_ADDR'].'.debug.html'); + } + + // If there's no custom front-end, then disable custom features (i.e. Misc menu in admin) + $this->customFeatures = false; + if ($this->config->custom_prefix != '') { + $this->customFeatures = true; + } + + // Start Session + $this->startSession(); + + // Get requested action + $this->getRequestedAction(); + + // Check for a member user + $this->checkMemberUser(); + + // Check if there's a request to reset all selected items + $this->checkResetSelected(); + + // User interface selection + $this->userInterfaceSelection(); + + // Track selected tabs so they aren't repeated in the user interface + $this->trackTabs(); + + // Setup page and template configurations and add some standard page data + $this->setupTemplate(); + + // Setup URLs and Locations for templates + $this->setupURLs(); + + // Add start of request debug data + $this->startOfRequestDebug(); + + // Perform requested action and add this to debug + $this->performAction(); + + // Display Output + $this->displayOutput(); + + // Output debug information if that's enabled + $this->displayDebug(); + + } + + /** + * Assemble all required config data into $this->config + * + * @return void + */ + private function buildIntegratedConfig() + { + + // Set common apps base location + define('COMMON_APP_BASE', '/var/www/server/CommonApps/'); + + // Get customer's config for this application and Merge in customer's main application.ini + $this->config = new Zend_Config_Ini( + BASE_PATH.'config/applications/EventManagement.ini', + strtolower($_ENV['GLM_HOST_ID']), + array('allowModifications' => true) + ); + $this->config->merge($this->applicationConfig->event_management); + $this->config->owner = $this->siteConfig->owner; + $this->config->file_server = $this->serverConfig->file_server; + + // Set location for this application + define('EVENT_MANAGEMENT_APP_BASE', COMMON_APP_BASE.$this->config->version.'/'); + + // Get common config data for this application and merge in site specific config + $EMConfig = new Zend_Config_Ini( + EVENT_MANAGEMENT_APP_BASE.'configs/common.ini', + strtolower($_ENV['GLM_HOST_ID']), + array('allowModifications' => true) + ); + $this->config->merge($EMConfig); + + } + + /** + * Set system defines + * + * @return void + */ + private function setupDefines() + { + + // Set datestyle string for DB results + define('DATE_STYLE_STRING', $this->config->misc->datestyle ); + + // Set common apps base location + define('DATA_ABSTRACT', COMMON_APP_BASE.'CommonAbstracts/'.$this->config->dataAbstractLocation.'/DataAbstract.php'); + define('PDF_ABSTRACT', COMMON_APP_BASE.'CommonAbstracts/'.$this->config->pdfAbstractLocation.'/GlmPdf.php'); + define('IMAGE_SERVER_ABSTRACT', COMMON_APP_BASE.'CommonAbstracts/'.$this->config->imageServerAbstractLocation.'/Server.php'); + + // Also set a defined parameter for access to the File/Image Server + define('IMAGE_SERVER_PREFIX', $this->config->file_server->secure.$this->config->file_server->owner_id.'/'); + + } + + /** + * Start Session + * + * @return object containing array as sub-objects + */ + function startSession($force = false) + { + // If we haven't started sessions yet + if (!isset($_SESSION)) { + session_start(); + } + + // Use "session_reset=true" in link to force a reset + if ($_REQUEST['session_reset'] == 'true') { + $force = true; + } + + // Set a different session name if the user is coming from the front end as an ADMIN_LOGIN_USER + if (defined('MEMBER_USER') && MEMBER_USER) { + define('GLM_EVENT_SESSION', 'GLM_EVENT_MGT_LOGIN_USER'); + } else { + define('GLM_EVENT_SESSION', 'GLM_EVENT_MGT_ADMIN'); + + // Define MEMBER_USER as false so we don't have to keep checking if it's defined + define('MEMBER_USER', false); + } + + // If the session timeout has past then reset session + if ($_SESSION[GLM_EVENT_SESSION]['timeOut'] < time()) { + $force = true; + + // Only notify the user if the session has timed out in the last hour + if (time() - $_SESSION[GLM_EVENT_SESSION]['timeOut'] < 60*60 ) { + $this->reason[] = 'Your user session has timed out due to inactivity.'; + } + } + + // If requested or not yet set, create a clean session array + if ($force || !isset($_SESSION[GLM_EVENT_SESSION])) { + + // But save certain things + $this->interface = $_SESSION[GLM_EVENT_SESSION]['Interface']; + if ($_SESSION[GLM_EVENT_SESSION]['MemberUser']) { + $userMember = $_SESSION[GLM_EVENT_SESSION]['Member']; + $userID = $_SESSION[GLM_EVENT_SESSION]['MemberUser']; + $userLevel = $_SESSION[GLM_EVENT_SESSION]['MemberUserLevel']; + } else { + $userID = false; + $userLevel = $this->config->permissions_numb->none; + } + + // If full reset then set user interface back to default + if ($force) { + $this->interface = $this->config->default_admin_interface; + } + + // create GLM_HOUSING session with all parameters false + $_SESSION[GLM_EVENT_SESSION] = array( + 'timeOut' => false, + 'Event' => false, + 'Member' => $userMember, + 'Accom' => false, + 'Inven' => false, + 'Team' => false, + 'Booking' => false, + 'Reservation' => false, + 'State' => false, + 'Division' => false, + 'Contact' => false, + 'Entrance' => false, + 'Section' => false, + 'Performance' => false, + 'Promo' => false, + 'Ticket' => false, + 'TicketInventory' => false, + 'Interface' => $this->interface, + 'TabsSelected' => false, + 'Order' => false, + 'MemberUser' => $userID, + 'MemberUserLevel' => $userLevel, + 'VoucherCoupon' => false + ); + + } + + // Reset session timeout to current time plus timeout length in minutes + $_SESSION[GLM_EVENT_SESSION]['timeOut'] = strtotime('now +'.$this->config->admin_session_timeout.' minutes'); + + $this->addDebug('startSession()', 'Session timeout at: '.date('r', $_SESSION[GLM_EVENT_SESSION]['timeOut']).' ('.$_SESSION[GLM_EVENT_SESSION]['timeOut'].')'); + + } + + /** + * Get requested action + * + * @return void + */ + private function getRequestedAction() + { + + // Try both GET and POST + if (!($this->Action = filter_input(INPUT_GET, 'Action', FILTER_SANITIZE_STRING, FILTER_FLAG_STRIP_HIGH)) && + !($this->Action = filter_input(INPUT_POST, 'Action', FILTER_SANITIZE_STRING, FILTER_FLAG_STRIP_HIGH)) + ) { + // No Action provided, so doing default + $this->Action = 'Index_index'; + } + + } + + /** + * Check for member user + * + * @return void + */ + private function checkMemberUser() + { + + // Start with assumption that we don't have a valid member user + $this->MemberUserValid = false; + + // Override for debug window + if ($this->Action == "Debug_start" || $this->Action == "Debug_update") { + $this->MemberUser = false; + $this->AdminUser = true; + } + + // Check if this is a member logout. If so, send user back to front-end. + if ($_REQUEST['EMlogout'] == 'true') { + $_SESSION[GLM_EVENT_SESSION]['MemberUser'] = false; + $_SESSION[GLM_EVENT_SESSION]['MemberUserLevel'] = 0; + + echo ' + '; + } + + // If this is a member user, and we're not processing a debug request + if (MEMBER_USER && $this->Action != "Debug_start" && $this->Action != "Debug_update") { + + // Check if we aren't getting a login request and we already have a member user login + if ($this->Action != "User_login" && $_SESSION[GLM_EVENT_SESSION]['MemberUser']) { + + // Check the current user level + $sql = " + SELECT C.id, C.user_rights, C.active, C.affiliation, C.fname, C.lname, M.name + FROM eventmgt.res_contact C, eventmgt.member M + WHERE C.id = ".$_SESSION[GLM_EVENT_SESSION]['MemberUser']." + AND M.id = C.affiliation + ;"; + $stmt = $this->dbh->prepare($sql); + $stmt->execute(); + $contact = $stmt->fetch(PDO::FETCH_ASSOC); + + // If the contact has been deleted, is marked inactive, or had their rights changed + if ($contact == false || !$contact['active'] || $contact['user_rights'] != $_SESSION[GLM_EVENT_SESSION]['MemberUserLevel']) { + + // Send the user back to login + $_SESSION[GLM_EVENT_SESSION]['MemberUser'] = false; + $reason = + "Your session is being reset. This can happen for one of the following reasons. " + ."Your permissions have changed, " + ."your user account has been marked inactive, " + ."your user account has been deleted, " + ."or there has been an unexpected system error."; + echo ' + + '; + exit; + + } + + // Otherwise we must not have a current login + } else { + + // Assume we're not going to get logged in and we're going to send them back + $this->Action = 'User_login'; + + $email = filter_input(INPUT_POST, 'email', FILTER_SANITIZE_EMAIL); + $password = filter_input(INPUT_POST, 'password', FILTER_SANITIZE_STRING); + + // Check if we have email and password supplied + if ($email != '' && $password != '') { + + $loginFail = false; + + // Crypt password + $pwCrypt = crypt($password); + + // Check contact table for user with the supplied E-Mail address + $sql = " + SELECT C.id, C.password, C.user_rights, C.active, C.contact_type, C.affiliation, C.fname, C.lname, M.name + FROM eventmgt.res_contact C, eventmgt.member M + WHERE (C.email = '$email' OR C.login_id = '$email') + AND M.id = C.affiliation + ;"; + $stmt = $this->dbh->prepare($sql); + $stmt->execute(); + $contact = $stmt->fetch(PDO::FETCH_ASSOC); + + // If we found a contact with this E-Mail address that's active + if ($contact != false && $contact['active'] && $contact['contact_type'] == 2) { + + // Does the crypt match? + if (crypt($password, $contact['password']) == $contact['password']) { + + // Yep, so send user to the admin home + $this->Action = 'Index_index'; + + // And save the user login info + $_SESSION[GLM_EVENT_SESSION]['Member'] = $contact['affiliation']; + $_SESSION[GLM_EVENT_SESSION]['MemberUser'] = $contact['id']; + $_SESSION[GLM_EVENT_SESSION]['MemberUserLevel'] = $contact['user_rights']; + + } else { + $loginFail = true; + } + + } else { + $loginFail = true; + } + + if ($loginFail) { + $this->reason[] = 'You did not supply a valid E-Mail address or Log in ID and password.'; + } + + } + + } // Don't have member user login + + } else { + if ($this->Action != "Debug_start" && $this->Action != "Debug_update") { + // The user is not a MemberUser, so must be an admin user - Give full permissions + $_SESSION[GLM_EVENT_SESSION]['MemberUser'] = false; + $_SESSION[GLM_EVENT_SESSION]['MemberUserLevel'] = 0; + } + } + + // This stuffs the current user level into the EventManagementPage class parameter + if ($_SESSION[GLM_EVENT_SESSION]['MemberUserLevel'] > 0) { + $this->userMemberID = $_SESSION[GLM_EVENT_SESSION]['Member']; + $this->memberName = $contact['fname']." ".$contact['lname']; + $this->userMemberVenueName = $contact['name']; + } else { + $this->userMemberID = false; + $this->memberName = ''; + $this->userMemberVenueName = ''; + } + + } + + + /** + * Check if selected items reset has been requested + * + * @return void + */ + private function checkResetSelected() + { + + // If requested, reset all selected items in the session - This is done with all main tabs + if ($_REQUEST['resetSelected'] == 'true') { + + $_SESSION[GLM_EVENT_SESSION]['Event'] = false; + if (!$_SESSION[GLM_EVENT_SESSION]['MemberUser']) { + $_SESSION[GLM_EVENT_SESSION]['Member'] = false; + } + $_SESSION[GLM_EVENT_SESSION]['Accom'] = false; + $_SESSION[GLM_EVENT_SESSION]['Team'] = false; + $_SESSION[GLM_EVENT_SESSION]['Booking'] = false; + $_SESSION[GLM_EVENT_SESSION]['Reservation'] = false; + $_SESSION[GLM_EVENT_SESSION]['State'] = false; + $_SESSION[GLM_EVENT_SESSION]['Division'] = false; + $_SESSION[GLM_EVENT_SESSION]['Contact'] = false; + $_SESSION[GLM_EVENT_SESSION]['Section'] = false; + $_SESSION[GLM_EVENT_SESSION]['Performance'] = false; + $_SESSION[GLM_EVENT_SESSION]['Ticket'] = false; + $_SESSION[GLM_EVENT_SESSION]['TicketInventory'] = false; + $_SESSION[GLM_EVENT_SESSION]['Order'] = false; + + } + + } + + /** + * User Interface selection (template dir) + * + * @return void + */ + private function userInterfaceSelection() + { + + // Is there a request for a specific interface + if (isset($_REQUEST['interface']) && + in_array($_REQUEST['interface'], $this->config->admin_interface->toArray()) + ) { + $this->interface = $_REQUEST['interface']; + // Oherwise, do we have an interface selection in the user session? + } elseif (isset($_SESSION[GLM_EVENT_SESSION]['Interface']) && $_SESSION[GLM_EVENT_SESSION]['Interface'] != '') { + $this->interface = $_SESSION[GLM_EVENT_SESSION]['Interface']; + // If neither, then use default user interface. + } else { + $this->interface = $this->config->default_admin_interface; + } + + // Update session and page to show selected user interface + $_SESSION[GLM_EVENT_SESSION]['Interface'] = $this->interface; + $this->userInterface = $this->interface; + + // Provide list of user interfaces to page + $interfaces = $this->config->admin_interface->toArray(); + $userInterfaces = array(); + foreach ($interfaces as $i) { + $userInterfaces[] = array( + 'directory' => $i, + 'name' => $i, + 'selected' => ($i == $this->interface) + ); + } + + // If there's more than 1 user interface then tell the template to display user interface selection + $this->userInterfacesSelectable = ($this->config->admin_interface->selectable && count($interfaces) > 1); + $this->userInterfaces = $this->bindArrayToObject($userInterfaces); + + } + + /** + * Track tabs that are selected + * + * This is to keep from displaying another tab in a + * lower layer that's already been displayed. + * + * @return void + */ + private function trackTabs() + { + + // If tab list is provided + if (isset($_REQUEST['tabList'])) { + $this->tabList = $_REQUEST['tabList']; + } else { + $this->tabList = ''; + } + if ($this->tabList != '') { + $this->tabList .= ','; + } + $this->tabList .= $this->Action; + + $blockTab = array(); + $nt = explode(',', $this->tabList); + foreach ($nt as $t) { + $blockTab[$t] = true; + } + $this->blockTab = $this->bindArrayToObject($blockTab); + + } + + /** + * Set template configuration + * + * @return void + */ + private function setupTemplate() + { + // Test if there is a local templates directory for the Web site + if (is_dir(BASE_PATH.'admin/EventManagement/templates')) { + $templatesDir = BASE_PATH.'admin/EventManagement/templates/admin/'; + } else { + // Otherwise use the templates in this app + $templatesDir = EVENT_MANAGEMENT_APP_BASE.'views/admin/'; + } + + // Setup Template and Page + $this->flexyOptions = array( + 'templateDir' => $templatesDir, + 'compileDir' => BASE_PATH.'/templates/compiled', + 'forceCompile' => false, + 'flexyIgnore' => true, + 'allowPHP' => true, + 'debug' => false + ); + $this->template = new HTML_Template_Flexy($this->flexyOptions); + $this->page = new EventManagementPage(); + + // Add some standard page data + $this->page->startScript = ' + '; + } + + } + + } + + /** + * Get all general search lists - Events, Members, etc + * + * @return object containing array as sub-objects + */ + function getSearchLists() + { + // Get full list of events + $sql = "SELECT id, name, event_code, active, end_date < 'now' AS expired, team_event + FROM eventmgt.event + ORDER BY name;"; + $stmt = $this->dbh->prepare($sql); + $stmt->execute(); + $eventsList = $stmt->fetchAll(PDO::FETCH_ASSOC); + + // Get full list of members + $sql = "SELECT id, name FROM eventmgt.member ORDER BY name;"; + $stmt = $this->dbh->prepare($sql); + $stmt->execute(); + $membersList = $stmt->fetchAll(PDO::FETCH_ASSOC); + + while( list($key, $val) = each( $membersList ) ) { + $membersList[$key]['name'] = addslashes($val['name']); + } + + // Get full list of Teams + $sql = "SELECT id, name FROM eventmgt.team ORDER BY name;"; + $stmt = $this->dbh->prepare($sql); + $stmt->execute(); + $teamsList = $stmt->fetchAll(PDO::FETCH_ASSOC); + + while( list($key, $val) = each( $teamsList ) ) { + $teamsList[$key]['name'] = addslashes($val['name']); + } + + $searchLists = array( + 'events' => $eventsList, + 'teamList' => $teamsList, + 'members' => $membersList + ); + + if ($this->config->option->admin_debug) { + $this->adminDebug .= "

EventManagement.php: getSearchLists()

".print_r($searchLists,1)."

"; + } + + return $searchLists; + } + + /** + * Format a number as money + * + * @param $value Value to format + * @param $option Options that control output + * NOPREFIX stops the "$" prefix + * + * @return none + * @access public + */ + private function money($value, $option = "") + { + + if ($option == "NOPREFIX") + $prefix = ""; + else + $prefix = "$"; + + // Do value sanity check + + if (!is_numeric($value)) + return ($prefix."0.00"); + + return ($prefix.number_format($value, 2, ".", ",")); + } + + +} + +// Start Event Management Admin - Pass the site's global application config data +$eh = new EventManagementAdminIndexController($GLOBALS['applicationConfig'], $GLOBALS['serverConfig'], $GLOBALS['siteConfig']); + +// If this is an admin user initial entry or if this is an admin user login +if (!(defined('SHOW_IN_SITE') && SHOW_IN_SITE)) { + exit; +} + + + +?> diff --git a/controllers/FrontController.php b/controllers/FrontController.php new file mode 100644 index 0000000..66f9e6d --- /dev/null +++ b/controllers/FrontController.php @@ -0,0 +1,909 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: FrontController.php,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +/* + +Custom Index file + {GLM} is replaced with a template include file that calls the selected template. + +If custom index + + base_url is /index.phtml - directly calls front-end controller + + Controller determines action and calls proper include file for that action + returns selected template file and data + + Controller + sets page->template parameter + calls custom index template + Template uses page-template parameter to include the target template. + +else + base_url is specified static page +end + +*/ + +/** + * EventManagementFrontIndexController class + * + * Event Management System - Front end main index + * + * PHP version 5 + * + * @category Reservations_Front_End + * @package EventManagement + * @author Chuck Scott + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: FrontController.php,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ +class EventManagementIndexController +{ + + /** + * Front End Support + * @var $frontDebug + * @access public + */ + public $support = false; + /** + * Debug Information + * @var $frontDebug + * @access public + */ + public $frontDebug = ''; + private $frontDebugMenu = ''; + /** + * Configuration information object + * @var $ini + * @access public + */ + public $config; + /** + * Database Object + * @var $dbh + * @access public + */ + public $dbh; + /** + * File/Image server adapter + * @var $isa + * @var $imageServer + * @access public + */ + public $isa; + public $imageServer; + /** + * Reason for any problems that come up + * @var unknown + * @access public + */ + public $reason = array(); + /** + * Have Cart + * @var $haveCart + * @access public + */ + public $haveCart = false; + /** + * Current Action + * Default is set to SelectConv + * @var $Action + * @access public + */ + public $Action = ''; + /** + * Template to use for output + * @var unknown + * @access public + */ + public $flexyOptions; + public $template; + private $page; + private $smarty; + /** + * User Interface + * @var unknown + * @access public + */ + private $userInterface = false; + private $interfaceType = false; + private $userInterfaces = false; + private $userInterfacesSelectable = false; + public $memberUser = false; + + private $resetSession = false; + /** + * Constructor + * + * @param object $d database connection + * + * @return void + * @access public + */ + public function __construct($applicationConfig, $serverConfig, $siteConfig) + { + + // Save config data and build a common config object + $this->applicationConfig = $applicationConfig; + $this->serverConfig = $serverConfig; + $this->siteConfig = $siteConfig; + $this->buildIntegratedConfig(); + + // Setup some required defines for this application + $this->setupDefines(); + + // Create database connection + $this->dbh = Toolkit_Database::getInstance(); + + // Set debug file name + if ($this->config->option->front_debug) { + define('DEBUG_DATA_FILENAME', '/tmp/EventManagement.'.$_SERVER['REMOTE_ADDR'].'.debug.html'); + } + + // Provide front-end support class + require_once EVENT_MANAGEMENT_APP_BASE.'models/front/classes/support.php'; + $this->support = new EventManagementFrontSupport($this->dbh, $this->config); + + // start this user session + $this->startSession(); + + // User interface selection + $this->userInterfaceSelection(); + + // Setup page and template configurations and add some standard page data + $this->setupTemplate(); + + // Perform requested action and add this to debug + $this->performAction(); + + // Display Output + $this->displayOutput(); + + // Check if we need to clear the session + if ($this->resetSession) { + $this->startSession(true); + } + + // Output debug information if that's enabled + $this->displayDebug(); + + // If this is a debug output page then stop here. + if (substr($this->Action,0,6) == 'Debug_') { + exit; + } + + } // _constructor + + /** + * Assemble all required config data into $this->config + * + * @return void + */ + private function buildIntegratedConfig() + { + + // Set common apps base location + define('COMMON_APP_BASE', '/var/www/server/CommonApps/'); + + // Get customer's config for this application and Merge in customer's main application.ini + $this->config = new Zend_Config_Ini( + BASE_PATH.'config/applications/EventManagement.ini', + strtolower($_ENV['GLM_HOST_ID']), + array('allowModifications' => true) + ); + $this->config->merge($this->applicationConfig->event_management); + $this->config->owner = $this->siteConfig->owner; + $this->config->file_server = $this->serverConfig->file_server; + + // Set location for this application + define('EVENT_MANAGEMENT_APP_BASE', COMMON_APP_BASE.$this->config->version.'/'); + + // Get common configuration for this application + $EMconfig = new Zend_Config_Ini( + EVENT_MANAGEMENT_APP_BASE.'configs/common.ini', + strtolower($_ENV['GLM_HOST_ID']), + array('allowModifications' => true) + ); + $this->config->merge($EMconfig); + + } + + /** + * Set system defines + * + * @return void + */ + private function setupDefines() + { + // Set datestyle string for DB results + define('DATE_STYLE_STRING', $this->config->misc->datestyle ); + + // Set common apps base location + define('DATA_ABSTRACT', COMMON_APP_BASE.'CommonAbstracts/'.$this->config->dataAbstractLocation.'/DataAbstract.php'); + define('PDF_ABSTRACT', COMMON_APP_BASE.'CommonAbstracts/'.$this->config->pdfAbstractLocation.'/GlmPdf.php'); + define('IMAGE_SERVER_ABSTRACT', COMMON_APP_BASE.'CommonAbstracts/'.$this->config->imageServerAbstractLocation.'/Server.php'); + + define('GLM_EVENT_SESSION', 'GLM_EVENT_MGT_FRONT'); + + // Also set a defined parameter for access to the File/Image Server + define('IMAGE_SERVER_PREFIX', $this->config->file_server->secure.$this->config->file_server->owner_id.'/'); + + // Set base script - If there's an application URL defined, use that, otherwise use page ID + $baseApplicationScript = ($this->config->application_url != '' ? + CURRENT_BASE_URL.$this->config->application_url.'/?x=1' : + CURRENT_BASE_URL.'index.php?catid='.$this->config->application_page + ); + define('BASE_APPLICATION_SCRIPT', $baseApplicationScript); + + // Set base URL + $baseApplicationUrl = ($this->config->application_page == 0 ? + $baseScript : + CURRENT_BASE_URL.'common/EventManagement/' + ); + define('BASE_APPLICATION_URL', $baseApplicationUrl); + + } + + /** + * Destroy Event Management Front-end Session + * + * @return object containing array as sub-objects + */ + function destroySession() + { + unset($_SESSION[GLM_EVENT_SESSION]); + return; + } + + /** + * Start Session + * + * @return object containing array as sub-objects + */ + function startSession($force = false) + { + + // If we haven't started sessions yet + if (!isset($_SESSION)) { + session_start(); + } + + // Use "session_reset=true" in link to force a reset + if ($_REQUEST['session_reset'] == 'true') { + $force = true; + } + + // If the session timeout has past then reset session + if ($_SESSION[GLM_EVENT_SESSION]['timeOut'] < time()) { + + $force = true; + + // Only notify the user if the session has timed out in the last hour + if (time() - $_SESSION[GLM_EVENT_SESSION]['timeOut'] < 60*60 ) { + $this->reason[] = 'Your user session has timed out due to inactivity and your cart has been cleared.'; + } + + // If not adding items to cart or starting with sectionSelect, reset Action + if ($_REQUEST['Action'] != 'Shop_sectionSelect' && $_REQUEST['cart'] != 'add') { + $this->Action = 'Shop_start'; + } + + } + + // If requested or not yet set, create a clean GLM_HOUSING session array + if ($force || !isset($_SESSION[GLM_EVENT_SESSION])) { + + // But save interface + $this->userInterface = $_SESSION[GLM_EVENT_SESSION]['Interface']; + + // If full reset then clear this also + if ($force) { + $this->userInterface = false; + } + + // create GLM_HOUSING session with all parameters false + $_SESSION[GLM_EVENT_SESSION] = array( + 'SessionID' => md5(($_SERVER["REMOTE_ADDR"].'-'.time())), + 'PseudoRand' => false, + 'permitInactive' => $this->permitInactive, + 'timeOut' => false, + 'Event' => false, + 'Member' => false, + 'Accom' => false, + 'Inven' => false, + 'Team' => false, + 'Booking' => false, + 'Reservation' => false, + 'State' => false, + 'Division' => false, + 'Contact' => false, + 'Entrance' => false, + 'Section' => false, + 'Performance' => false, + 'Ticket' => false, + 'TicketInventory' => false, + 'Interface' => $this->userInterface, + 'Search' => false, + 'Cart' => false, + 'CartIndex' => 0, + 'OptServCart' => false, + 'TicketCart' => false, + 'ContactInput' => false, + 'TicketPayments' => false, + 'AdminUser' => false + ); + + // Initialze Cart + $this->clearCart(); + + $this->addDebug("startSession()", 'Session Reset', false); + + } + + // Reset session timeout to current time plus timeout length in minutes + $_SESSION[GLM_EVENT_SESSION]['timeOut'] = strtotime('now +'.$this->config->session_timeout.' minutes'); + + // Now let's check for an admin login user who might have more privileges than a normal front-end user + if (isset($_REQUEST['adminUserCheck']) && $_REQUEST['adminUserCheck'] != '') { + +/* Temporarily bypassed due to issues with office computer Check Failures. + // Check admin user ID and check string + $check = md5($this->config->orderVerificationSecret.$_SERVER['REMOTE_ADDR'].date('m/d/Y')); + if ($_REQUEST['adminUserCheck'] != $check) { + echo "Check failure:"; + exit; + } +*/ + + $_SESSION[GLM_EVENT_SESSION]['AdminUser'] = true; + } + + $this->addDebug('startSession()', 'Session timeout at: '.date('r', $_SESSION[GLM_EVENT_SESSION]['timeOut']).' ('.$_SESSION[GLM_EVENT_SESSION]['timeOut'].')'); + + + } + + /** + * User Interface selection (template dir) + * + * @return void + */ + private function userInterfaceSelection() + { + + // Is there a request for a specific interface + if (isset($_REQUEST['interface']) && + in_array($_REQUEST['interface'], $this->config->front_interface->toArray()) + ) { + $this->userInterface = $_REQUEST['interface']; + // Oherwise, do we have an interface selection in the user session? + } elseif (isset($_SESSION[GLM_EVENT_SESSION]['Interface']) && $_SESSION[GLM_EVENT_SESSION]['Interface'] != '') { + $this->userInterface = $_SESSION[GLM_EVENT_SESSION]['Interface']; + // If neither, then use default user interface. + } else { + $this->userInterface = $this->config->default_front_interface; + } + + // Update session with current user interface + $_SESSION[GLM_EVENT_SESSION]['Interface'] = $this->userInterface; + + // Get interface type (flexy or smarty) + $this->interfaceType = $this->config->front_interface_type->{$this->userInterface}; + + // Provide list of user interfaces to page + $interfaces = $this->config->front_interface->toArray(); + $userInterfaces = array(); + foreach ($interfaces as $i) { + $userInterfaces[] = array( + 'directory' => $i, + 'name' => $i, + 'selected' => ($i == $interface) + ); + } + + // If there's more than 1 user interface then tell the template to display user interface selection + $this->userInterfacesSelectable = ($this->config->front_interface->selectable && count($interfaces) > 1); + $this->userInterfaces = $this->bindArrayToObject($userInterfaces); + + $this->addDebug("userInterfaceSelection()", $this->userInterface.' (template engine: '.$this->interfaceType.')', false); + + } + + /** + * Set template configuration + * + * @return void + */ + private function setupTemplate() + { + + // Test if there is a local templates directory for the Web site + if (is_dir(BASE_PATH.'admin/EventManagement/templates')) { + $templatesDir = BASE_PATH.'admin/EventManagement/templates/front/'; + } else { + // Otherwise use the templates in this app + $templatesDir = EVENT_MANAGEMENT_APP_BASE.'views/front/'; + } + + switch ($this->interfaceType) { + + case 'smarty': + + // Load Smarty class and create instance + require(COMMON_APP_BASE.'Smarty/3.1/Smarty.class.php'); + $this->smarty = new Smarty(); + + // Setup required Smarty paths + $this->smarty->setTemplateDir($templatesDir); + $this->smarty->setCompileDir(BASE_PATH.'/smarty/templates_c'); + $this->smarty->setCacheDir(BASE_PATH.'/smarty/cache'); + $this->smarty->setConfigDir(BASE_PATH.'/smarty/configs'); + + break; + + case 'flexy': + // Setup Template and Page + $this->flexyOptions = array( + 'templateDir' => $templatesDir, + 'compileDir' => BASE_PATH.'/templates/compiled', + 'forceCompile' => false, + 'flexyIgnore' => true, + 'allowPHP' => true, + 'debug' => false + ); + $this->template = new HTML_Template_Flexy($this->flexyOptions); + $this->page = new stdClass(); + + break; + } + + // Get misc system configuration data for use below + require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/misc.php'; + $Misc = new EventManagementAdminMisc($this->dbh, $this->config); + $miscConfigDetail = $Misc->getEntry(1); + + // Get some standard page data + $this->templateAssign( + array( + + 'owner' => $this->bindArrayToObject($this->config->owner->toArray()), + + 'startScript' => ' + '; + + } + + } + + /* + * Assign parameters to the template + * + * @param array Array of arrays with parameter name, value pairs + * or + * @param text parameter name + * @param {whatever} parameter value + * + * @return void + */ + private function templateAssign($params, $value = false) + { + + // If this is a single assignment + if ($value != false) { + + switch ($this->interfaceType) { + case 'smarty': + $this->smarty->assign($param, $value); + break; + case 'flexy': + $this->page->{$params} = $value; + break; + } + + // Otherwise it's an array of parameter/value pairs + } else { + + while (list($key, $value) = each($params)) { + + switch ($this->interfaceType) { + case 'smarty': + $this->smarty->assign($key, $value); + break; + case 'flexy': + $this->page->{$key} = $value; + break; + } + + } + + } + + } + + /** + * If debug for mail turned on, display E-Mail messages rather than send them + * + * @access public + */ + public function debug_mail( $to, $subject, $message, $headers = '', $parameters = '' ) + { + if( $this->config->debug->mail ) + { + $mailDebug = '

+ + + + + + + +
MAIL DEBUG
Recipient(s): '.$to.'
Subject: '.$subject.'
Headers:
'.$headers.'
Parameters:
'.$parameters.'
Message Content:
'.$message.'
+

+ '; + + // If front-debug is enabled, display in debug window + if ($this->config->option->front_debug) { + $this->addDebug('Email Message', $subject, $mailDebug, true); + } else { + // Otherwise display in-line. + echo $mailDebug; + } + + return( true ); + } else { + return( mail( $to, $subject, $message, $headers, $parameters ) ); + } + } + + + + +} // EventManagementIndexController + +// Start Event Management Front-End - Pass the site's global application config data +//$eh = new EventManagementIndexController($applicationConfig, $serverConfig); +//exit; + +?> diff --git a/data/DatabaseModificationsForTicketing.sql b/data/DatabaseModificationsForTicketing.sql new file mode 100644 index 0000000..93f3931 --- /dev/null +++ b/data/DatabaseModificationsForTicketing.sql @@ -0,0 +1,2 @@ + +Updates to database required for current updates diff --git a/data/EventManagement.sql b/data/EventManagement.sql new file mode 100644 index 0000000..c57b235 --- /dev/null +++ b/data/EventManagement.sql @@ -0,0 +1,1183 @@ +CREATE SCHEMA eventmgt; + +ALTER SCHEMA eventmgt OWNER TO postgres; +GRANT ALL ON SCHEMA eventmgt TO nobody; + +CREATE TABLE eventmgt.misc +( + id integer, + intro_text text, + section_text text, + ticket_text text, + ticket_opt_text text, + cart_text text, + checkout_text text, + success_text text, + tracking text, + no_payment_reasons text, + opt_field_1_name text, + opt_field_2_name text, + opt_field_3_name text, + central_payment smallint +); + +ALTER TABLE eventmgt.misc OWNER TO postgres; +REVOKE ALL ON TABLE eventmgt.misc FROM PUBLIC; +REVOKE ALL ON TABLE eventmgt.misc FROM postgres; +GRANT ALL ON TABLE eventmgt.misc TO postgres; +GRANT ALL ON TABLE eventmgt.misc TO nobody; + +INSERT INTO eventmgt.misc + (id, intro_text, section_text, ticket_text, ticket_opt_text, cart_text, checkout_text, success_text, central_payment) + VALUES + (1, 'Intro text', 'Section selection text', 'Ticket selection text', 'Ticket option selection text', 'Cart text', 'Checkout text', 'Checkout success text', 0); + + +CREATE TABLE eventmgt.fees +( +id SERIAL, +affiliation_type smallint, +owner smallint, +fee_method smallint, +room_specific bool, +name text, +fee_amount float, +taxable bool, +itemize bool, +event_specific bool, +event smallint, +optional_service bool, +service_quant bool, +service_max_quant smallint, +descr text +); + +ALTER TABLE eventmgt.fees OWNER TO postgres; +REVOKE ALL ON TABLE eventmgt.fees FROM PUBLIC; +REVOKE ALL ON TABLE eventmgt.fees FROM postgres; +GRANT ALL ON TABLE eventmgt.fees TO postgres; +GRANT ALL ON TABLE eventmgt.fees TO nobody; +GRANT ALL ON TABLE eventmgt.fees_id_seq TO postgres; +GRANT ALL ON TABLE eventmgt.fees_id_seq TO nobody; + +CREATE INDEX fees_id_index ON eventmgt.fees ( id ); +CREATE INDEX fees_owner_index ON eventmgt.fees ( owner ); + +CREATE TABLE eventmgt.division + ( + id SERIAL, + event integer, + name text, + descr text, + notes text + ); + +ALTER TABLE eventmgt.division OWNER TO postgres; +REVOKE ALL ON TABLE eventmgt.division FROM PUBLIC; +REVOKE ALL ON TABLE eventmgt.division FROM postgres; +GRANT ALL ON TABLE eventmgt.division TO postgres; +GRANT ALL ON TABLE eventmgt.division TO nobody; +GRANT ALL ON TABLE eventmgt.division_id_seq TO postgres; +GRANT ALL ON TABLE eventmgt.division_id_seq TO nobody; + +CREATE INDEX division_id_index ON eventmgt.division ( id ); +CREATE INDEX division_event_index ON eventmgt.division ( event ); + +CREATE TABLE eventmgt.state_rep + ( + id SERIAL, + event integer, + code text, + password text, + descr text, + notes text + ); + +ALTER TABLE eventmgt.state_rep OWNER TO postgres; +REVOKE ALL ON TABLE eventmgt.state_rep FROM PUBLIC; +REVOKE ALL ON TABLE eventmgt.state_rep FROM postgres; +GRANT ALL ON TABLE eventmgt.state_rep TO postgres; +GRANT ALL ON TABLE eventmgt.state_rep TO nobody; +GRANT ALL ON TABLE eventmgt.state_rep_id_seq TO postgres; +GRANT ALL ON TABLE eventmgt.state_rep_id_seq TO nobody; + +CREATE INDEX state_rep_id_index ON eventmgt.state_rep ( id ); +CREATE INDEX state_rep_event_index ON eventmgt.state_rep ( event ); + + +CREATE TABLE eventmgt.room_block + ( + id SERIAL, + event integer, + state_rep integer, + team integer, + member integer, + block_name integer + ); + +ALTER TABLE eventmgt.room_block OWNER TO postgres; +REVOKE ALL ON TABLE eventmgt.room_block FROM PUBLIC; +REVOKE ALL ON TABLE eventmgt.room_block FROM postgres; +GRANT ALL ON TABLE eventmgt.room_block TO postgres; +GRANT ALL ON TABLE eventmgt.room_block TO nobody; +GRANT ALL ON TABLE eventmgt.room_block_id_seq TO postgres; +GRANT ALL ON TABLE eventmgt.room_block_id_seq TO nobody; + +CREATE INDEX room_block_id_index ON eventmgt.room_block ( id ); +CREATE INDEX room_block_event_index ON eventmgt.room_block ( event ); +CREATE INDEX room_block_state_rep_index ON eventmgt.room_block ( state_rep ); +CREATE INDEX room_block_team_index ON eventmgt.room_block ( team ); +CREATE INDEX room_block_member_index ON eventmgt.room_block ( member ); + + +CREATE TABLE eventmgt.room_block_seg + ( + id SERIAL, + block integer, + event integer, + accommodation integer, + allocated smallint, + available smallint + ); + +ALTER TABLE eventmgt.room_block_seg OWNER TO postgres; +REVOKE ALL ON TABLE eventmgt.room_block_seg FROM PUBLIC; +REVOKE ALL ON TABLE eventmgt.room_block_seg FROM postgres; +GRANT ALL ON TABLE eventmgt.room_block_seg TO postgres; +GRANT ALL ON TABLE eventmgt.room_block_seg TO nobody; +GRANT ALL ON TABLE eventmgt.room_block_seg_id_seq TO postgres; +GRANT ALL ON TABLE eventmgt.room_block_seg_id_seq TO nobody; + +CREATE INDEX room_block_seg_id_index ON eventmgt.room_block_seg ( id ); +CREATE INDEX room_block_seg_block_index ON eventmgt.room_block_seg ( block ); +CREATE INDEX room_block_seg_event_index ON eventmgt.room_block_seg ( event ); +CREATE INDEX room_block_seg_accommodation_index ON eventmgt.room_block_seg ( accommodation ); + + +CREATE TABLE eventmgt.team + ( + id SERIAL, + event integer, + division integer, + state integer, + name text, + team_code text, + participants smallint, + room_block integer, + notes text + ); + +ALTER TABLE eventmgt.team OWNER TO postgres; +REVOKE ALL ON TABLE eventmgt.team FROM PUBLIC; +REVOKE ALL ON TABLE eventmgt.team FROM postgres; +GRANT ALL ON TABLE eventmgt.team TO postgres; +GRANT ALL ON TABLE eventmgt.team TO nobody; +GRANT ALL ON TABLE eventmgt.team_id_seq TO postgres; +GRANT ALL ON TABLE eventmgt.team_id_seq TO nobody; + +CREATE INDEX team_id_index ON eventmgt.team ( id ); +CREATE INDEX team_code_index ON eventmgt.team ( team_code ); +CREATE INDEX team_event_index ON eventmgt.team ( event ); + + +CREATE TABLE eventmgt.team_roster + ( + id SERIAL, + team integer, + lname text, + fname text, + pos text, + notes text + ); + +ALTER TABLE eventmgt.team_roster OWNER TO postgres; +REVOKE ALL ON TABLE eventmgt.team_roster FROM PUBLIC; +REVOKE ALL ON TABLE eventmgt.team_roster FROM postgres; +GRANT ALL ON TABLE eventmgt.team_roster TO postgres; +GRANT ALL ON TABLE eventmgt.team_roster TO nobody; +GRANT ALL ON TABLE eventmgt.team_roster_id_seq TO postgres; +GRANT ALL ON TABLE eventmgt.team_roster_id_seq TO nobody; + +CREATE INDEX team_roster_id_index ON eventmgt.team_roster ( id ); +CREATE INDEX team_roster_team_index ON eventmgt.team_roster ( team ); + + + +CREATE TABLE eventmgt.team_property + ( + id SERIAL, + team integer, + property integer, + event integer, + start date, + stop date + ); + +ALTER TABLE eventmgt.team_property OWNER TO postgres; +REVOKE ALL ON TABLE eventmgt.team_property FROM PUBLIC; +REVOKE ALL ON TABLE eventmgt.team_property FROM postgres; +GRANT ALL ON TABLE eventmgt.team_property TO postgres; +GRANT ALL ON TABLE eventmgt.team_property TO nobody; +GRANT ALL ON TABLE eventmgt.team_property_id_seq TO postgres; +GRANT ALL ON TABLE eventmgt.team_property_id_seq TO nobody; + +CREATE INDEX team_property_id_index ON eventmgt.team_property ( id ); +CREATE INDEX team_property_team_id_index ON eventmgt.team_property ( team ); +CREATE INDEX team_property_property_id_index ON eventmgt.team_property ( property ); +CREATE INDEX team_property_event_id_index ON eventmgt.team_property ( event ); + + +CREATE TABLE eventmgt.accommodation + ( + id SERIAL, + member integer, + name text, + title text, + category smallint, + descr text, + image text, + quant integer, + occupants smallint, + maxoccupants smallint, + sort smallint + ); + +ALTER TABLE eventmgt.accommodation OWNER TO postgres; +REVOKE ALL ON TABLE eventmgt.accommodation FROM PUBLIC; +REVOKE ALL ON TABLE eventmgt.accommodation FROM postgres; +GRANT ALL ON TABLE eventmgt.accommodation TO postgres; +GRANT ALL ON TABLE eventmgt.accommodation TO nobody; +GRANT ALL ON TABLE eventmgt.accommodation_id_seq TO postgres; +GRANT ALL ON TABLE eventmgt.accommodation_id_seq TO nobody; + +CREATE INDEX accommodation_id_index ON eventmgt.accommodation (id); +CREATE INDEX accommodation_member_index ON eventmgt.accommodation (member); + +CREATE TABLE eventmgt.entrance + ( + id SERIAL, + member integer, + name text, + addr1 text, + addr2 text, + city text, + state text, + country text, + zip text, + phone text, + lat float, + lon float, + descr text, + image text, + color text, + notes text, + sort smallint + ); + +ALTER TABLE eventmgt.entrance OWNER TO postgres; +REVOKE ALL ON TABLE eventmgt.entrance FROM PUBLIC; +REVOKE ALL ON TABLE eventmgt.entrance FROM postgres; +GRANT ALL ON TABLE eventmgt.entrance TO postgres; +GRANT ALL ON TABLE eventmgt.entrance TO nobody; +GRANT ALL ON TABLE eventmgt.entrance_id_seq TO postgres; +GRANT ALL ON TABLE eventmgt.entrance_id_seq TO nobody; + +CREATE INDEX entrance_id_index ON eventmgt.entrance (id); +CREATE INDEX entrance_member_index ON eventmgt.entrance (member); +CREATE INDEX entrance_sort_index ON eventmgt.entrance (sort); + +CREATE TABLE eventmgt.section + ( + id SERIAL, + member integer, + name text, + descr text, + image text, + entrance integer, + notes text, + sort smallint + ); + +ALTER TABLE eventmgt.section OWNER TO postgres; +REVOKE ALL ON TABLE eventmgt.section FROM PUBLIC; +REVOKE ALL ON TABLE eventmgt.section FROM postgres; +GRANT ALL ON TABLE eventmgt.section TO postgres; +GRANT ALL ON TABLE eventmgt.section TO nobody; +GRANT ALL ON TABLE eventmgt.section_id_seq TO postgres; +GRANT ALL ON TABLE eventmgt.section_id_seq TO nobody; + +CREATE INDEX section_id_index ON eventmgt.section (id); +CREATE INDEX section_member_index ON eventmgt.section (member); +CREATE INDEX section_sort_index ON eventmgt.section (sort); + +CREATE TABLE eventmgt.performance + ( + id SERIAL, + member smallint, + name text, + active boolean, + admin_only boolean, + descr text, + short_descr text, + start_date date, + end_date date, + purch_leadtime smallint, + image text, + policy text, + voucher_text text, + conf_text text, + notes text, + promote_in_cart boolean, + sort smallint + ); + +ALTER TABLE eventmgt.performance OWNER TO postgres; +REVOKE ALL ON TABLE eventmgt.performance FROM PUBLIC; +REVOKE ALL ON TABLE eventmgt.performance FROM postgres; +GRANT ALL ON TABLE eventmgt.performance TO postgres; +GRANT ALL ON TABLE eventmgt.performance TO nobody; +GRANT ALL ON TABLE eventmgt.performance_id_seq TO postgres; +GRANT ALL ON TABLE eventmgt.performance_id_seq TO nobody; + +CREATE INDEX performance_id_index ON eventmgt.performance (id); +CREATE INDEX performance_member_index ON eventmgt.performance (member); +CREATE INDEX performance_sort_index ON eventmgt.performance (sort); + +CREATE TABLE eventmgt.ticket + ( + id SERIAL, + active boolean, + admin_only boolean, + ticket_type integer, + member integer, + name text, + title text, + section smallint, + date_specific boolean, + days_of_week integer, + start_date date, + end_date date, + time_specific boolean, + ticket_time time, + unlimited_use boolean, + uses smallint, + performance smallint, + unlimited_quant boolean, + quant integer, + consignment_type smallint, + cart_sticky boolean, + show_on_start boolean, + price float, + descr text, + image text, + voucher_text text, + voucher_type integer, + sort smallint + ); + +ALTER TABLE eventmgt.ticket OWNER TO postgres; +REVOKE ALL ON TABLE eventmgt.ticket FROM PUBLIC; +REVOKE ALL ON TABLE eventmgt.ticket FROM postgres; +GRANT ALL ON TABLE eventmgt.ticket TO postgres; +GRANT ALL ON TABLE eventmgt.ticket TO nobody; +GRANT ALL ON TABLE eventmgt.ticket_id_seq TO postgres; +GRANT ALL ON TABLE eventmgt.ticket_id_seq TO nobody; + +CREATE INDEX ticket_id_index ON eventmgt.ticket (id); +CREATE INDEX ticket_member_index ON eventmgt.ticket (member); +CREATE INDEX ticket_section_index ON eventmgt.ticket (section); + +CREATE TABLE eventmgt.ticket_package + ( + id SERIAL, + package integer, + ticket integer, + member integer, + performance integer, + quant integer, + sort smallint + ); + +ALTER TABLE eventmgt.ticket_package OWNER TO postgres; +REVOKE ALL ON TABLE eventmgt.ticket_package FROM PUBLIC; +REVOKE ALL ON TABLE eventmgt.ticket_package FROM postgres; +GRANT ALL ON TABLE eventmgt.ticket_package TO postgres; +GRANT ALL ON TABLE eventmgt.ticket_package TO nobody; +GRANT ALL ON TABLE eventmgt.ticket_package_id_seq TO postgres; +GRANT ALL ON TABLE eventmgt.ticket_package_id_seq TO nobody; + +CREATE INDEX ticket_package_id_index ON eventmgt.ticket_package (id); +CREATE INDEX ticket_package_package_index ON eventmgt.ticket_package (package); +CREATE INDEX ticket_package_ticket_index ON eventmgt.ticket_package (ticket); + +CREATE TABLE eventmgt.member_scans_for + ( + id SERIAL, + member integer, + scans_for integer + ); + +ALTER TABLE eventmgt.member_scans_for OWNER TO postgres; +REVOKE ALL ON TABLE eventmgt.member_scans_for FROM PUBLIC; +REVOKE ALL ON TABLE eventmgt.member_scans_for FROM postgres; +GRANT ALL ON TABLE eventmgt.member_scans_for TO postgres; +GRANT ALL ON TABLE eventmgt.member_scans_for TO nobody; +GRANT ALL ON TABLE eventmgt.member_scans_for_id_seq TO postgres; +GRANT ALL ON TABLE eventmgt.member_scans_for_id_seq TO nobody; + +CREATE INDEX member_scans_for_id_index ON eventmgt.member_scans_for (id); +CREATE INDEX member_scans_for_member_index ON eventmgt.member_scans_for (member); +CREATE INDEX member_scans_for_scans_for_index ON eventmgt.member_scans_for (scans_for); + + +CREATE TABLE eventmgt.ticket_inventory + ( + id SERIAL, + ticket integer, + member integer, + quant integer, + available integer, + sold integer, + ticket_date date, + ticket_time time, + active boolean + ); + +ALTER TABLE eventmgt.ticket_inventory OWNER TO postgres; +REVOKE ALL ON TABLE eventmgt.ticket_inventory FROM PUBLIC; +REVOKE ALL ON TABLE eventmgt.ticket_inventory FROM postgres; +GRANT ALL ON TABLE eventmgt.ticket_inventory TO postgres; +GRANT ALL ON TABLE eventmgt.ticket_inventory TO nobody; +GRANT ALL ON TABLE eventmgt.ticket_inventory_id_seq TO postgres; +GRANT ALL ON TABLE eventmgt.ticket_inventory_id_seq TO nobody; + +CREATE INDEX ticket_inventory_id_index ON eventmgt.ticket_inventory (id); +CREATE INDEX ticket_inventory_ticket_index ON eventmgt.ticket_inventory (ticket); +CREATE INDEX ticket_inventory_member_index ON eventmgt.ticket_inventory (member); +CREATE INDEX ticket_inventory_date_index ON eventmgt.ticket_inventory (ticket_date); + +CREATE TABLE eventmgt.ticket_add_on + ( + id SERIAL, + ticket integer, + name text, + descr text, + add_on_type integer, + max_quant integer, + unit_name text, + unit_cost float + ); + +ALTER TABLE eventmgt.ticket_add_on OWNER TO postgres; +REVOKE ALL ON TABLE eventmgt.ticket_add_on FROM PUBLIC; +REVOKE ALL ON TABLE eventmgt.ticket_add_on FROM postgres; +GRANT ALL ON TABLE eventmgt.ticket_add_on TO postgres; +GRANT ALL ON TABLE eventmgt.ticket_add_on TO nobody; +GRANT ALL ON TABLE eventmgt.ticket_add_on_id_seq TO postgres; +GRANT ALL ON TABLE eventmgt.ticket_add_on_id_seq TO nobody; + +CREATE INDEX ticket_add_on_id_index ON eventmgt.ticket_add_on (id); +CREATE INDEX ticket_add_on_ticket_index ON eventmgt.ticket_add_on (ticket); + +CREATE TABLE eventmgt.promo_code + ( + id SERIAL, + name text, + long_name text, + descr text, + start_date date, + end_date date, + notes text + ); + +ALTER TABLE eventmgt.promo_code OWNER TO postgres; +REVOKE ALL ON TABLE eventmgt.promo_code FROM PUBLIC; +REVOKE ALL ON TABLE eventmgt.promo_code FROM postgres; +GRANT ALL ON TABLE eventmgt.promo_code TO postgres; +GRANT ALL ON TABLE eventmgt.promo_code TO nobody; +GRANT ALL ON TABLE eventmgt.promo_code_id_seq TO postgres; +GRANT ALL ON TABLE eventmgt.promo_code_id_seq TO nobody; + +CREATE INDEX promo_code_id_index ON eventmgt.promo_code (id); +CREATE INDEX promo_code_start_date_index ON eventmgt.promo_code (start_date); +CREATE INDEX promo_code_end_date_index ON eventmgt.promo_code (end_date); + +CREATE TABLE eventmgt.promo_ticket + ( + id SERIAL, + promo integer, + ticket integer, + promo_type integer, + amount float, + notes text + ); + +ALTER TABLE eventmgt.promo_ticket OWNER TO postgres; +REVOKE ALL ON TABLE eventmgt.promo_ticket FROM PUBLIC; +REVOKE ALL ON TABLE eventmgt.promo_ticket FROM postgres; +GRANT ALL ON TABLE eventmgt.promo_ticket TO postgres; +GRANT ALL ON TABLE eventmgt.promo_ticket TO nobody; +GRANT ALL ON TABLE eventmgt.promo_ticket_id_seq TO postgres; +GRANT ALL ON TABLE eventmgt.promo_ticket_id_seq TO nobody; + +CREATE INDEX promo_ticket_id_index ON eventmgt.promo_ticket (id); +CREATE INDEX promo_ticket_ticket_index ON eventmgt.promo_ticket (ticket); + +CREATE TABLE eventmgt.room_detail + ( + id SERIAL, + member integer, + accommodation integer, + occupants smallint, + room_type smallint, + bath_type smallint, + pullout_beds smallint, + single_beds smallint, + double_beds smallint, + queen_beds smallint, + king_beds smallint, + tv bool, + fridge bool, + safe bool, + descr text, + image text, + sort smallint + ); + +ALTER TABLE eventmgt.room_detail OWNER TO postgres; +REVOKE ALL ON TABLE eventmgt.room_detail FROM PUBLIC; +REVOKE ALL ON TABLE eventmgt.room_detail FROM postgres; +GRANT ALL ON TABLE eventmgt.room_detail TO postgres; +GRANT ALL ON TABLE eventmgt.room_detail TO nobody; +GRANT ALL ON TABLE eventmgt.room_detail_id_seq TO postgres; +GRANT ALL ON TABLE eventmgt.room_detail_id_seq TO nobody; + +CREATE INDEX room_detail_id_index ON eventmgt.room_detail (id); +CREATE INDEX room_detail_member_index ON eventmgt.room_detail (member); +CREATE INDEX room_detail_accom_index ON eventmgt.room_detail (accommodation); + + +CREATE TABLE eventmgt.res_contact + ( + id SERIAL, + contact_type int, + affiliation int, + fname text, + lname text, + org text, + addr1 text, + addr2 text, + city text, + state text, + country text, + zip text, + org_url text, + office_phone text, + mobile_phone text, + alt_phone text, + fax text, + email text, + login_id text, + alt_email text, + image text, + notes text, + create_date date, + active bool, + password text, + user_rights int + ); + +ALTER TABLE eventmgt.res_contact OWNER TO postgres; +REVOKE ALL ON TABLE eventmgt.res_contact FROM PUBLIC; +REVOKE ALL ON TABLE eventmgt.res_contact FROM postgres; +GRANT ALL ON TABLE eventmgt.res_contact TO postgres; +GRANT ALL ON TABLE eventmgt.res_contact TO nobody; +GRANT ALL ON TABLE eventmgt.res_contact_id_seq TO postgres; +GRANT ALL ON TABLE eventmgt.res_contact_id_seq TO nobody; + +CREATE INDEX res_contact_id_index ON eventmgt.res_contact (id); +CREATE INDEX res_contact_affiliation_index ON eventmgt.res_contact (affiliation); +CREATE INDEX res_contact_city_index ON eventmgt.res_contact (city); +CREATE INDEX res_contact_email_index ON eventmgt.res_contact (email); +CREATE INDEX res_contact_fname_index ON eventmgt.res_contact (fname); +CREATE INDEX res_contact_lname_index ON eventmgt.res_contact (lname); +CREATE INDEX res_contact_zip_index ON eventmgt.res_contact (zip); +CREATE INDEX res_contact_login_id_index ON eventmgt.res_contact (login_id); + + +CREATE TABLE eventmgt.event + ( + id SERIAL, + name text, + event_code text, + addr1 text, + addr2 text, + city text, + state text, + zip text, + country text, + descr text, + event_dates text, + active bool, + image text, + team_event bool, + days smallint, + start_date date, + end_date date, + cutoff_date date, + req_stay bool, + req_stay_arrive date, + req_stay_depart date, + req_stay_notice text, + open_res_date date, + conf_hours integer, + inven_hold_time integer, + sort smallint, + lat float, + lon float, + multiple_rooms bool, + max_rooms smallint, + cart_text text, + res_policy text, + can_policy text, + pmt_policy text, + res_msg text, + conf_msg text, + reserve_by_code bool, + central_payment bool, + central_payment_email text, + host_property smallint, + parking_image text, + parking_descr text + ); + +ALTER TABLE eventmgt.event OWNER TO postgres; +REVOKE ALL ON TABLE eventmgt.event FROM PUBLIC; +REVOKE ALL ON TABLE eventmgt.event FROM postgres; +GRANT ALL ON TABLE eventmgt.event TO postgres; +GRANT ALL ON TABLE eventmgt.event TO nobody; +GRANT ALL ON TABLE eventmgt.event_id_seq TO postgres; +GRANT ALL ON TABLE eventmgt.event_id_seq TO nobody; + +CREATE INDEX event_id_index ON eventmgt.event ( id ); +CREATE INDEX event_sort_index ON eventmgt.event ( sort ); + + +CREATE TABLE eventmgt.event_prop_dist + ( + id SERIAL, + event integer, + event_lat float, + event_lon float, + member integer, + memb_lat float, + memb_lon float, + summary text, + start_addr text, + end_addr text, + distance text, + duration text + ); + +ALTER TABLE eventmgt.event_prop_dist OWNER TO postgres; +REVOKE ALL ON TABLE eventmgt.event_prop_dist FROM PUBLIC; +REVOKE ALL ON TABLE eventmgt.event_prop_dist FROM postgres; +GRANT ALL ON TABLE eventmgt.event_prop_dist TO postgres; +GRANT ALL ON TABLE eventmgt.event_prop_dist TO nobody; +GRANT ALL ON TABLE eventmgt.event_prop_dist_id_seq TO postgres; +GRANT ALL ON TABLE eventmgt.event_prop_dist_id_seq TO nobody; + +CREATE INDEX event_prop_event_index ON eventmgt.event_prop_dist (event); +CREATE INDEX event_prop_member_index ON eventmgt.event_prop_dist (member); + + +CREATE TABLE eventmgt.inventory + ( + id SERIAL, + date date, + member integer, + accommodation integer, + event integer, + assigned smallint, + available smallint, + rate float, + add_person float, + room_block text, + res_policy text, + can_policy text, + min_nights integer, + descr text + ); + +ALTER TABLE eventmgt.inventory OWNER TO postgres; +REVOKE ALL ON TABLE eventmgt.inventory FROM PUBLIC; +REVOKE ALL ON TABLE eventmgt.inventory FROM postgres; +GRANT ALL ON TABLE eventmgt.inventory TO postgres; +GRANT ALL ON TABLE eventmgt.inventory TO nobody; +GRANT ALL ON TABLE eventmgt.inventory_id_seq TO postgres; +GRANT ALL ON TABLE eventmgt.inventory_id_seq TO nobody; + +CREATE INDEX inventory_id_index ON eventmgt.inventory ( id ); +CREATE INDEX inventory_date_index ON eventmgt.inventory ( date ); +CREATE INDEX inventory_member_index ON eventmgt.inventory ( member ); +CREATE INDEX inventory_accom_index ON eventmgt.inventory ( accommodation ); + + +CREATE TABLE eventmgt.inven_hold + ( + id SERIAL, + hold_type integer, + inventory integer, + quant integer, + expire_time timestamp, + session_id text + ); + +ALTER TABLE eventmgt.inven_hold OWNER TO postgres; +REVOKE ALL ON TABLE eventmgt.inven_hold FROM PUBLIC; +REVOKE ALL ON TABLE eventmgt.inven_hold FROM postgres; +GRANT ALL ON TABLE eventmgt.inven_hold TO postgres; +GRANT ALL ON TABLE eventmgt.inven_hold TO nobody; +GRANT ALL ON TABLE eventmgt.inven_hold_id_seq TO postgres; +GRANT ALL ON TABLE eventmgt.inven_hold_id_seq TO nobody; + +CREATE INDEX inven_hold_inventory_index ON eventmgt.inven_hold (inventory); +CREATE INDEX inven_hold_session_id_index ON eventmgt.inven_hold (session_id); + + +CREATE TABLE eventmgt.member + ( + id SERIAL, + member_type smallint, + name text, + descr text, + addr1 text, + addr2 text, + city text, + state text, + zip text, + country text, + lat float, + lon float, + active boolean, + cards_accepted smallint, + payment_gateway smallint, + gateway_par1 text, + gateway_par2 text, + gateway_par3 text, + gateway_par4 boolean, + gateway_par5 text, + paypal boolean, + paypal_client_id text, + paypal_secret text, + paypal_mode smallint, + image text, + parking_map text, + ticket_sec_map text, + ticket_spec_req boolean, + ticket_policy text, + intro_text text, + checkout_email text, + phone text, + email text, + proc_email text, + proc_email2 text, + checkout_notify boolean, + check_in time, + check_out time, + def_res_pol text, + def_can_pol text, + notes text, + amen_1 boolean, + amen_2 boolean, + amen_3 boolean, + amen_4 boolean, + amen_5 boolean, + amen_6 boolean, + amen_7 boolean, + amen_8 boolean, + amen_9 boolean, + amen_10 boolean, + def_ticket_pol text, + sort integer, + checkout_opt_1 text, + checkout_opt_2 text, + checkout_opt_3 text + ); + +ALTER TABLE eventmgt.member OWNER TO postgres; +REVOKE ALL ON TABLE eventmgt.member FROM PUBLIC; +REVOKE ALL ON TABLE eventmgt.member FROM postgres; +GRANT ALL ON TABLE eventmgt.member TO postgres; +GRANT ALL ON TABLE eventmgt.member TO nobody; +GRANT ALL ON TABLE eventmgt.member_id_seq TO postgres; +GRANT ALL ON TABLE eventmgt.member_id_seq TO nobody; + +CREATE INDEX member_id_index ON eventmgt.member ( id ); + +CREATE TABLE eventmgt.amenities + ( + id SERIAL, + affiliation_type smallint, + owner smallint, + name text, + quant int, + descr text + ); + +ALTER TABLE eventmgt.amenities OWNER TO postgres; +REVOKE ALL ON TABLE eventmgt.amenities FROM PUBLIC; +REVOKE ALL ON TABLE eventmgt.amenities FROM postgres; +GRANT ALL ON TABLE eventmgt.amenities TO postgres; +GRANT ALL ON TABLE eventmgt.amenities TO nobody; +GRANT ALL ON TABLE eventmgt.amenities_id_seq TO postgres; +GRANT ALL ON TABLE eventmgt.amenities_id_seq TO nobody; + +CREATE INDEX amenities_id_index ON eventmgt.amenities ( id ); +CREATE INDEX amenities_owner_index ON eventmgt.amenities ( owner ); + + +CREATE TABLE eventmgt.event_prop + ( + id SERIAL, + event integer, + property integer + ); + +ALTER TABLE eventmgt.event_prop OWNER TO postgres; +REVOKE ALL ON TABLE eventmgt.event_prop FROM PUBLIC; +REVOKE ALL ON TABLE eventmgt.event_prop FROM postgres; +GRANT ALL ON TABLE eventmgt.event_prop TO postgres; +GRANT ALL ON TABLE eventmgt.event_prop TO nobody; +GRANT ALL ON TABLE eventmgt.event_prop_id_seq TO postgres; +GRANT ALL ON TABLE eventmgt.event_prop_id_seq TO nobody; + +CREATE INDEX event_prop_event_id_index ON eventmgt.event_prop ( event ); +CREATE INDEX event_prop_property_id_index ON eventmgt.event_prop ( property ); + +CREATE TABLE eventmgt.reservation + ( + id SERIAL, + user_trace_info text, + fname text, + lname text, + org text, + team_id smallint, + state_rep smallint, + addr1 text, + addr2 text, + city text, + state text, + zip text, + country text, + phone text, + email text, + email_ok bool, + date_entered date, + arrive_date date, + nights smallint, + rooms smallint, + adults smallint, + team smallint, + member integer, + accommodation int, + room_block integer, + arrival text, + event smallint, + event_name text, + event_start date, + event_end date, + payby smallint, + cctype text, + ccnumber text, + expire text, + ccname text, + cccode text, + hotel_price float, + taxes float, + grand_total float, + confirmation smallint, + confirmed bool, + declined bool, + conf_numb text, + date_confirmed date, + conf_by text, + conf_message text, + special_needs text, + notes text, + res_detail text, + summary text + ); + +ALTER TABLE eventmgt.reservation OWNER TO postgres; +REVOKE ALL ON TABLE eventmgt.reservation FROM PUBLIC; +REVOKE ALL ON TABLE eventmgt.reservation FROM postgres; +GRANT ALL ON TABLE eventmgt.reservation TO postgres; +GRANT ALL ON TABLE eventmgt.reservation TO nobody; +GRANT ALL ON TABLE eventmgt.reservation_id_seq TO postgres; +GRANT ALL ON TABLE eventmgt.reservation_id_seq TO nobody; + +CREATE INDEX reservation_id_index ON eventmgt.reservation ( id ); +CREATE INDEX reservation_lname_index ON eventmgt.reservation ( lname ); +CREATE INDEX reservation_fname_index ON eventmgt.reservation ( fname ); +CREATE INDEX reservation_email_index ON eventmgt.reservation ( email ); +CREATE INDEX reservation_arrive_index ON eventmgt.reservation ( arrive_date ); + + +CREATE TABLE eventmgt.ticket_order + ( + id SERIAL, + user_trace_info text, + active boolean, + fname text, + lname text, + addr1 text, + addr2 text, + city text, + state text, + zip text, + country text, + phone text, + email text, + email_ok bool, + opt_field_1_name text, + opt_field_1 text, + opt_field_2_name text, + opt_field_2 text, + opt_field_3_name text, + opt_field_3 text, + purchase_date date, + member integer, + cctype text, + ccnumber text, + expire text, + ccname text, + ccconf text, + charge_total float, + special_needs text, + notes text, + session_id text + ); + +ALTER TABLE eventmgt.ticket_order OWNER TO postgres; +REVOKE ALL ON TABLE eventmgt.ticket_order FROM PUBLIC; +REVOKE ALL ON TABLE eventmgt.ticket_order FROM postgres; +GRANT ALL ON TABLE eventmgt.ticket_order TO postgres; +GRANT ALL ON TABLE eventmgt.ticket_order TO nobody; +GRANT ALL ON TABLE eventmgt.ticket_order_id_seq TO postgres; +GRANT ALL ON TABLE eventmgt.ticket_order_id_seq TO nobody; + +CREATE INDEX ticket_order_id_index ON eventmgt.ticket_order ( id ); +CREATE INDEX ticket_order_lname_index ON eventmgt.ticket_order ( lname ); +CREATE INDEX ticket_order_fname_index ON eventmgt.ticket_order ( fname ); +CREATE INDEX ticket_order_email_index ON eventmgt.ticket_order ( email ); +CREATE INDEX ticket_order_purchase_date_index ON eventmgt.ticket_order ( purchase_date ); +CREATE INDEX ticket_order_member_index ON eventmgt.ticket_order ( member ); +CREATE INDEX ticket_order_session_id_index ON eventmgt.ticket_order ( session_id ); + + +CREATE TABLE eventmgt.ticket_sold + ( + id SERIAL, + ticket_order integer, + member integer, + member_name text, + assigned boolean, + assigned_from integer, + assigned_from_name text, + performance smallint, + performance_name text, + entrance smallint, + entrance_name text, + entrance_color text, + section smallint, + section_name text, + ticket integer, + ticket_name text, + is_package boolean, + package_sold_id text, + ticket_package integer, + package_name text, + date_specific boolean, + ticket_date date, + time_specific boolean, + ticket_time time, + start_date date, + end_date date, + likely_date date, + price_paid float, + policies text, + unlimited_use boolean, + numb_uses smallint, + numb_claimed smallint, + time_claimed timestamp, + voucher_type smallint, + voucher_text text, + session_id text + ); + +ALTER TABLE eventmgt.ticket_sold OWNER TO postgres; +REVOKE ALL ON TABLE eventmgt.ticket_sold FROM PUBLIC; +REVOKE ALL ON TABLE eventmgt.ticket_sold FROM postgres; +GRANT ALL ON TABLE eventmgt.ticket_sold TO postgres; +GRANT ALL ON TABLE eventmgt.ticket_sold TO nobody; +GRANT ALL ON TABLE eventmgt.ticket_sold_id_seq TO postgres; +GRANT ALL ON TABLE eventmgt.ticket_sold_id_seq TO nobody; + +CREATE INDEX ticket_sold_id_index ON eventmgt.ticket_sold ( id ); +CREATE INDEX ticket_sold_ticket_order_index ON eventmgt.ticket_sold ( ticket_order ); +CREATE INDEX ticket_sold_member_index ON eventmgt.ticket_sold ( member ); +CREATE INDEX ticket_sold_assigned_from_index ON eventmgt.ticket_sold ( assigned_from ); +CREATE INDEX ticket_sold_performance_index ON eventmgt.ticket_sold ( performance ); +CREATE INDEX ticket_sold_ticket_index ON eventmgt.ticket_sold ( ticket ); +CREATE INDEX ticket_sold_ticket_date_index ON eventmgt.ticket_sold ( ticket_date ); +CREATE INDEX ticket_sold_likely_date_index ON eventmgt.ticket_sold ( likely_date ); +CREATE INDEX ticket_sold_time_claimed_index ON eventmgt.ticket_sold ( time_claimed ); +CREATE INDEX ticket_sold_session_id_index ON eventmgt.ticket_sold ( session_id ); +CREATE INDEX ticket_sold_package_sold_id_index ON eventmgt.ticket_sold ( package_sold_id ); +CREATE INDEX ticket_sold_ticket_package_index ON eventmgt.ticket_sold ( ticket_package ); + +CREATE TABLE eventmgt.add_on_sold + ( + id SERIAL, + ticket_order integer, + ticket_sold integer, + add_on_name text, + add_on_type integer, + add_on_type_name text, + unit_name text, + unit_price float, + quant integer, + price_paid float, + session_id text + ); + +ALTER TABLE eventmgt.add_on_sold OWNER TO postgres; +REVOKE ALL ON TABLE eventmgt.add_on_sold FROM PUBLIC; +REVOKE ALL ON TABLE eventmgt.add_on_sold FROM postgres; +GRANT ALL ON TABLE eventmgt.add_on_sold TO postgres; +GRANT ALL ON TABLE eventmgt.add_on_sold TO nobody; +GRANT ALL ON TABLE eventmgt.add_on_sold_id_seq TO postgres; +GRANT ALL ON TABLE eventmgt.add_on_sold_id_seq TO nobody; + +CREATE INDEX add_on_sold_id_index ON eventmgt.add_on_sold ( id ); +CREATE INDEX add_on_sold_ticket_order_index ON eventmgt.add_on_sold ( ticket_order ); +CREATE INDEX add_on_sold_ticket_sold_index ON eventmgt.add_on_sold ( ticket_sold ); +CREATE INDEX add_on_sold_session_id_index ON eventmgt.add_on_sold ( session_id ); + +CREATE TABLE eventmgt.promo_sold + ( + id SERIAL, + ticket_order integer, + ticket_sold integer, + promo integer, + promo_name text, + promo_type integer, + promo_type_name text, + amount float, + session_id text + ); + +ALTER TABLE eventmgt.promo_sold OWNER TO postgres; +REVOKE ALL ON TABLE eventmgt.promo_sold FROM PUBLIC; +REVOKE ALL ON TABLE eventmgt.promo_sold FROM postgres; +GRANT ALL ON TABLE eventmgt.promo_sold TO postgres; +GRANT ALL ON TABLE eventmgt.promo_sold TO nobody; +GRANT ALL ON TABLE eventmgt.promo_sold_id_seq TO postgres; +GRANT ALL ON TABLE eventmgt.promo_sold_id_seq TO nobody; + +CREATE INDEX promo_sold_id_index ON eventmgt.promo_sold ( id ); +CREATE INDEX promo_sold_ticket_order_index ON eventmgt.promo_sold ( ticket_order ); +CREATE INDEX promo_sold_ticket_sold_index ON eventmgt.promo_sold ( ticket_sold ); +CREATE INDEX promo_sold_promo_index ON eventmgt.promo_sold ( promo ); +CREATE INDEX promo_sold_session_id_index ON eventmgt.promo_sold ( session_id ); + + +CREATE TABLE eventmgt.ticket_claim_tracking + ( + id SERIAL, + ticket_order integer, + ticket_sold integer, + time_of_action timestamp, + action_type smallint, + quant smallint, + scan_user integer, + scan_name text, + attendance smallint, + attendee_name text, + attendee_notes text + ); + +ALTER TABLE eventmgt.ticket_claim_tracking OWNER TO postgres; +REVOKE ALL ON TABLE eventmgt.ticket_claim_tracking FROM PUBLIC; +REVOKE ALL ON TABLE eventmgt.ticket_claim_tracking FROM postgres; +GRANT ALL ON TABLE eventmgt.ticket_claim_tracking TO postgres; +GRANT ALL ON TABLE eventmgt.ticket_claim_tracking TO nobody; +GRANT ALL ON TABLE eventmgt.ticket_claim_tracking_id_seq TO postgres; +GRANT ALL ON TABLE eventmgt.ticket_claim_tracking_id_seq TO nobody; + +CREATE INDEX ticket_claim_tracking_id_index ON eventmgt.ticket_claim_tracking ( id ); +CREATE INDEX ticket_claim_tracking_order_index ON eventmgt.ticket_claim_tracking ( ticket_order ); +CREATE INDEX ticket_claim_tracking_sold_index ON eventmgt.ticket_claim_tracking ( ticket_sold ); +CREATE INDEX ticket_claim_tracking_scan_user_index ON eventmgt.ticket_claim_tracking ( scan_user ); + + +CREATE TABLE eventmgt.attendance + ( + id SERIAL, + member smallint, + name text, + notes text, + attendance_date timestamp, + entrance_start_time timestamp, + entrance_end_time timestamp, + perf_start_time timestamp, + perf_end_time timestamp + ); + +ALTER TABLE eventmgt.attendance OWNER TO postgres; +REVOKE ALL ON TABLE eventmgt.attendance FROM PUBLIC; +REVOKE ALL ON TABLE eventmgt.attendance FROM postgres; +GRANT ALL ON TABLE eventmgt.attendance TO postgres; +GRANT ALL ON TABLE eventmgt.attendance TO nobody; +GRANT ALL ON TABLE eventmgt.attendance_id_seq TO postgres; +GRANT ALL ON TABLE eventmgt.attendance_id_seq TO nobody; + +CREATE INDEX attendance_id_index ON eventmgt.attendance ( id ); +CREATE INDEX attendance_lmember_index ON eventmgt.attendance ( member ); +CREATE INDEX attendance_performance_index ON eventmgt.attendance ( performance ); +CREATE INDEX attendance_attendance_date_index ON eventmgt.attendance ( attendance_date ); +CREATE INDEX attendance_entrance_start_time_index ON eventmgt.attendance ( entrance_start_time ); +CREATE INDEX attendance_perf_start_time_index ON eventmgt.attendance ( perf_start_time ); + + +CREATE TABLE eventmgt.voucher_coupons + ( + id SERIAL, + name text, + active boolean, + display_from timestamp, + display_to timestamp, + coupon_type smallint, + coupon_image text, + coupon_position smallint, + stretch_to_fit boolean, + padding integer, + show_border boolean, + max_display_count smallint, + display_count integer, + notes text + ); + +ALTER TABLE eventmgt.voucher_coupons OWNER TO postgres; +REVOKE ALL ON TABLE eventmgt.voucher_coupons FROM PUBLIC; +REVOKE ALL ON TABLE eventmgt.voucher_coupons FROM postgres; +GRANT ALL ON TABLE eventmgt.voucher_coupons TO postgres; +GRANT ALL ON TABLE eventmgt.voucher_coupons TO nobody; +GRANT ALL ON TABLE eventmgt.voucher_coupons_id_seq TO postgres; +GRANT ALL ON TABLE eventmgt.voucher_coupons_id_seq TO nobody; + +CREATE INDEX voucher_coupons_id_index ON eventmgt.voucher_coupons ( id ); +CREATE INDEX voucher_coupons_from_index ON eventmgt.voucher_coupons ( display_from ); +CREATE INDEX voucher_coupons_to_index ON eventmgt.voucher_coupons ( display_to ); + diff --git a/docs/Current_Deployment_Notes.txt b/docs/Current_Deployment_Notes.txt new file mode 100644 index 0000000..4be5dc8 --- /dev/null +++ b/docs/Current_Deployment_Notes.txt @@ -0,0 +1,638 @@ +Current Deployment Notes +======================== + + +NEW CHANGES + + DATABASE CHANGES + ---------------- + + CREATE TABLE eventmgt.voucher_coupons + ( + id SERIAL, + name text, + active boolean, + display_from timestamp, + display_to timestamp, + coupon_type smallint, + coupon_image text, + coupon_position smallint, + stretch_to_fit boolean, + padding integer, + show_border boolean, + max_display_count smallint, + display_count integer, + notes text + ); + + ALTER TABLE eventmgt.voucher_coupons OWNER TO postgres; + REVOKE ALL ON TABLE eventmgt.voucher_coupons FROM PUBLIC; + REVOKE ALL ON TABLE eventmgt.voucher_coupons FROM postgres; + GRANT ALL ON TABLE eventmgt.voucher_coupons TO postgres; + GRANT ALL ON TABLE eventmgt.voucher_coupons TO nobody; + GRANT ALL ON TABLE eventmgt.voucher_coupons_id_seq TO postgres; + GRANT ALL ON TABLE eventmgt.voucher_coupons_id_seq TO nobody; + + CREATE INDEX voucher_coupons_id_index ON eventmgt.voucher_coupons ( id ); + CREATE INDEX voucher_coupons_from_index ON eventmgt.voucher_coupons ( display_from ); + CREATE INDEX voucher_coupons_to_index ON eventmgt.voucher_coupons ( display_to ); + + + + ALTER TABLE eventmgt.ticket_sold ADD COLUMN package_name text; + update eventmgt.ticket_sold set package_name = ''; + ALTER TABLE eventmgt.ticket_sold ADD COLUMN is_package boolean; + update eventmgt.ticket_sold SET is_package = false; + + ALTER TABLE eventmgt.ticket_sold ADD COLUMN package_sold_id text; + + CREATE INDEX ticket_sold_package_sold_id_index ON eventmgt.ticket_sold ( package_sold_id ); + CREATE INDEX ticket_sold_ticket_package_index ON eventmgt.ticket_sold ( ticket_package ); + + CREATE TABLE eventmgt.attendance + ( + id SERIAL, + member smallint, + name text, + notes text, + attendance_date timestamp, + entrance_start_time timestamp, + entrance_end_time timestamp, + perf_start_time timestamp, + perf_end_time timestamp + ); + + ALTER TABLE eventmgt.attendance OWNER TO postgres; + REVOKE ALL ON TABLE eventmgt.attendance FROM PUBLIC; + REVOKE ALL ON TABLE eventmgt.attendance FROM postgres; + GRANT ALL ON TABLE eventmgt.attendance TO postgres; + GRANT ALL ON TABLE eventmgt.attendance TO nobody; + GRANT ALL ON TABLE eventmgt.attendance_id_seq TO postgres; + GRANT ALL ON TABLE eventmgt.attendance_id_seq TO nobody; + + CREATE INDEX attendance_id_index ON eventmgt.attendance ( id ); + CREATE INDEX attendance_lmember_index ON eventmgt.attendance ( member ); + CREATE INDEX attendance_attendance_date_index ON eventmgt.attendance ( attendance_date ); + CREATE INDEX attendance_entrance_start_time_index ON eventmgt.attendance ( entrance_start_time ); + CREATE INDEX attendance_perf_start_time_index ON eventmgt.attendance ( perf_start_time ); + + ALTER TABLE eventmgt.ticket_claim_tracking ADD COLUMN attendance smallint; + ALTER TABLE eventmgt.ticket_claim_tracking ADD COLUMN attendee_name text; + ALTER TABLE eventmgt.ticket_claim_tracking ADD COLUMN attendee_notes text; + CREATE INDEX ticket_claim_tracking_attendance_index ON eventmgt.ticket_claim_tracking ( attendance ); + UPDATE eventmgt.ticket_claim_tracking SET attendance = 0, attendee_name = '', attendee_notes = ''; + + CREATE TABLE eventmgt.member_scans_for + ( + id SERIAL, + member integer, + scans_for integer + ); + + ALTER TABLE eventmgt.member_scans_for OWNER TO postgres; + REVOKE ALL ON TABLE eventmgt.member_scans_for FROM PUBLIC; + REVOKE ALL ON TABLE eventmgt.member_scans_for FROM postgres; + GRANT ALL ON TABLE eventmgt.member_scans_for TO postgres; + GRANT ALL ON TABLE eventmgt.member_scans_for TO nobody; + GRANT ALL ON TABLE eventmgt.member_scans_for_id_seq TO postgres; + GRANT ALL ON TABLE eventmgt.member_scans_for_id_seq TO nobody; + + CREATE INDEX member_scans_for_id_index ON eventmgt.member_scans_for (id); + CREATE INDEX member_scans_for_member_index ON eventmgt.member_scans_for (member); + CREATE INDEX member_scans_for_scans_for_index ON eventmgt.member_scans_for (scans_for); + + + + + CONFIG CHANGES + -------------- + + ; Terms used to refer to an attendance + term.attendance.norm = "attendance" + term.attendance.cap = "Attendance" + term.attendance.plur = "attendance" + term.attendance.plur_cap = "Attendance" + + ; Terms used to refer to an attendee + term.attendee.norm = "attendee" + term.attendee.cap = "Attendee" + term.attendee.plur = "attendees" + term.attendee.plur_cap = "Attendees" + + ; Terms used to refer to an attendance log + term.attendance_log.norm = "attendance log" + term.attendance_log.cap = "Attendance Log" + term.attendance_log.plur = "attendance logs" + term.attendance_log.plur_cap = "Attendance Logs" + + ; Terms used to refer to entering (attendance) + term.attendance_entering.norm = "entering" + term.attendance_entering.cap = "Entering" + term.attendance_entering.plur = "entering" + term.attendance_entering.plur_cap = "Entering" + + ; Terms used to refer to Coupons (advertisements) for vouchers + term.coupon.norm = "voucher coupon" + term.coupon.cap = "Voucher Coupon" + term.coupon.plur = "voucher coupons" + term.coupon.plur_cap = "Voucher Coupons" + + + +------------END OF NEW CHANGES NOTES------------------------------------ + +Mackinaw Lakeshore Development (Mackinaw City) +Username: hydrojet955 +Password: Mc33BoAt +Current API Login ID: 6AkBG3xJ7HB +Current Transaction Key: 6tJ5BxaB4X4f37JE + +Star Line Mackinac Island Passenger Service Inc. (St Ignace) +Username: hydrojet956 +Password: Mc34BoAt +Current API Login ID: 3Wazxf7G5u97 +Current Transaction Key: 3TW7f7Z28p5m4x9Y + + +Database Update Notes +--------------------- + + + +Temporary Notes from Notepad +---------------------------- + +Jodie Things and other thing I've noticed + +* Include contact permission options to enable access to all locations data + +* Fix problems with Likely date not being validated + DONE + +* Check on correct "From:" E-Mail address for confirmation messages. + +* Agree to policies on checkout page not staying as what was selected when checkout fails. + +* Session ID or something not going to Authorize.net for use as an order ID. + +* Inventory may not be being created when a ticket is created. + +Longer term Jodie Things + +* One credit card checkout form + +* Need to consider limits on report results. + +To do + +* Can't use Add-ons for children in sunset cruises + +* Promo Codes not working on checkout - Check again + DONE + +* Make sure promo codes respect time ranges + DONE + +* Add "Code Recognized" indication to cart + +* Check if we should be storing ID of Add-on in add_on_sold table. + +* Make Checkout Results look like current checkout page for tables. + DONE + +* make likely date = ticket date if fixed date + +* may be issue with selection on "Ticket Select" page (cruises) when there's unlimited quantity and the underlying quant field is 0 or null. + +* Flag to permit voucher scanning by contact from any location + +* Ticket claim tracking + +* Check if login user can check/claim tickets at all locations - May need to make this a configuration option per customer. + Use option to suppress location name at top of page. + + + +Done + +* checkout now storing add-ons correctly + +* Vouchers now showing add-ons correctly + +* Sticky items showing up when category is active = false + + + + + +Current modifications to complete for Star Line +----------------------------------------------- + +QUESTIONS + + Are the dates on promo codes the date of purchase or the date of use? + ANSWER: Date of sale. + +Vouchers: + + * Specified color per dock for voucher and for display when scanning vouchers. + Not always displaying correctly - Check + DONE - If not an assignment, the Section must specify an entrance and entrance must have color. + + * 90 deg Rotated text not displaying in the correct position and moves as text changes. + DONE - Needed to use "left" for $align in glmpdfPlaceText() then "position=center" in the optlist. + + * Summary of items purchased and totals on voucher cover page + DONE + + * Policies per location for display on cover sheet of voucher. + DONE + + * Simple (limited) text per category (performance) for display on bottom of voucher. + DONE + + * Provide for blocking of printing Voucher Barcode if card will be printed and mailed. Note on voucher. + DONE - NEED TO TEST WITH PURCHASE + + * Properly show add-ons + DONE + +Voucher related functionality: + + * Ability to show just barcode for a specific voucher for possible scanning from a phone. + NOT DOING AT THIS TIME + + * Ability of customers to enter a voucher number (and check code) to view order and re-print vouchers and display barcode for phone scanning. + NOT DOING AT THIS TIME + + * Check on auto-scaling image on Voucher + + * Check fonts on Dev53 used by Vouchers + +Front-End General: + + * Removed number of "uses" from display on Front-end. Relying on descriptions to say how the tickets will be used. + DONE + + * Fixed improper reference to ticket.ticket_name when should have been ticket.ticket_title for use on front-end. + DONE + + * Test in Chrome and other browsers + + * Test in mobile widths + + * Check sort order of all output + DONE - for everything we're showing for Star Line + + * Make sure that all available data can be displayed. (descriptions, images, etc). Set configurable options (in config/applications/EventManagement.ini) to turn those on/off. + DONE + + * Sale of "group" tickets, like 2 Adults and 2 Children, should be on one voucher (which they are now). Need to confirm with Star Line. + DONE - Must be this way as they are group tickets. + + * Look for "Check if we're receiving an array of new additions" in front/classes/support.php and check on this. + + * Make sure add-ons work on ticketSelect page. + + * Check that all new information is passed all the way through to orders + +Cart Page: + + * Check on ordering of categories. They don't seem to follow the sort order field in the database. + DONE + + * Have "nights" selection for valet parking display right away when user selects quantity for valet parking. + DONE - Decided to show it all the time for now. + + * Have resubmit updates try to return to the same page scroll position. + DONE + + * Check on not showing Dock selection or likely departure date unless they're needed. This is interfering with ordering things that don't need them. + DONE + + * Consider adding a notice overlay when the first thing is selected that needs dock and date selection to instruct user that they need to enter that information. + + * Remove the "reprint a previous order" thing from the top of the page. + DONE + + * Added short descriptions to Categories. In cart use short description instead of normal when less than 600 wide. + DONE + +Checkout page: + + * Make checkout page items lists look like Cart page + DONE - But might need to check what's store + + * Make checkout prompt fields configurable in customer config file. + DONE + + * Add a few optional/configurable text fields for checkout + DONE + + * Fixed Special Requests field showing when not requested + DONE + + * Fixed improper reference to ticket.ticket_name when should have been ticket.ticket_title for use on front-end. + DONE + + * Fixed missing info for ticket orders. + DONE + + * Check storage of promotions with purchase + + * Check storage of Add-Ons with purchase + DONE + +Admin: + + * Admin Login and improved colored claim scan results indications + DONE + + * Test in Chrome and other browsers + + * See if can do better with consignment type text - less confusing + DONE - Might want to move text for these things to customer config + + * Add time override to inventory - Default to that set in the ticket + Added to inventory edit + Need to use that time throughout the rest of admin and front-end + SUSPENDED FOR NOW + + * Fix issues with small and large list switching and alignment of columns when selecting large/small or resizing window. + DONE + + * Redisplay lists when something is added deleted or edited. + Need to add feature to know where the list is so it can be updated. + Working on this.... + + * Low-level front-end admin access. + DONE + + * Background color on scan of voucher to show Pass/No Pass status. + DONE + + * Inventory calendars not showing all dates at times + + * Add link from a performance to permit purchasing from admin even if performance or ticket is not active. + Added flag to ticket to permit active boolean, but need to Respect in front-end. + + * Add any needed reporting for promotions + + * Add any needed reporting for Add-Ons + + * Consider copying default ticket time into inventory so that a specific inventory item can have the time of the event adjusted. + Only do this if there's time available for the change. + + * Consider adding a "Category" parameter to performances to permit categorizing performances. (This would mean changing how we use these terms for Star Line.) + +Not-categorized: + +* May need to consider non-date-related items such as purchased physical items (books, etc) - Don't show likely departure date in cart for these. + +* Consider adding year/season to all ticket data and establishing a "seasonal" option that lets admin select a year/season to work with. + +* Check Member Ticket Policy - Does not seem to be in detail or edit. + +* Agree to policies on checkout needs to be in red - required. + +* Need to complete tracking of multiple claims for tickets that can be claimed more than once. + Database seems to be setup, but need to add tracking and display in ticket sold display + +* Need to add code to handle editing of tickets sold. + +* Check on adding entrance to ticket. May not always be able to use "Entrance" from section + i.e. Sunset Cruises. + DONE - may need some work later to make this more universal + +* Check on doing a pop-up message when checkout completed instructing users to print tickets or retain order and voucher numbers. + +* Voucher cover page + Web address + Phone Numbers + Maps??? Or do the appropriate map with each voucher. + +* Set a date range for creating inventory in ticket edit + This should be used as the date range when building inventory + It should be the dates checked when checking if inventory needs to be added or turned off + It should default to the date range specified in the event + DONE - But not defaulting to performance dates + +* Need to handle Valet Parking + Valet parking is charged per night. + Consider this a ticket "Add-On" item + Select 1 or multiple for an add-on item (yes/no or quantity) + Optional Price per add-on + Include field to say what this is (i.e "Per Night", or "Each") + Should show on line below primary line for ticket. + + Ticket Add-On + + * create table ticket_add_on + name + description + type (single (option), selected quantity, + other - perhaps packaging of other tickets) + see "ticket_add_on_type" in config + max quantity if quantity related + unit name + unit amount + + * Add admin management of add-ons for a specific ticket + + * Add handling of add-ons when selecting tickets and in cart and checkout + + * Add handling of add-ons in reporting. + + Added to admin but not done on front-end + +* Promo Code + Entry of Promo Code text + Each promo code has list of tickets it applies to + Each promo code provides either percentage or $ amount + + promo_code + id SERIAL, + name text, + descr text, + start_date date, + end_date date, + notes text + + promo_ticket + + id SERIAL, + ticket text, + promo_type integer, + amount float, + notes text + + +* Check on entrance display in Section selection page. + +Completed + +* Toggle list size button for lists in admin. + DONE + +* Need to add time specific, # of uses, and number of claims to ticket sold data + DONE + +* For vouchers "Round Trip Ticket", "Retain this ticket for your return trip. + Now configurable text per ticket or event + DONE + +* Forget session button when running on Development server + Added to bottom of all pages if running on a development server + DONE + +* Add better "Please Wait" thingy. + Added pop-up/overlay for pages needing this. + DONE + +* Departure date for non-date-specific tickets + Added likely departure date to cart and likely date to checkout + Need to add to ticket order information also + DONE + +* Remove "Each" from cart and checkout tables + DONE + +* Add second doc (location) handling for St. Ignace + Added "Entrance" feature to ticketing system and termed this as "Docks" for Star Line + Still need to get this printing on summaries and vouchers + DONE + +* Checkout contact information "Please send information ..." should default to checked. + DONE + +* "Print Vouchers" to "Print Boarding Passes" ??? + Changed terms used for "Voucher" to "Boarding Pass" + DONE + +* Enable browser menus on the voucher window so people can print. + Enabled menus and added window.print() to script + DONE + +------- + + + +* Create new optional Purchase process for Star Line + See "Streamlined Ticketing for Star Line.odg" + + Venues need "type" + type 1 Standard Location/venue + Can sell items + type 2 Standard Location/venue + Sell through other venues + Can sell items + Can offer items for sale by other locations + Must flag items to be sold this way + Other vendors must be approved by this vendor to sell their stuff + Items must be flagged as sellable by others + (may want to have specific ticket negotiations) + type 3 Non-sales vendor, tickets only sold by type 1 or 2 locations/venues on this system + Does not sell items + Items of Type 3 are available for sale by type 2 + + Ticket need flag that permits them to be sold by other vendors + + Need flag for ticket that causes it to always be shown on cart - even with 0 quantity. + + Ticket sold needs pointer to vendor who sold the ticket/item (in addition to the point to the member who's tickets they are) + +* Try to sort cart by ticket sort order + +* Set global terms + location: Departing From + (Consider adding categories of events) + Event: Category ??? + Section: Section + Ticket: Item + Inventory: Inventory + +* Get info on Motorola hand scanners for Jerry - May need 8 to 10 - Most WiFi but some Cell. + http://www.motorolasolutions.com/US-EN/Business+Product+and+Services/Bar+Code+Scanning# + + Possible options - Prices approx + + Simple for use with computer + $108 (Amazon) http://www.motorolasolutions.com/US-EN/Business+Product+and+Services/Bar+Code+Scanning/General+Purpose+Scanners/LI2208 + $380 (Amazon) http://www.motorolasolutions.com/US-EN/Business+Product+and+Services/Bar+Code+Scanning/General+Purpose+Scanners/LI4278 + + Wireless + http://www.motorolasolutions.com/US-EN/Business+Product+and+Services/Mobile+Computers/Handheld+Computers/MT2000+Series+Handheld+Mobile+Terminals_US-EN + http://www.motorolasolutions.com/US-EN/Business+Product+and+Services/Mobile+Computers/Handheld+Computers/MC55A0 + http://www.motorolasolutions.com/US-EN/Business+Product+and+Services/Bar+Code+Scanning/Rugged+Scanners/MT2000+Series+Handheld+Mobile+Terminals_US-EN + + Ruggedized Mobile Computer + http://www.motorolasolutions.com/US-EN/Business+Product+and+Services/Mobile+Computers/Handheld+Computers/MC3100_US-EN + + Cell Capable + http://www.motorolasolutions.com/US-EN/Business+Product+and+Services/Mobile+Computers/Handheld+Computers/TC55#specs_tab + http://www.motorolasolutions.com/US-EN/Business+Product+and+Services/Mobile+Computers/Handheld+Computers/MC67 + + +* Create Venue - Event - Section - Ticket - Inventory summary with flags for issues in Admin area + Expandable sections might be good + +* Update reports to work correctly with all new changes + +* Add Month and Day of Week enable/dissable for inventory edit page + * Consider being able to highlight date cells and do bulk edit with them. + +* Update Help file and enable context sensitive admin help + + + +Issues to check on +------------------ + +* Make sure default inventory is created when tickets are created. + +* Make sure that tickets are not presented on the front-end unless there's inventory + +* Make sure that non-date-specific inventory is handled correctly + * Inventory edit updates quantities properly + * Front-end and reports use correct numbers + +* Make sure we're using the right name/title for tickets and other things (internal vs user terms) + +* Check on content of stored purchase summary + +* Check that credit card type and name on cart are stored in order detail + +* Make sure that multiple claims per ticket is working correctly and showing on back-end correctly + + + + + + +OLD INFO - MAY NOT BE RELEVANT ANYMORE + +* Change any fees of type 11 or 12 that are in use to type 10 +* Check to make sure Toolkit/EventManagement/config.ini has updated fee definitions + +; Fee Method +fee_method.fixed_stay = 1 +fee_method.fixed_accom = 2 +fee_method.fixed_accomnight = 3 +fee_method.percent_stay = 10 + +; Fee Method Numbers - admin +fee_method_numb.1 = "Per Reservation - Fixed Fee" +fee_method_numb.2 = "Per Room - Fixed Fee" +fee_method_numb.3 = "Per Night - Fixed Fee" +fee_method_numb.10 = "% of Room Rate" + +; Fee Method Numbers - Front End +fee_method_numb_fe.1 = "Per Reservation" +fee_method_numb_fe.2 = "Per Room" +fee_method_numb_fe.3 = "Per Night" +fee_method_numb_fe.10 = "Per Room" + + +alter table convention add column central_payment boolean; +alter table convention add column central_payment_email text; +alter table convention add column host_property smallint; +update convention set central_payment = 'f', central_payment_email = '', host_property = 0; diff --git a/docs/Delete_Event.sql b/docs/Delete_Event.sql new file mode 100644 index 0000000..1ec7fea --- /dev/null +++ b/docs/Delete_Event.sql @@ -0,0 +1,21 @@ + +-- Find event ID +SELECT id, name, conv_code, start_date, end_date FROM convention; + + +-- Replace {CONV ID} with desired event id +DELETE FROM team_roster WHERE team IN (SELECT id FROM team WHERE conv = {CONV ID}); +DELETE FROM team_property WHERE conv = {CONV ID}; +DELETE FROM team_property WHERE conv = {CONV ID}; +DELETE FROM state_rep WHERE conv = {CONV ID}; +DELETE FROM division WHERE conv = {CONV ID}; +DELETE FROM room_block WHERE conv = {CONV ID}; +DELETE FROM room_block_seg WHERE conv = {CONV ID}; +DELETE FROM inven_hold WHERE inventory IN (SELECT id FROM inventory WHERE conv = {CONV ID}); +DELETE FROM inventory WHERE conv = {CONV ID}; +DELETE FROM reservation WHERE conv = {CONV ID}; +DELETE FROM fees WHERE affiliation_type = 1 AND owner = {CONV ID}; +DELETE FROM conv_prop_dist WHERE convention = {CONV ID}; +DELETE FROM event_prop WHERE event = {CONV ID}; +DELETE FROM convention WHERE id = {CONV ID}; + diff --git a/docs/Development_Notes.txt b/docs/Development_Notes.txt new file mode 100644 index 0000000..47d4be3 --- /dev/null +++ b/docs/Development_Notes.txt @@ -0,0 +1,513 @@ +Current Work +------------ + +Notes regarding modifications to Ticketing to support ferry services + +Things to update +---------- +SQL and database changes required for current updates + +alter table eventmgt.ticket add column unlimited_quant boolean; +update eventmgt.ticket set unlimited_quant = false; +alter table eventmgt.misc drop column return_url; +alter table eventmgt.misc add column intro_text text; +alter table eventmgt.misc add column ticket_text text; +alter table eventmgt.misc add column ticket_opt_text text; +alter table eventmgt.misc add column cart_text text; +alter table eventmgt.misc add column checkout_text text; +alter table eventmgt.misc add column success_text text; +update eventmgt.misc set + intro_text = 'Intro text', + ticket_text = 'Ticket selection text', + ticket_opt_text = 'Ticket option selection text', + cart_text = 'Cart text', + checkout_text = 'Checkout text', + success_text = 'Checkout success text'; + +Above needed for current devdb copy + +alter table eventmgt.ticket add column section_specific boolean; +alter table eventmgt.ticket add column time_specific boolean; +alter table eventmgt.ticket add column date_specific boolean; +alter table eventmgt.ticket add column unlimited_use boolean; +alter table eventmgt.ticket add column start_date date; +alter table eventmgt.ticket add column end_date date; +alter table eventmgt.ticket add column uses smallint; +update eventmgt.ticket set + section_specific = true, + time_specific = true, + date_specific = true, + unlimited_use = false, + start_date = null, + end_date = null, + uses = 1; + + + +How to add a new main tab item to admin +--------------------------------------- + +* Edit view index.html and add a new tab where desired. +* Set "emTabId" for that tab to the desired model and action (i.e. Attendees_list} +* Create a matching directory under both... + models/admin/actions/{model} + views/admin/tickets/{model} +* Add action include files in models/admin/actions/{model}. Typically these are... + add.inc, confirmDelete.inc, delete,inc, detail.inc, edit.inc, insert.inc, list.inc, selected.inc, update.inc +* Add view files in views/admin/tickets/{model}. Typically these are... + added.html, deleted,html, detail.html, edit.html, list.html + + + + +Update CommonAbstracts-PDF-V0 +------------- + +High priority for Starline + +* Check on creating tickets for an event needing to select the venu +* Check on permitting selection of both date specific and non date specific tickets for the same event +* Options to set defaults for checkboxes when creating tickets + +* Options for tickets + * No Section + * No time + * Non-date specific + * Active for specified range of dates for non-date specific tickets + * Multiple scans/uses for a single ticket - Specified number + * Unlimited scans/uses for ticket + * Unlimited inventory +* Track Scan time, location, user when claiming tickets + +* Convert to Smarty Templates +* Create admin/log-in user ticket sales interface +* If a single venue, default to that venue when creating tickets and other things +* Recommend other tickets/sales on ticket selection +* Packaging + * Purchase multiple tickets as one item +* Pre-sales to other sales agents + * Create agents to sell (use contacts with specified permissions) + * Track sales agent / means of sale for each ticket sold + Add "sold_by" field to ticket_sold table +* Add filters to lists + * Active/inactive + * Venue + * Section + * Date range for ticket orders + + +* Check on support for portable bar-code readers with audible/light/display confirmation. + BarcodesInc, Chicago 1-800-351-9962 + * Hand held, weather proof, bar-code, WiFi, optional link to cell phone/service, display/audio for confirmation/info + + + + + +Things to check on + +* Checkout permitted with no cart contents if re-displaying checkout +* on checkout fail (field not filled in) says "This venue does not have a payment method configured. Please call this venue to purchase tickets." +* Need ability to display prototype of all E-Mail messages sent. Optionally all forms. + + + + +* Need to split and verify application.ini file into common app and user configuration files. + +* Moving schema from reservations to eventmgt +* Moving table convention to table event +* Moving fields that point to event (convention) to event +* Move ..._APP_BASE to THIS_APP_BASE as appropriate + + + + + +FROM V2 - Much still needs to be implemented + +Notes from 2/1/2013 + +Do something to deal with someone double selecting the same available inventory into their cart. +Cart should check for actual maximums available or we can implement the selected inventory hold. + +Check all property fees to see if any type 1 or type 10 are set as "Fee is selectable per room": + +For event fees, per room % of room rate seems to be superfluous. + +May need to check for per Reservation optional fee that's not per room on accommodations selection page. + +---- + + + +DB updates + alter table convention add column central_payment boolean; + alter table convention add column central_payment_email text; + alter table convention add column host_property smallint; + update convention set central_payment = 'f', central_payment_email = '', host_property = 0; + + +In procees + Central Payment + Admin work + * central_payment Flag + * central_payment_email Who gets bills + Request credit card Flag + Show prices to guests Flag + ??? Billing/payment reconciliation to members ??? + Front-end + Request credit card if set + Send reservation to Prop + Send billing to central billing + Members Area + Look through to find things that might need to be fixed up + ??? payment reconciliation to members ??? + Host Property + Admin + * Work completed + Front End + Need to display host propert at top of lists + Highlight background? + + + + + +General Development Notes + +alter table + +Fees Matrix + + Available with + Applied at level Event Property + Per Reservation - Fixed Fee + + Optional Off Property Yes Yes + Optional On Property Yes Yes + Selectable per room Accommodation No No + + Per Room - Fixed Fee + + Optional Off Property Yes Yes + Optional On Property Yes Yes + Selectable per room Accommodation No Yes + + Per Night - Fixed Fee + + Optional Off Property Yes Yes + Optional On Property Yes Yes + Selectable per room Accommodation No Yes + + % of Room Rate + + Optional Off Property Yes Yes + Optional On Property Yes Yes + Selectable per room Accommodation No Yes + + +Misc Notes +---------- + +Pending database updates for live servers +----------------------------------------- + +For geo mapping address +/* +include this link +http://maps.googleapis.com/maps/api/js?sensor=true + +// For the Event Map +// Create a jquery dialog with #map-dialog +$('#map-dialog').dialog({ +height: 480, +width: 520, +modal: true, +autoOpen: false +}); +$("#map-it").click(function(e){ +e.preventDefault(); +$("#map-dialog").dialog('open'); +GLM_GeoMap.initialize(); +}); + +

+*/ + +Site Status +----------- + + Server Site Version Notes + dev52 Development V1, V2 + dev53 Development (pending) + ws0 app.gaslightmedia.com V1, V2 + ws3 app.gaslightmedia.com V1, V2 + www.discoverkalamazoo.com V2 + + +Task List +--------- + +GENERAL + +** Check for International Address Support + DONE + +** Add fields for E-Mail addresses to event (general contact, internal contact, from address) + Can we use Discover Kalamazoo in the from line and GeneralInfo@DiscoverKalamazoo.com as the email address? - Jodie + +** Ability to select an event that is charged to a central entity rather than to each attendee + +** Check owner name salutation line in confirmation e-mails. + +** Event ID as access to event registrations + DONE + +** Host property selection in event + +** Display of date/rates when rates are inconsistent for a stay + +* Purge any previous customer info or links from system (greatlakesbay) + +* Need to change calendar.phtml pop-up to all JAVAscript using a layer at some point. + +* Add "conv" field to inven_hold table to make it easier to identify by event. + +ADMIN AREA + +** Add Team filter and output sorting options to Reservations report + +* Add check for inventory that doesn't match the evnet dates when the dates for an event are changed. + Add check for this whenever the event is selected and prominantly warn the user. + Make sure that inventory associated with an event is displayed even if it's outside the date range for the event. + Add warning to inventory that is outside the date range for an event when listing/viewing that inventory. + +* Need to have system check to make sure inventory is in a rational date frame for the event. If the event date + changes, it needs to still be able to display what inventory is in there (which it seems to have a problem with) + and needs to warn the admin user that the inventory needs to be change. Consider adding code such that if the + event start date changes that all inventory slides the same number of days. + +* Add Division to reservation reports + +* Add Division to Events->Reservations list and detail + +* Check fees/taxes detail output to make sure $ & % are displayed correctly for selected type. + +* Add date for earliest possible reservation used to block reservations prior to a certain date. + +* Reservations report + Add table ordered by State Rep, Team + ***DONE*** Add filter for State Rep + +* Add map drag-drop capability for Lat/Lon input and refining positions. + Ask Steve for his code. + +* Check on styles properly loading for printed reports + +* Set table headers to not scroll in admin areas + +* Add property search field for Inventory list summary screen + +* Add delete functions to dataAbstract.php and appropriate admin areas + ***DONE*** Contacts + Events + Event Fees & Taxes + State Reps + Divisions + Teams + ***DONE*** Inventory ( this is done in inventory edit - now checking for room blocks first ) + Properties + Property Fees & Taxes + Property Accommodations + +* Reports - Complete basic reports + ***DONE*** Room block Reports + Room Requests + Reservations + Finance + +* Help - complete help texts and Quickhelp popups + +* When inventory is added, see if it's easy to have the inventory summary at the top scroll to the selected property + +* Build default teams using "Division" names when a division or State rep is added + +* Add ability to include sort links at top of tables + +* Add demographics info to reports + +* Auto-generate default "access codes" (currently "Team code") to produce rational password style string + {word}{nnn}{word} kind of password + +* Auto-generate team records when state-division is added + +* Check for and fix "&" in Room Block Report + +RESERVATIONS FRONT-END + +* System does not handle the situation where all of the inventory for an event is well outside the date range of the event. + (See similar issue for admin area above). If this happens it should not break but rather show no properties available. + +* Accommodations image problem + +* Add support for Fee/Tax guest optional items and optional quantities. + +* Check for earliest possible reservation date and display that instead of link to event on event selection page if it's not time to reserve yet. + +* Room Blocks Front-end lists, include fees/taxes in property detail pages just below room-blocks list. + +* Move fees/taxes on property detail page, to just below accommodation selection + Move "Add Selected Accommodation" button to bottom of list. + +* Mage sure "Must arrive by" and "Must not depart before" dates are displayed correctly and that default arrive/depart search dates are correct. + +* Add "Must arrive by" and "Must not depart before" dates to Event Selection screen + +* Keep pending reservations selections (on hold) from being reserved by others + +* Need to deal with checkout problem where there might be more than one room block that matches the same accommodation and team. + Currently not able to distribute consumption of rooms between multiple room blocks where the conv, state, team, and accomodation all match. + +* Make sure reservations respect + req_stay_arrive + req_stay_depart dates + ***DONE*** open_res_date + cutoff_date + +* Setup default and custom E-Mail message templates (by event) for sending to visitor on making the reservation. (file in this directory) + +* Check "OK to send" setting. Make sure it's respected on checkout + +* Check cart to make sure that there is availability for all cart entries + Currently only checking each separately + Consider combining same accommodation to make one entry + +* Add check-in and check-out times to conf E-Mail to visitors + +* On property profile (unit selection) page add the following: + Room Amenitites + Distance from Event + Consider moving number of rooms, credit card data to right had side as in main site + Make sure all appropriate data displayed in main site member profile pages is displayed + Consider moving description to below room list to minimize scrolling + Consider making profile page and property selection page similar + +* Check to make sure any session timeout is handled properly. + +* Reservations submitted E-Mail messages need to be customizable by event. + +* E-Mail sent when submitting reservation should include driving directions + +* Fix arrive_date stored with reservation request + +* Add storage of fees summary into reservations request then fix reservations reports to use that data + +MEMBERS FRONT-END + +* Fix problem with editing reservation dates and such. + Note that line with "calc_unit_totals()" call has been commented out. + +* Complete processing of accommodation quantity and date changes when updating a reservation. + Check again for availability + Rebuild summary + Note changes in Notes field. + +* Fix "fudged" min and max reservations available dates for modifying reservations + Should be based on actual availability for each accommodation + +* Create "print" option for printing out reservation detail for a selected reservation. + +* Change to appearance similar to back-end tables + +* Add copy of policies to reservation confirmation E-Mail + +* When declining reservations do not send E-Mail to visitor, only send E-Mail to event contacts (King Comm.) + +* Check reservations daily(hourly?) and send warning notices of unconfirmed reservations (see conf_hours) to members and summary to event contacts. + +* Confirmation E-Mail messages need to be customizable by event. + Need to be able to say whether credit card will be charged upon reservation or at checkin. + +* Change conf message to HTML and use view file + +* Driving directions link on Confirmation E-Mail + +* Ability to edit reservations dates + When storing, update all inventory and room block availability numbers + Recalculate all charges, fess, and totals + Update reservation record with new data + Add to notes for this reservations record how it was modified + +STATE-REP ROOM BLOCK SUMMARY + + + +OTHER NOTES ON USE + +Info on sending test message to properties for a specific event +--------------------------------------------------------------- +* Enter front-end reservations as a team or regular visitor. +* Select accommodations for a single property +* Proceed to checkout +* Under "Billing Information" in the "First Name" field enter "Event Test Property Message" +* Fill out rest of information and submit + You may use the 0011001100110011 pseudo creadit card number +* System will produce a single test message to the "cscott@gaslightmedia.com" address for testing this mode +* To have the test message sent to all properties associated with the selected event enter "Production Mode" in the "Last Name" field. +* Messages will contain + - "John Doe" information for the billed party + - Will be addressed to each property + - Will NOT contain any of the credit card information submitted + - Will contain the exact selected reservations summary and totals selected in the cart + - Will NOT clear the cart or create an actual reservation + + +PHASE 2 WORK + +* Property defines cut-off date for reservations if not defined in Event + + + + +How to delete an entire event +----------------------------- + +Delete data in this order + +Table Link to Link field +----------------------- --------------- ------------------------------------------- + SELECT id, name, conv_code, start_date, end_date FROM convention; +team_roster team team = {team for specified event} + DELETE FROM team_roster WHERE team IN (SELECT id FROM team WHERE conv = {CONV ID}); +team_property convention conv = {convention} + DELETE FROM team_property WHERE conv = {CONV ID}; +team convention conv = {convention} + DELETE FROM team_property WHERE conv = {CONV ID}; +state_rep convention conv = {convention} + DELETE FROM state_rep WHERE conv = {CONV ID}; +division convention conv = {convention} + DELETE FROM division WHERE conv = {CONV ID}; +room_block convention conv = {convention} + DELETE FROM room_block WHERE conv = {CONV ID}; +room_block_seg convention conv = {convention} + DELETE FROM room_block_seg WHERE conv = {CONV ID}; +inven_hold inventory inventory = {inv for specified event} + DELETE FROM inven_hold WHERE inventory IN (SELECT id FROM inventory WHERE conv = {CONV ID}); +inventory convention conv = {convention} + DELETE FROM inventory WHERE conv = {CONV ID}; +res_contact ??? +reservation convention conv = {convention} + DELETE FROM reservation WHERE conv = {CONV ID}; +fees convention affiliation_type = 1, owner = {convention} + DELETE FROM fees WHERE affiliation_type = 1 AND owner = {CONV ID}; +conv_prop_dist convention convention = {convention} + DELETE FROM conv_prop_dist WHERE convention = {CONV ID}; +event_prop convention event = {convention} + DELETE FROM event_prop WHERE event = {CONV ID}; +convention + DELETE FROM convention WHERE id = {CONV ID}; + + diff --git a/docs/Field Specifications b/docs/Field Specifications new file mode 100644 index 0000000..05784ab --- /dev/null +++ b/docs/Field Specifications @@ -0,0 +1,271 @@ +Field Definitions Specification + +Fields are specified using an array of field specification arrays. + +Sample: + + $this->fields = array( + + // Record ID + 'id' => array( + 'field' => 'id', + 'as' => false, + 'type' => 'integer', + 'filter' => 'int', + 'required' => true, + 'unique' => true, + 'default' => false, + 'use' => 'a' + ), + + // Name of event + 'name' => array( + 'field' => 'name', + 'as' => false, + 'type' => 'text', + 'filter' => 'string', + 'required' => true, + 'unique' => true, + 'default' => false, + 'use' => 'a' + ) + + ); + + +The index for fields must be unique, but three may be multiple entries for a +single field ('field') in the database table. + + +Field Specifications: + +(array index) The array index is only used to permit multiple entries for the + same database field. This permits including the field several + times so it can be processed differently based on the operation + being performed or can be displayed multiple time but each in a + different way. + +'field' Name of field in database table + +'as' Name to use for this field for all operations other than for talking + with the database. Doing this keeps any possible multiple instances + of use of a single database field separate. (see array index above) + + If this is not specified, then the actual database field name is + used for these purposes. + + +'type' Type of field - Possible field types are... + + 'integer', + 'float', + 'money', + 'percent', + 'pointer', + 'list', + 'bitmap', like list but permits multi-pick + 'text', + 'checkbox', + 'email', + 'date', + 'time', + 'phone', + 'image', + 'latitude', Data is an array of (dir,deg,min,sec); + 'longitude' " " " + "dir" is - for West and South + +'filter' Optional filter - See PHP filter_input() "filter" parameter. + Currently only for type "text" + FILTER_SANITIZE_FULL_SPECIAL_CHARS does not seem to be defined at this time. + +'filter_options' Optional filter options - See PHP filter_input() "options" parameter. + Currently only for type "text" + +'required' If set and true, field data must be supplied + +'unique' If set and true, must be a unique value + +'default' If set and true use this value as the default for input fields. + Dates/times are expected to be timestamps + There is no default image capability + +'use' Character(s) that indicate which operations to use this field with. + + l = Listing records + g = Get - Displaying a record + n = Setup input for a new record + i = Insert new record + e = Edit an existing record + u = Update an edited record + d = Ask for verification of deletion of a record + c = Confirm delete and delete record. + a = All above operations + +'minValue' Minimum acceptable value (numeric) + Dates are specified as timestamp + +'maxValue' Maximum acceptable value (numeric) + Dates are specified as timestamp + +'p_table' Table to get related data from for pointer types + +'p_field' Field to get related data from for field types + +'p_id' name of ID field in related data table + +'p_where' Additional WHERE clause for getting possible values from related table. + +'p_from' Additional FROM tables for getting possible values from related table. + See example in dataMembers.php + +'p_blank' If set or true provide a "blank" option for pointer input + +'p_sort' Optional ORDER BY sort clause (i.e. "name, age DESC") - May not be functional yet. + +'p_orderby' Optional "ORDER BY" clause for results from table pointed to by pointer + +'p_autoadd' Option to permit the addition of a new entry using a text input field + +'p_sum' If true causes a numeric sum of all returned values from the target table/column + +'p_static' A static pointer that does not do a lookup for a list of values, only a single value reference + +'output_type' Optional type to use for output. Useful with pointers. + +'latlon_type' Optional specification for lat/lon output (DMS, DM, or D) + +'view_only' View only field, do not check for input or store, only provide data from record. + +'list' Required with field type 'list' - includes simple array where... + array key is value for option + array value is name for option + +'bitmap' Required with field type 'bitmap' - includes array of (position, name) for each option + array key is a value indicating the bit position (i.e. 1, 2, 3, 4) starting with 1 rather than 0 (it will be converted) + array value is the name for the option + +'list_keytype' Type of key field (default is 'text') + 'text' A Text key - expects a text field in the database + 'int' An Integer key - expects a numeric field in the database + +'output_format' Optional output format specification as would be used in printf() + Use only the actual format and not the type identifier (i.e. "02.2" rather than "%f02.2") + +'no_stripslashes' Don't strip slashes when recalling this field from the database. + +'quicktip' Text description of this field and its use. + + +Data specification for various types +------------------------------------ + +Type 'list' + + Return data + + array( + 'list' => array( + array('name' => {name}, 'value' => {value}, 'default' => {true if default or selected}, + .... + ), + 'value' => {value of selected option}, + 'name' => {name of selected option} + ) + +Type 'bitmap' + + Return data + + array( + 'bitmap' => array( + array('name' => {name}, 'value' => {value}, 'default' => {true if default or selected}, + .... + ), + 'value' => {value of selected option}, + 'names' => array( {simple list of names of selected options} ) + ) + +Type 'date' + + Input data fields + + When using single input text field, input field is name of field + + When using separate M, D, Y picklist or input fields + + '{field}_month' + '{field}_day' + '{field}_year' + + Return data + + array( + 'date' => {text date}, + 'timestamp' => {timestamp}, + 'date_list' => array( + 'month' => {picklist array}, + 'day' => {picklist array}, + 'year' => {picklist array} + ), + ) + +Type 'time' + + Input data fields + + When using single input text field, input field is name of field + + When using separate H, M picklist or input fields + + '{field}_hour' + '{field}_min' + '{field}_ampm' + + + Return data + + array( + 'time' => {text time}, + 'time_list' => array( + 'hour' => {picklist array}, + 'min' => {picklist array}, + 'ampm' => {picklist array} + ), + ) + + +Types 'latitude' & 'longitude' + + Return data + + array( + 'dir' => {direction: -1 = S or W, +1 = N or E}, + 'dir_list' => array( + array('name' => 'N', 'value' => 1, 'default' => {true if default or selected}), + array('name' => 'S', 'value' => -1, 'default' => {true if default or selected}) + ), + 'deg' => {degrees}, + 'min' => {minutes}, + 'sec' => {seconds} + ) + + +Type 'image' + + Input fields + + '{field}_delete' Name of checkbox field to delete image + '{field}_new' Name of file input field to save new image + + +Type 'picklist' + + Parameters for {picklist array} + + 'name' Name to use for this option + 'value' Value to return when this option is selected + 'default' True if this option is currently selected + + + diff --git a/docs/Install.txt b/docs/Install.txt new file mode 100644 index 0000000..254f460 --- /dev/null +++ b/docs/Install.txt @@ -0,0 +1,226 @@ +Install Instructions + +* This version of Event Management is a New Common App so it's in /var/www/server/CommonApps/EventManagement_V? + +* Add the following files/directories if they don't already exist + + /common Directory containing symbolic links to a "web" directory in a common application + If creating directory, set svn:ignore for all files below that directory. + + /admin/EventManagement Directory containing a file to kick off EventManagement admin functions + /config/applications Directory containing ini files for specific applications + +* Add the following symbolic links in the Web site /common directory + + ln -s /var/www/server/CommonApps/EventManagement_V{version}/web EventManagement + ln -s /var/www/server/CommonApps/Public Public + touch Only_symbolic_links_in_this_directory-do_not_add_to_repository + +* Copy the contents of the docs/admin/EventManagement directory to /admin/EventManagement + +* Copy the contents of docs/config/applications directory to /config/applications + +* Check if the contents of docs/Barcode already exist in "/usr/share/fonts/truetype/barcode". + If not, copy docs/Barcode to /usr/share/fonts/truetype/barcode + +* Edit site's /config/application.ini. + + Make sure the following is near the top of the file + + ; CommonApps configuration + commonApps.base_path = "/var/www/server/CommonApps/" + + Remove any any old configuration for EventManagement and add the following + + ; Turn the events management application On or Off + event_management.application = On + event_management.version = "EventManagement_V3" + +* Make sure site loads jquery + +* Create a Toolbox page for the EventManagement front-end and note catid + +* Create a Toolbox page for the EventManagement Member's login and note catid + +* Add eventmgt schema to database - data/EventManagement.sql + +* Edit /admin/nav.phtml and add the following + + if (defined('EVENT_MANAGEMENT') && EVENT_MANAGEMENT) { + $nav['Event Management'] = BASE_URL.'admin/EventManagement/EventManagement.php'; + } + +* Edit /config/applications/EventManagement.ini and set at least + + "home_page", "members_only_page" with ID's for pages created above + +* Make sure there's not reference to a "reservations" schema in /Toolkit/Database.php + +* Create file in /static directory for the front-end catid with the following... + + commonApps->base_path.$GLOBALS['applicationConfig']->event_management->version.'/controllers/FrontController.php'; + $html = new EventManagementIndexController($GLOBALS['applicationConfig'], $GLOBALS['serverConfig'], $GLOBALS['siteConfig']); + ?> + +* Create file in /static directory for the admin login catid with the following... + + event_management->version.'/controllers/AdminController.php'; + ?> + +* Check to make sure site has owner information in the config/site.ini file. + + ; Web Site Owner Information - for use by certain applications + owner.name = "Gaslight Media" + owner.short_name = "GLM" + owner.address1 = "120 E. Lake St." + owner.address2 = False + owner.city = "Petoskey" + owner.state = "MI" + owner.zip = "49770" + owner.country = "US" + owner.phone = "231-487-0692" + owner.toll_free = False + + +HEREHERHRHERHERHE + + + +// **************** below is OLD *********************** + +* Add the contents of the documentation/config/application.ini file to /config/application.ini + +* Add a page for the Event Reservations front-end and note the catid + +* Add a page for the members only area Event Housing and note the catid + +* Update the following files to include the necessary references to Event Management + For old sites without ini files and schemas use replacements in Old sites below. + + /setup.phtml + + /** + * Site has Event Management + */ + define('EVENT_MANAGEMENT', $applicationConfig->event_management->application); + define('EVENT_MANAGEMENT_HOME_PAGE', $applicationConfig->event_management->home_page); + define('EVENT_MANAGEMENT_MEMBERS_PAGE', $applicationConfig->event_management->members_only_page); + + +; Turn the events management application On or Off +event_management.application = On +event_management.common_apps = "/var/www/server/CommonApps/" +event_management.base_path = "/var/www/server/CommonApps/EventManagement_V3/" +; The page id in the toolbox that is the entry page for Event management - Generally set for each server +event_management.home_page = 130 +event_management.members_only_page = 131 + + + ; Turn the events management application On or Off + event_management.application = On + ; The page id in the toolbox that is the entry page for Event management - Generally set for each server + event_management.home_page = 239 + event_management.members_only_page = 240 + + ************ NOT NEEDED ANY MORE ************ + /Toolkit/Database.php in _setSearchPath() function - *** Only if site already has schemas!!! *** + + if (defined('EVENT_MANAGEMENT') && EVENT_MANAGEMENT) { + // define event management search path + $stmt->bindValue(':schema', 'reservations', PDO::PARAM_STR); + $stmt->execute(); + } + ********************************************* + + /admin/nav.phtml + + if (defined('EVENT_MANAGEMENT') && EVENT_MANAGEMENT) { + $nav['Event Management'] = 'admin/EventManagement/EventManagement.php'; + } + + /static/{front-end-page} + + + + /static/{member-admin-page} + + + +* Fix member login problem with some sites. + + /memberdb/index.php -- Move logout before auth start + + $memberAuth =& new Toolkit_Members_Auth($root, 'DB', array(), '', false); + $memberAuth->setIdle(); + if (isset($_GET['logout']) || isset($_POST['doLogin'])) { + $memberAuth->logout(); + } + $memberAuth->start(); + + /memberdb/classes/class_user.inc -- Add user name to logout button. + + $out .= '
  • User:  '.$_SESSION['_authsession']['username'].'
    Log Out
  • '; + + +* Old sites that don't have ini files and schemas + + /setup.phtml + + /** + * Site has Event Management + */ + define('EVENT_MANAGEMENT', true); + define('EVENT_MANAGEMENT_HOME_PAGE', 0); + define('EVENT_MANAGEMENT_MEMBERS_PAGE', 0); + define('EVENT_MANAGEMENT_LEGACY_SITE', true); + + + /static/{front-end-page} + + prepare($sql); + $stmt->execute(); + + $html = new Toolkit_EventManagement_EventManagement($dbh); + + ?> + +* Edit /Toolkit/EventManagement/config.ini to set the customer's information + +* Add page catid for all pages that should be secure to "$securePagesArray = array(12,33);" in setup.phtml + +* Optionally to have a seprate style for this site copy Legacy/styles.css to virtual server directory /Toolkit/EventManagement/styles.css + + + + \ No newline at end of file diff --git a/docs/ProgramFlow.txt b/docs/ProgramFlow.txt new file mode 100644 index 0000000..51a96b1 --- /dev/null +++ b/docs/ProgramFlow.txt @@ -0,0 +1,83 @@ +Event Management + +NEED TO UPDATE FOR VERSION 3 + + +Notes: + +* If there is an /admin/EventManagement/templates directory, the application will look for + templates there. Otherwise it will use the standard set in {app}/Common/EventManagement_V2/admin/templates + + +General Program Flow and Class Organization +------------------------------------------- + +Directories & Components + +Toolkit/EventManangement + + Contains all setup, configuration, and libraries for application + +Toolkit/EventManagement/data + + Contains all Libraries for access to data + + dataAbstract.php + + Abstract class for all access to data + + Methods for processing input and output for all standard field types + Method to build queries from field specification tables + Methods for all standard data operations + + getStats() Get record counts of various types + getList() Get list of records for a particular table + getEntry() Get record detail for an entry in a table + newEntry() Prepare data to ask for detail for a new table entry + insertEntry() Add new detail entry to table + editEntry() Prepare data for edit of entry + updateEntry() Update data for an entry + deleteEntry() Prepare data for confirmation to delete and entry + deleteConfirmEntry() Delete an entry if confirmed + + data{app}.php - i.e. dataEvents.php, dataMembers.php, ... + + Data support class for a specific application - such as handing event data or member data + + Field definitions and specifications for a particular table or related group of tables + Methods for handling data from these tables for various types of operations. + i.e. Stats, List, ... + Whenever possible, these methods should try to use methods in the abstract class + to support these operations. + Methods for handling operations unique to this specific application. + + +admin/EventManagement + + Contains code specific to the admin section for this applicaiton. + Whenever possible this code should use the classes in the "Toolkit/EventManagement/Data" + directory to support the admin actions. + +admin/EventManagement/EventManagement.php + + Main code section for the admin section + +admin/Eventmanagement/classes + + Contains all class libraries for performing data retrieval and storage. + Whenever possible should use the "data" classes in "Toolkit/EventManagement/data" for + data storage and retrieval by calling the "data{app}.php" base classes. + + + + +Admin + + /admin/nav.phtml + /admin/EventManagement/EventManagement.php + /setup.phtml + /Toolkit/EventManagement/config.ini + /admin/EventManagement/classes/{} - where {} = events.php, ... + /Toolkit/EventManagement/data/data{} - where {} is same as above + /Toolkit/EventManagment/data/dataAbstract.php + diff --git a/docs/Sites_Using.txt b/docs/Sites_Using.txt new file mode 100644 index 0000000..e7b1db5 --- /dev/null +++ b/docs/Sites_Using.txt @@ -0,0 +1,6 @@ +Sites_Using.txt +--------------- + +File depreciated + +See: CommonApps/EventManagement/V3/Notes/Sites_Using.txt \ No newline at end of file diff --git a/docs/Streamlined Ticketing for Star Line.odg b/docs/Streamlined Ticketing for Star Line.odg new file mode 100644 index 0000000000000000000000000000000000000000..085cd9444f196f5317628b01031651e80076ab69 GIT binary patch literal 16904 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 literal 0 HcmV?d00001 diff --git a/docs/Testing Notes.txt b/docs/Testing Notes.txt new file mode 100644 index 0000000..321b96f --- /dev/null +++ b/docs/Testing Notes.txt @@ -0,0 +1,12 @@ +Testing Notes + +Checkout Test options + +This parameter is required for any test option below + Last name: GLM TEST ONLY + +Do not store the reservation result + First name: GLM DO NOT STORE + +Do not clear the cart cookie + Address (line 1): GLM DO NOT CLEAR diff --git a/docs/Toolkit/EventManagement/EventManagement.php b/docs/Toolkit/EventManagement/EventManagement.php new file mode 100644 index 0000000..b23162e --- /dev/null +++ b/docs/Toolkit/EventManagement/EventManagement.php @@ -0,0 +1,19 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: EventManagement.php,v 1.0 2011/01/25 19:31:47 cscott Exp $ + * @link http://housing.gaslightmedia.com/admin/ + */ + +echo "NEED TO FIGURE THIS OUT ..."; exit; +require_once GLM_APP_BASE.'Common/EventManagement_V2/Legacy/EventManagement.php'; + +?> \ No newline at end of file diff --git a/docs/Toolkit/EventManagement/MembersEventManagement.php b/docs/Toolkit/EventManagement/MembersEventManagement.php new file mode 100644 index 0000000..f833df0 --- /dev/null +++ b/docs/Toolkit/EventManagement/MembersEventManagement.php @@ -0,0 +1,57 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: EventManagement.php,v 1.0 2011/01/25 19:31:47 cscott Exp $ + * @link http://housing.gaslightmedia.com/admin/ + */ + + +// Check for an old site that doesn't have a proper autoloader or $dbh defined. +if (defined('EVENT_MANAGEMENT_LEGACY_SITE')) { + + /* DEPRECIATED ALERT */ + echo ' +

    Depreciated: EVENT_MANAGEMENT_LEGACY_SITE

    +

    See: CommonApps/EventManagement_V?/admin/EventManagement.php

    + '; + $backtrace = debug_backtrace(); + echo 'Processes back-trace: (in return order)
    + + + '; + foreach($backtrace as $b) { + echo ' + + '; + } + echo '
    FileLineFunctionClass
    '.$b['file'].''.$b['line'].''.$b['function'].''.$b['class'].'
    '; + exit; + /* END DEPRECIATED ALERT */ + + $dbh = Toolkit_Database::getInstance(); + $sql = "set search_path = reservations,public;"; + $stmt = $dbh->prepare($sql); + $stmt->execute(); + + set_include_path(get_include_path().':'.GLM_APP_BASE.'glmPEAR'); + set_include_path(get_include_path().':'.GLM_APP_BASE.'glmZend/1.10.2/library'); + set_include_path(get_include_path().':'.GLM_APP_BASE.'glmZend/1.10.2/library/Zend/Config'); + set_include_path(get_include_path().':'.GLM_APP_BASE.'Common/EventManagement_V2/Legacy/classes'); + include_once('Ini.php'); + + require_once GLM_APP_BASE.'Common/EventManagement_V2/Legacy/classes/GeoCalculations.php'; + require_once(GLM_APP_BASE.'Common/EventManagement_V2/Legacy/EventManagement.php'); +} + +echo "NEED TO FIGURE THIS OUT..."; exit; +require_once GLM_APP_BASE.'Common/EventManagement_V2/Legacy/Members/index.phtml'; + +?> \ No newline at end of file diff --git a/docs/Toolkit/EventManagement/NOT_SURE_ABOUT_THIS_STUFF_MIGHT_NOT_BE_USED b/docs/Toolkit/EventManagement/NOT_SURE_ABOUT_THIS_STUFF_MIGHT_NOT_BE_USED new file mode 100644 index 0000000..e69de29 diff --git a/docs/VenueAdminGuide.odt b/docs/VenueAdminGuide.odt new file mode 100644 index 0000000000000000000000000000000000000000..954d31a0578e90bc6ffd588e056f82e0e4614566 GIT binary patch literal 311096 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%0AD`!)8e`(^h3-Ca+_fvLj5gn{{a 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 z f_qR*yI#6)XIQ{#dFRy=>V)Gd>kN+VQ*{zfQ(xJGOT@)>?(nnr5%xdu#6_qg$U zpt*hwIaJkK-uEwrPw1;8zL=E#oj}5@=KW$Sk}SzNk^I(Gr|6XYXQqb)lr{2KOz`A= z?s>3`@9f@KGX{7PsMl(zb0qm8z0OpP?M7SEoDs7f}pIKdvQHp^Kve>AMefiASpahAO}o096K=nE-U-PteE_@ zAcXm+=E5W(E>hU*B8xUZ1K*eDr>#QitgJxM=L1H`H>;!EC;7F48+yum zx6}ob71~8bf|D#P26&PPI;Q@AC^x`YSEbKcRYFxz2g1PY&<&`lrDw(n5M}t8gf}y( zhgc4=?hj|r1d^h#24LT71ESPK!=F@&_7|Gi173RP6($iWuzIO~UB5nN{8<2Ugw(cD zQ94$0>12N(nwefBmeBrk&!PpE2GE+ejyavv)yP{`GAgs-6TV*Yp~5VP!v1;;J~X>q z^M2KLUxngzPQt)P_AN?Ht0WpP<8Q2(WV&Om7!?sr^H{EaMnYQ<(d+|l@d|OF;yfm8 z7|cCB(Xp=89L2XFC|9AyphOn4XEhv|Vv!(`;YyiGg5>#mx$($IjvDuqpw}ShXe@jc9SF)6B?Rmyo<%<`^n=S#0=Y`pX?W6)4Ey6SnqfdpF%M|sNAtdt3=$|WEgo;Vq zRsv$*?f96>5C>r142>!)iVE2^0rT#p1#_DzOn8FIW=w8NKV?_K>OM!N!LI~mZY~uz zap~H1(L0a8OSZJVx{=)rULbfKw(IB_meRGVjibeRqPH44th)7yYuJ2g04KX*Y_lu) z3p;1ej7bx#09BBKAF0Vcq73{ayA9rtfL!^sq)lEKFR25SRJt^bW!X;nK{p^-Tx(8s z+Ob)qO|85UaOEfB(-iX;utH2wGy9Z^mxuRjx&|)Iow#!#ayQB2kgQm_ifh!&Z$}K~ z#unhrDwsq(a3w`1d197do}zwStEl`l;yw6{!54gb+h36W>GV9 zJ3a_EH3abYD$%ybiWQ8@MV;@%0!2mb$@?nLdW6qamet7arGTWkp?2PQ&^ORHJID3X znaO9f?>z~w#QR3;sjP&F6-r@yvCrjj;4D`L!kb)$w5+7f^Nrt<=fy}a^TRNZXD0dy zxbGy6ekt63<_~c-*bJ6iUiR?lt;x8^F6H$(d50Xy? z0sJT*G^S02G~d|W)FY;T{Pg8u>i4*`J}L3_|FoRF1Xn>hdljmT9JPzZfJR=mutEbJ zHHhve2Ov=67*5#<7JP2Q0MjC7?xQhrq62ohM;k=Lgf!P1K23KlA9qQP)OAgCg{>pd7$$HIL7#<*^%k-B2#hKgQ)S~Z&`^C)k*WdLjaAD7pFIr z_^wk8`bJi`w$)5!Ljn09lZ@@IIVa`L8m&zU3}f0z0(qItawc(ZEWv&*!>KTV*|%4; z|L7oT+cv-3tXvuc#xFhD%A2GzrbtZJy{n4+F#R*GZdNe4vuS?ifXggzw&@D~E2^x_ z!pWc%8^1{r!C>G|qv^Twx2`3sS=@b$uMiA=FI<9q7z`=v~TXK$Bm-T$yKv!aTfULgh? zXb>3yeNTm>=1zC8FS2;kqh__Jr|hpD=7G$HQz*fFW@RoWmZnEVlkNQNTy!5Eg@L3f zh`+`82JOH3j1W+5R3=5NxzwSUP!K^D9yoIKfaN*wr`4EldR`URavE1zxGBAtGFn_* zB(;%-vq@pGVOYubUAX6xY=h+f5zQ-23t6++aItTQ_rB?f6-~qh+wMR9iZgE+X)Djo?dez*{`a~ZR z92?kmY3U2XhxprI)X9pW_o*aP&jsapR(pix9kSX#2gC*_yQA-YnWKfRIhdo*_CALE zRh|;n_65FCV^3GAL)9X1=L~N;)e!&}MGodAqKjY1zo?ee~!M#zQz!KN|%Ee;VV(u#+m1*2PP1KpTW~ zR7B8$2aZMe0tEYS&S%P=Q+PGIciI-b->$m%_2&Kx#BBz9UURXt@R#R7ql7pj4Igp} z)J0~$4Gm?N=U9r25hw=vBBxR<+Pk1c9zB*yZpaWWTx1n2qiNa-|Pi zZc5l!;_eI~Cke^G5ucYqxk-vUaTz*LK3nF^ln)c6ovK!P8~W1!&KMfhVdL8_3*}2$ zvzhTqq`>2l;{P{8PPi*pkS%3h@f)F+1IOn zPPNhZtQlmt%0kEB>Ij}+^GDx+6@IC*FxIbz@za29Z;-QlQcV35?2IrbSZ4-+j;RBU z_9--TxhaxrAh77r=J9oO8N3Tv`;*kp! zyvihXN0w*P69I)rp7hJYvHf&RXcUPKgL(#E&}Nmk`igzkKGubjUJL-)aOAI9!GCc0 z@2ksLr9Cwq5?(2Er(=VU&P3{}*CjK-yzmVjO>rfm&hWsK=DhV)B-hnWQz^7n4yYVq zJ{SRG!BH_NTMi>`DA`9e$`I%24uwL32vB)0?};;rg#gKHtTefSH8VF;4smC%jrY8p z8jj{@qb-Hu>Vs-&4&X~IbjKJGYPk(`s;BtYe>p)$Qy>*D)VQeCNB#lmI=Vf1=}Wm} zSa{B4EnkZeI%P?_7?!Qm9%sv;SCtCd43#8G(GT+t^B9IOO%yV%dpRJo2yEO3-0a&^ z?Vy-{olgW3l*8ePp;o$yas#q$kd!7m#y}A+rd{rz>vjaYZcW^qzOdrQr~ z4jfO$>sC@1KVZzmV~os;b9IUwX7K>A0}~Q12AnROGydVqJ%>j>NEMNo;Cclj-Xvt1 zpe5d!(Z0bzl)>oz#K4;b|>zotCfu(U5ig>E}yz$15doVc_aDEEFlu z#n)Ww9sMzng7aL-3+?*(*i=qi20hB$?4vR~#8k=PHs(k|-8v*7{T{)vFLL}8z*klP zLZ5p2nHV-n8~FCF_Ai2+Plv#;QRA8)3jI;HvXt%|hm4X_|A#YIS_=tcu|`WPs3dlWR7W5Xv{y{befwBJ84 zCP2-@w{g>XLbhS}*gPB>kf1$t@F;6Am?!OKuJ6W}-u^V+O)~66H*N9VFv!9NVIQIL z&TT-1y4eBuxdo3?Y=qD++}i8Nx%T>qT_i}Y_F?K65um41xe4Z)rIL}BUhZGERu!8b ze|>6Xkv&|Z!`d|7^}CzAKRoS;DsFRDIkUEg>u%SR%}YO~;dxd~y>Rl+S<#P=SGHJb zO>ktapPSt@sR(LD9!t5R*8J9>^&g+*Ed3Ww0?{Bwy{dR%rG!#zlwY6}t?N2r4LGq& zfbb%mzX_%5I>C|lt99M=)SGu@RyOWWCB^jU=5aasQ_OLHt=v)v?lkoXJT_t>a%i?> z1DXF0rZzsq=M%N`v~ENpzlUN3R#xZumpQ+&OL~r2G0B^~&Pn|tl4=l8Apt0;U#`$~90^{Rw z#(AilHJ)4xy&dJv_&^^ef&!vny{rfGvP^!*s)?AI#zk}*o_3*La%ooqMPwIYtjRpf7GKxQYQud7LFX?UcjeH8epnvwh`;4HIwrY>@} zX1m0jilp4dQg;ENL#3KnL|a%#(N+hiyO^_#a~Af*Z#9Q>>HYgi}a2lzia0y zp(*XV%y#Y=&fRwIrutGXHj9xNSnnn%GB<{$gQZ-sEy4!6q1Wqd7AT^p(2P=*BOUQP zjBl{0N+kSNb57Jc-UWx~=4|8VfeNtchdduTqQixkwkBt8yW1QA<3(QBy!%}l4AE@5 z_&wi)sIzJ3xehwz&k13Ay#~n+VHQTb!9sFRzZw z2_^ZEufr1ed;ibt@?JiK@0{0>5$l|gt7FR8f{Sma zNl?%~hNeY1(`@Nz?r-PllffSam(nU+$hLGD$XTnqR?}xCQvF#rU;H(qr#Vkp6}`|o z*PgYP@aSIcUb?h#0X95P3D2ySVdLyO(0Cz@{X;Eju6D1tnd56**xCiejTL-6>w|jt z_My(YJCB! zGbZx-JSR49!Ia}QS}VHG#xhCm?ipM%L6X?yp%34FW9%#U*&X0952>s?kAjCCxG6s` zOfQ_Ijl1oTRc{2$pq)XhDtB~v6wsHKamiorXcKB5*{QTjL<%3PaDVkI-2`8bV+Zkf zD2!f(5k;bwI}`c5zx#$w`BtY7uMtHNR^4RlMH#MAN1VEpoMNH9uEM&A1ImM`qf=sv^%HCpT zrnaucXjikFn1u7r^q%7x_pJKRJPv$?QGP)M;Lo@N8m;HYYdi>37O6!CYq=4=z6Nwy zDY$~L+%+TU=PAb4`DH-4DCoaHw~f^l1h$JwyXQAXYlgcZ7S$n`HKRtO`U7Z5Uq>Rj zR4OZRsL+J1fBtPLi)uR*xdmq_-1wS3MmVjh z#L+S`Wy(?30(@#S2MjsB%_Ip8?gcyG)y{fK5>4&WPL0J~`s~IYx9&b`1Za(9_!jgC z=GEYPF(9FEH=L;ji%SL$3i>3WzxKwqWkDGn0bAPa$_5Nv7+tb6I)!Tnw3~7w-e)Ra ziM&QayLuI@R!MuoV0`N zg|*C~CaX@~w<;K)t}1Qe(oh*}|3$D(OQ2rG#w;TvZmNH2Hh$5QUt*@KF*(7z5zHGX z$({Ac2h++OVLK;Ib8Tcfvd7&iR`61b!_JSp&f*4oX!mrFR;O5C|FUZFaPEjT^#Sw{e3cd6MesL$kUA7J~8O5{81!{(BUGX3n~d(qlcX3rQxdQj`aX+=0wr&Y^n*M~n+ zUKp=?xNF~c4rluY`w-M{Y4dtivjh}!k1kTn{q)$a)rV#ZX)!3XNo=aae0KR4M}=qC z@(KbTD^^sJJOg9YY<_#Aip4ItlUi7mGkaq@+(iXA*Jyj}qw1G`)wWFf;VqkfZ+3MT z7mnfxR|6)o^f^9{ncl^PCE{+{ZfbfmCK6+G%D-08C9ER{m~&zkt8mYwV6m+gEOi)r zB~AERZ$&GtJKxiw?Qzq+UuR{N5|`?-@4;sXQIlHI%;C(yqa9gHY5Ou7Bgc4~yg;;O z8RgF~a75}h8zivhSWH39lPGNa#WenwuF&E~tY2iWmJW0JB0wNFg4g%W$`4uwnRs3^ zdLUkmk+%+LdL*%&PD$1`SHE0A)q>t+-RyqPlkYgz$BL3im=Hy7Sj3&&W;~pj*_(l*E~oXST8c6xywzCGVnS z3kSIfx#~lxo5zRyNapFJDySasyfIiotITt+YHrA|W-0EJuN<(mZAP}2L^T@}k>o2H zf=d`Uy+g#gLm^z)59D7CQu$5X7J_>_j`#~fuQ&vRBH;lG2Y1AN;7WVtAjgqTpjjSA zFJ_$w-vE9?j1<+%Yr|BHnvzHMO1+;6B;D}wX9j7?$kKQM7KOMasR0y-5ZSF~Xe=!ZY(4W7akzSe)|6A3xQ=?c-SG14FTMlylW}~?59w03}wsRcC2Kj zXa?ECFk1Bxw-0YJ8}aWAJ)W*mo_d%2(Q zFyEE}ecC>#DCTexCv$5OlDTS^M69Wh7pn}J#p4ZjOQMdGBX1Cv43kD1yGU}?i48fF zq>9S(UnPFM*jEm0X^+XA^fr3TRJWUCgZrEXNs8!Fw}b-HVQ1&aXJlrwRGd%+vvWiV zneaU0X2cdJiFMYjuw-%PuzAnByJAKTuxRF-Y%VC@2J54Iki?RhwBB0CDmQdTWtRCh zH*H*S`WUI$;9|;;b638mc7>(ybU47M9)6HOh#E3gQ@i2r?J0Gwx}|h>I!W6HMKD%@ ziMS>^0x?NC1nfw&4I$*9v0-eU9Qu9SierMAXM~(~<{q*e3Dk9)fBfJ)>%{uI|tS$|c?fk7sOo+X8~~hY`2lJmfV6*}jGP?h-CFp(jhnZFd~VZDiqH^GwW2vSUCwq)SQ9oQh|uKFQw34Fg-{RIa! zEG>z;n*kCltR8B2RtA2I^4`N5RSa@!3`=ZLEeb=!PgiMR?J=-9=984dKtX|-_`<}U z>EN}0Q%irkJzY)XpEzo|5-1bSdSar1(D~F5m+=)XsT41^>XE3&P1vg{OP&fGmE?U4{FACJcsuh)$yF+-d9K1cwJ6heQcFX~{eup%B@lQ}#P}k$8X78&@ z?#7p(CTT9KgeUSAA4{&YGcpqF%*VRe^C?d+?Ux--(%EiQY>BPZ95`(W=Js#fv#IMn z^=5SK#gzF7(CVQ(I?JBnx%PtAVMfEg`k}_Y=pbjOKf;7V)7u2~jgSf2WB8ia{lx=e z$*H0En>Bkad0nXBA5ungXGlZAS3KQxfe)*zEjf+j&pMk{GKt5_XBD8T*T1ADWm|JU z@nFlXHIU!H9KB1>-G3XDFuzhewE5IsV7*cCKvjGzD)qxoxcc6}5>zhym!Q6147+-b z)fWtY6HY_|;*jpvp~fe1!ah-8?CiNQ{f>`KfEI2P{1v#!Epfd5^?n?~!hzY>j&yDi zwi03=XjcUiq*x(_aNBT<1agi{T}RCFJLJG-K-6`74d8_$+nXnats$=^HUpLVxHJGn zEb?G4aMKTEhv|Mz?8N7u$nmarJ%%8u`vk5@HZ~9k2N1ZjrqdhRISMhq2Dt`s2nL#v zxGhU!Hz*K7Fjhtp%h`*DS^jQ|4Z~*O^oU*>F;&R*Gqo|XqDO=#uZUB1aBH;QO&>Je z>ab9Y{@g=nf0H?^R(Wk*7A4flQ1@hez znqsrEL|)Q&%@6mHHBZURf>ST_(dOz>iYaj|uCYp6`wv}TVsxI<^e0P45ZLE3D5b-$ zjLkkrb~P@9h!#mgqdUl)JelRsa_PJX1geMSuBkC$nel+Ewv9u62JT-G6LaqC=pwxE zK&#~DM7^85$xo4Jli9^tDR-xHLq3_aH@o0I1LP?nFouSVsTG@urj z)E@VdR#0U_T=M5lGQ8J2bj|TmbD!NHEjKzd0z9%$S`$P^-PS=n;L;CqT10WGbpD!r zf)hwr+=kJxLs0EI0>7F5u5&vjWwjn(d4t&Re`EwASVG<6 ziPxCd$z<4DK65igh{J{7Twg(LFB1t9KR_LzTOMy!WvmT-R7CUL%iJ)&%}9WcMmp)Q z8~el>wIv0H`TPD|Kw7!C3x0N|-&u|}#2szB$GvFW1*3vUz%IVq^Q7fQ`$z9vdH3_$ zyN5QMb$V{^-kG&K-u{*>yKcsEZHDyWSSJ(kE+CCCo>!++v=(J#F5akFBpj}s5k)!H zuA-EZ!7tjKne*9&JN#JQ9ay4Ftdo)c>mU=Ej8pugVeR2=9W+VEni9?(7V6V)fNMD~ zS0jomrIJ@(fZ9%Eo!L>^wb2ajmQrvXB7=EnX5Mu@_Niaiq~h>&L0|qdU)DxXGP-i7 zq5HWlIWFpW(PBDik2@zvTJdionO$v8VZ96`(u z!1>>9Rs;XJKph5u%Y*ED6^Ab!dLjUS**R>1dZzp(2}ev(4~aXwS1yPP-+T?^h;oAQ zgtH5kS<$82#pey@kNR?3%=WqC1-h5nO-=x1R$n&qD*O5k?^5qZmwy9<=ZaZ#N)Q1P zMON37_0rOygQmkenshlB-5jrQy(SfNs;InCxETw=HR47+T9ziUZ|HnbSp_|wBnex+ zPd7(eQQl=!J}5DG^SPd-21K1{EUbJy+qT90g(Ox({jrf{tJ|uk%2Sk}@c9Dm`f)Lt z%LZZ~#@?~!Z1A;w$_P#5wIxQosu5{p7n`@m6iU0marNDTEfP&u`3NY}`6>Qpdwl-jp!j?rb)ujr?Ha9e@B0;q& z@2WNUA9@bqgAWMSmsG7{`p3Sv@;zq6F z>-@~_5s|vS8A;>JG~v&|QbZl6O~VKwGu_IaE7mBuY!9?!jo=FuPxxvfcdekaiRP<6p8R$NK+sr={Ese^w&M8Wkg-v zlgCgU3LU^5u5yIU7SVIC_9o{XZLpcOD#q6eV=Vub+%==}A$1QYg@sbbj6yu_zPK3~ z*_vNpM~>{mm!LRzXs2vatM3CN73narR%(E1M>^z>2S6P+knXHfHGmD}33B7)%vf(xGW-30S?LaqN)xPPzteK-BJVq!$C9yp(GjD8u+M zx8QmpTV`v}Nx$ei74EE8@$ZNF2qh1gPHOR;coF2>ttZbcVdFM6LOL0H<*1p~o3WhX zs|LjQS23twx&U9~Q=jx9!A4Xc-v~J?rmm=&CgY9zjb#p1hvRsSlZzD7dZV$@c70I3 z=?MvZ-gIa^LeSca^}>YdSlMIjV`fSse6l?i61|FgYu?r3sKqX1D7VM%ra= z8Fd1!67nZh`LKoRJ}gxUEaiD($S_ z@imT5&6&G;Jp_7&1vadxXa3yEm0=`?Fa}aUpqZ1h4v2_iLN^RQ7Az!W5+DV88>MIL zI+GRP?J*#2#PnrW5scm&&EuDwPUD$&#F~wjmL5pP&T4li)2~AhPyRXzLka!eEXMhNjj~dZMflmwx|$s!RL1kY>M$}@Q{P|J4I;0 zG{mAL>~&t$4c?xzf?iXM7_(7nrG&lo>aB|?{X<$%(tdZP6y*)O+&f>s&z`SCM$;H; zEeQ4>>aDf{(V&Q**Bl7|h7$N3zyoS{p^F)JX=`di)h;lZGUg8f2`}Az455Pva!bty zLPT~HkKJG74Y)t||AaF=A0Y$T;MxL5zFxnb3zZ^720@i<;5hg5V9cfNiJlEARCX2? zz+(15UnNdMuQ}TF>VBWniQKQ=rH|zS1f|_KN%;e>0r>l2nVi$Ho-4$+r>C(wZk^%) zG2+J{+WetRWAiD+&y)plxWjY+uzdc!L$Z_&WymbsCs@%xov**}4AgAI;m8-eRUQ}0 zlgmShH{;J86(j?Q{R7-mo&w_HZ6R24FegjSauC{l_05PTwqQlY&)Ew3e0VRX0mMDu zC^!uM{R(ro_a>W4Iq96i2C^j>_I$H*$c<_p?_1#Ey73zfRrQ7;k@%-iM2wWljSV>4>JVv9S-4bwA^YFKbX%%aT0wJmGrcki!}PI6G^V-*BT zrQ^ZeW0spu6xtuV-=|EP&DPxK7xtFfat%A83;EJYyR^<;zSVcCDqB}h4tEYNBg0Sc zxFC!WjpEeL{6?G}+IL5l$yt}rd--qTwA-1`DEOPqXZ7vlHD*H(5e{Faxc z&5ba>*c3+>Czp-(-8{RuMKLWv9RukxG1;HC+Jd}uFz;Uwv9$;zf&PcJSg-*I=Z!Zp zH#F!7^><2XOlupEm^;p%-%FXz`48dA{YAh}9(D7c*w#)m@GG*V#$CFR$m8MXKJEb7 zG_f}PjpL&xWaxs!DtV$?tf^;qhk@zP?sK`{015IBFhqjv3w%%bdUgL@>&>5S+fzId z7(S&DLwAtB9HV;6f4zExpBUaE6>UVcpTM;o1`so|wY4><-?ZjUfgs4kJmEiPoHp8m)qetz*@27_5=mb<-6b^;GBv6Bu5WrS6KTqa+jVQi;5o0! za1i^#d5=ygP~X;15Y@T<;&P3I%j(ywL(b#S_15vHtloTo8V23pi0ORGc1|u&42H(y zyS?5&y1F=U99;}cMxJ(b=5F6y<@||p*tu>PUGEmoIPzE`>pLy_r?km}xw|Kk$^@Mv zjtPZS3a&Tv3ZTK2tCh)(K2Ci0P*WcO0uXs z6H)j=1&vmYu^}M`npcnNcrQCNAs_l`Tysc^t&=I46uka9vC^4LJl+q8po_da4!}|} z>TghPo|A+S)9(ZSc&}Vu6UtK}|3orH9@CaZNSt~CnStP)g&X81V%fMM>o-vdS2lEW zK=h^cBSyQZ1D>d5jIrkr!c0sF0C=HBX9!X25LZF%u6`t`zA?)cBK6SwPL@T6AGMj~ z)w2-8I5Z>j(>LQ5E~~86Iyd0^{ZOG?UYzCqJ;n4)(NS6Y<<V&vh@iQ(|1+Sm~dg0|B>zs0|Wz9O9d1H zR>5+*jsuvX|HA-5|1Z|A#h%=D<|YEr?`s>mlNKV*eV55}5!%UPk)vCSdm`!Eem$NP zBj^N)Bf3zEADL0xR<+g0nh0czgcq@7R7OC?1T5*(I2^oG9VMYmqBa89NiWX)8LoTIN?NR##1-oKhi5 z(27r>6vxFmYDKl;iYb={Bb1ye7Mq0R(jMhv+aR%+hO(&^J)yo)HMqB@dVy29yR0+k zYfC{ZoQ^8MGLR?d4pAX~q}<7s>YgaLIJ}itygBZOMc4!U?aAPw=lIRwoW%8Ix{ z8lFJPFA`q^Lbuaaf@lM27~BXZS1eHy*qJqoXGLz*P)#8E=h7*WK!6;41yBWxh(PS+ z!c2xvFJ$37yY%IW+VdW~#7oG@5f20hyMq8OB~r*%C+Q%Pgbx#eJn}3PLWsqw0U#{H zzh4=;XYtFs>g>P7-X!u~kFZy=Q z1n8fX5IV)NdRwkKZ>&<9n~~2wjR*?mg2V>GP)cZx#~2=-x*i}sR8tQOWNmOwHn@Na zszg__<}mbhKoaI1a{yG%9UiIf(LAfcXRBD#L4d};PIL`Pz4hj-4PF@#vwjt)!C?qj zY`eov5G(JMIc;E3e1HMhA?-J-A-sq0W;CwyP_1{fFLEy=|7)zyYaJ6ENjVusHVn*u z@92)D>q|IbwjG<_k`O>*%danQXhEGyBNM(4!Kh;LR6TgZE2Im!wttmMjOxjCn@pi> zv0gr-cY`!J@ps2|jy#1TF5N?kz<5Hy6tBK(2$&o3{p{i(LZI__4ODBg!02zCA=xGm ztatKEo)HKLQ6OR5&@ry*a0n<^T))%~W}}rJiW(Kv!m%Z9D*E(G;>5D~Ze3!IZjMh; zcvv*n2&6;kk4!GLBy;`_OBJcrDe+yksTUR{F^NCSI>U{mm+@M@BY|DNb^ z9|DC;;K~Vw?;)`FgVX!hSgh2kut24Ko`4j|!Y=R+H6_|=;zCiCehW!BADh^ea>t_| zS)3So&$Mag!sTjhAe?>So@2XbE8Y?0LBN~{>EMGwV*$a7qcycHDYt;&-g;vmm^}#M z3!f)eGb##6y#4oIJgzl90%rEKDXy!JI6DL~_Nde2ldL421E(PhO@ckW7z2DKv8~+F zNyHry+HvV_iaz_H2gkwL=6r<$CzLD#*MEaxIN9h=7XE0B=5ZW!u|ckgI?Z**<07G8 zfW(MHL;{GtxpyS?dvs85^*JFEjj8d8h_DHH@Bs};0q6XF{M=A=wbAb#~J!CxF0Q|xaP zgoReGvmohC4MXehdM~Irl#_A*T-_;&7#<({X^G4?TL7{s3alna2Fk2AObT?Pez~q6 zV@afyOZriXCZI?^pZ z`Tu*m0F>YO!PrBmQ*u0v#BeTp%KOJ(2Au@-X_L}0CSnG|-=5yOF2BBn98b_yBSZSp z(-N|Mnap4c5eS~RT-(R@v#A7WLea*!S#Yr-vq=zc+qzu63U;|Pdk)f%(YUz1x;gnR z=6@7RIj05w7(oL?ONVg{H#H(0vM>-Jiqyd&$W*4uJqsZ48prwWoQMT7D_BMW2&qK$ zVlk&eWFq3i+9dQ3cQD8H_=c~dpd@KpbR|>=W$6Zfgy+CYs>T&{$P@rEoL8tyWo-_h zC8g>(Lx9AX`0N~zn7AWTVF!-(b7!YH9_~N>PVx9tsKO!Op&)PQ6BA>5DwXvpJ}2Bn zxVNDX!P>UU0`7$DL;<1P+e1zcAfjH`X~Nuw~A~!zmOyU2_Zl?-F%B6Ap?co2h** zyYdbtX~|@3jbC`Agf$E(xmp`Ee7jvPPgid<|1MoWp_W1hvn{hd6Co66pj*-d$?j8F z%!r`qm2ndNDkjbBDr+V2#`%{&(y{9-@Gkkfi%ngsZ8EyfoL_UzGVnICoS$Mr3|5tu zsn5M@gt3N_DUDheMu4+xn!~GfL{hG|DE>;iDONvWl96n8xi^-SnEnXdVgMW;AGi1| z2BYb1?YUD(o?1}mDN!c3q!YxodpuwKE3s=5R_)kp!$v0;ILumZy++=m(AmtvEn@hw zaB+3y0XTvXoqC8MrfU_SEVe%EnfJJfcL=$^VZ(yaa!b*;>Qf7xb4n6s`($Gmz%|=vyo0`9YB=KV}Se@rXqg(5G6+cRYX(40E39q zzxoLOf<53I_`k|2Qbd3H7k;?&t_%Z;HsFh5s?!1r)2`hk{ruwRNku0TMg547fWIoODZz2$)v#U#Pinkapv`V zm*;iM^QQfD%c*y_e{Nu51_VMLgJ{{1nf(ZbC$~!@rjbToVf&W1d z3&8Ka{`$9;r@)HH*%x?{`>Z!stxzZfj)`;0HwXb>ix~)jC*RK(!XFagZ4=MY?Qu9C zwU)zfH=Mu7CMg1v)PFqfw=2FLwna*#MZUL5rjI_&rI{jz8pGV2Cx>*7kZ@p)Y2VAI zOZmfSMeUXUhac|LCUrj=d{|?3D%65+=lBsHRz zcBNJ(5eiGwmZt)sfxte!jCFNRfM^rujOVPfnL#hbp&C;iTaAPp)nww-p$gOMXLrk3 z_Aub0ay%Kw+V?CzEV|0_@+s@<--%7ytVP*?Y03;K*R%5S7t<-LPuFilBMLGf@i&Balg^o-q*lc5(f z`z}EXFEbiS7#TkRCX+=t?F}!)7gh}H#}e?+VYbi3;i#MUMuNPt4e8e-XIHP*pm;kT zu|bC6>E53G<%$&S&~SA`76HDUou<=px_q?+kGHsRxB%irSFGAD_0#C_KX&R=a`+)4q_P`o1Y?@grJ9bbb!1}ZbVR9f{T<$z*nOB& ztvs-eW=&!3AdZO`5IcN1a_#atOTL+m*JoR0C6ypMM3K6CEo?&<$Ld^kzy8DgvGiP; z7IBsD9~jj_QLiHE_F^!L36xJma^;M9D)z7g+lzB8Vo&cX$<(d#KgeC{q44c zgM2*}rWx9)CGI}Nv6uer`bOGnN_vtF4QO*hi}~%+g-vaRco@D-hsGn(njPe70UkIT z9MXLxE@t?(J+4BOp5A>HRqOQXrYDn3plRua^X<9Uuol^e?{$4y;T%1~y%Xw)=-%Ab zjmgQ#_pG|K7C2ag;eTkY!^x`h^6?S)WNJuFOv;ZGBBpC3ngouM*?d^0zM;y_{ezja zMG-+F(oQ@928t9xm)huL^<&HDEh@R!%*s?JTSWy`I3iXaD899T(#qJCB50H{lkq|r z%YL@GewcWi^#LEG@jt3`BF=&pl2RHes<$k>NfQ~gt-i28{!3n^o9&vomD}JC&V%=T zR|~|3Bb|&K|iu1vyt`3CvZw!Z&L*E@>qfnjn7K`M*zP==iHY3Z29K!pm$2ya4 z8X{e@kg{=`%|hiw9S!dZF=*)OGcK=&=J>dVPd zBJ`mh*qEavFcq6ju_%PiId|2en-p$Rp#rnB^X$b@oV zQJhp^Mzxqo)WD2}K}?Mmo>Tn7oz5Wu$@t974$$teaWgdgxTnS~;%c)eg`!HaVrK)) zoF$8nt~GREokLlpbk^7gQX_WI*z?%RPQ?wfXOkA>1O)}%Xjxcg*@#+sr=+DZ0+X%v z36!}C=G~u+@}aUE1p4*TYAF~HpGKh8By8@|10KAUp3{d+O;@(gvG0kuihf-^thT~T zfDJ|1IQiNTVP4VuHpckL)LxDIG1?p*dclPD2j$mpRdf{Hv7jfkevS=pJt(uVDh3N= zD(o6-Yim=h$4Ka^xU#ejjCW`nV$`hu5dws71f4LRdG*K9twn92EYW1eK3_?4er3wK zGcFtTK;l1;js<^b8^_G((a_n~?F!Zy$%Kmtu8MtZeK1fBCyK}|s%xI$y< zVR*JQ9&iU;nKOHlm`7bqs?%UhWWN#pu8sd#UFdfI+G+**UE%tOk|6aebS`4{##~;$ zEY>RSw&wU)$AsQRbXGrcjV*mJ;83Ap(A@@Iv{g`9+Hu_*j z9Z%wYHKB`L@zNZ;>?h6-?w8u6^AXe14($*FpnxfIx{O-o6xR=P7u75y)1XvCjbHin+J#DZweP-5o8k-7GM%(`JWW74yvxK(~2h;hY**5 zK@l#%X@Y=&Am1Uy|8^z|Xpw9$jL`uC=}%Y`LMs4b8it7_d~QoZ^5-W|Z|ipFH|KPH z_KM?l>dLLUd&jN185Xai{E}kdFNmK2Vdl0U;^Q^=(RUP+1)|9r7K8|>rwi0}A1IeP z@2uC9Kz`|V_2<`Yr!OiU2_!-7HT3)a^`OrWpb#BnZdYo~-x-yk9g2R=S7$AgU~cy{ zmv1|RD5`mdjl?maFK?L3_o<1rpoC4fgzv`8_IvjMByc9G;+u@eqWV##S`Y) z00OLJrjuZ`maKK=8t1LXruH3e%^Q9KUK5{Xj{AWND&4m2Y1>vko%i9LgEx)q-W({_ z?w839Rdmgj>Dm5H-c?BQj%i`=g6l5NS&wzQ!g;sY!U8<4&0f`aG!fyI1N%2eYx$`8 zN3%7LPsOxf{^(-azC`(+AcSuH!i(ZE=Z{OZi$~_qCK(mw&QgL|YH{1HFCHESObUq> zDsN52M_X^CsqMB1!wk1x7~J?Tnj1_^QwnKheF$`K=J$3=BMbDe47H=!P~-)zCY*_QtTTp+=yWGn6g+xgc8%E_0*8fgl}O}*Kw1&?2su)&`FeH zG-1I(5@!yq%%1XVQLmRE*fx3jf!)sgfRZYm9WQcQ>~r=Lffpm{-QnWA^cb)XvMZQi z)}?+mpdvI-Wlnn$;bCgP>FH^->cd%`@HN&ysikJW^w@FxAU%=AFn|a1`JcHa3NNy% z;Ft48ITD{phuAbA)?im`6u!UmU2joNu+R;t!r~^5rA}+1lFw4tmGgND8O|EgVoE(s zv1x%QSVh9OdO6o_Ba9s@tECJ^_qn(KhqH6s&Ma8aaK}zMwmP=Wj&0kvZ5tii zwr$(CZGOSzoS7?_ANvmWs#W#sadwoBzpG)M?Y9~lwWA=eZ#d&i%tw;EQleqmN*eD! zYIEd@>u5m_LH~tcGzR*HF1{MVQjPBGWUY1JgwaowvaUWAt6v zp><+ByfZg;Uu9ZiSY#^U+Su|5h1cJ8V%yyeU6?WlZ5E(X-{&_J@cy(MUajsJz&R;zSt)Gu|?YeY9Nw?9lv~d5)1BMt*47)VP*Qc4A`$Z z_Lp=Hx2{qGrqf%^{9wyr>GRropn2cQv)zN=U5Qxl8)*42N`h?|cKub?&t{GRnAahuT|>znYEmu!~G!a)s65 za$lIhz4V(82#~~1bUMz5%Q(pQaOckUXB-s;W$|gaxhg$I7rqc!I6l8}C(E~C!lIX& zt{c_tjB{Q{43JS`*kMS+@;aN4@DeI;q}bH)VIw zi++RIbIIs^TxK7;;p90)o&MzWcZpi&1BJAs`AAK!<&i^aTpf+UrhE206i(JGqb(IL zuPy*CD6b5@-xvKTcdP!Hl6wB+q-SIWODJ(l@iU|JUC(WI8L_{a*MMh&vyOc~jXakMuX7fSg0%uY z-n66(C@OQ8wD%Ab2)~|L<3VdzOR+ELE1Nlh>7QR@FARLi;fsLYA;Nx5xP}_B;YqI& zo6QU-e3c$HF#g{VZr^@$k5WV1P44JT^4lJDTaN=tO$q%vzrUs!V<-XvHXnZ2lDVL{ zsM#`g~sdE~J5C8si3A=extb^G1p9_0mYf6Z~$rsxNA1tBO ztL9Fn1D+8yz$mZRH^WmBe5g(C=raQ6;4i|sM0D;fOP@w#5!OrdES-GX_VD9kK&M?B z*ou#?)kjr0FAfZg=e~v;?n=O()<0=!B}~)y!)iBsB56+KORbb8m7va_vRer2{gtr? zca*7TdqG;e*{v8+L|ShdW!d7X?&@u0Y|`Wqesh4SF7$yfI5KFL&eYkC6_s@ zwDp3OS#;Gw^SMbeY6N&YR=EC9HFH58HP>(Dz_M8~qwg4KueUc2pfPX(& zo(+Mosj?4b?7fXbEzjy3BBT{#AU7jBLZJcCh%Dqx0UOOIjNR5F@P%RX@92=IBXrOg z|)%YpMlG2$#!WrNNr{69_ zFODPyij~K?jf3mB_1C9H9RU?ymg^WuB#&}#?TTj`Y)}}?(N}A31t^})9||^6QHR>U z^Y@kngOX(nce=VY?_YH^erF)MLT&W=LFr>f#KyR|4_P)8Ed^v<>Z4~!;-8It(Ma% zGbvHayj|DTMGhbdv^vEtcw3ZH>Hsy4!lp2_`x?-H;j%PHY9UvDq#%CNoZ*g+%V{l! z%tGPiY#A=|2#z#SS;iI+QCWy&^81HAgLqykr%%TyJUWWO&n6kIVHCC3Pm{O2yk}r~ z+YtV3pzM)Z26k~ydi9(*7eJ&nr02e!>j{I#`TkM+mzEM6ja?K4WD@$K?0EF#WwFQv zMfW7#`TC@ip*&4@n_vHt`BV=@GTG|b&}u8P@{|ARf>?%_gRq%quD4}CyDgwn+E%+6 zG~B?B(vshZUUUCwROAM}4HLOJMM2y0Jr@rbx}Pj?71;??7nC-N64RbJNimk`+v@Q$RJ!%YgN`L@8%Vi9I2e?BYA<=73mxs5~QMntKmLQ(lYpoY)JUeM9tAXN3;U-k9%JW?kkF1JPyl!uD5Nvb?Ef62ujMRj_pF zTEH{i*#R__FgD~f^0uT1IN=eFyAvx_ykGjK@D0jel=`im6y-LvbsOf#r4%Nx6ek0 zSSdFOLbuI_^fSudo&41x;^8!y<&PkPs@sK4RnPs2I6K}e$=z4QCKmyFGDW>Yg{#ma z#nD+%a~DbWU_BBoxp+Y)tl%A%-%QwYI&1ZAc`&27?>{crh!@VaV`n=))|`;qe#*Z8 zI#uyfvvC($RMd4mK9Nlj^p4_))UCc5&h0;y+rD^&^8W%X8vo)-QkQ44J;ES&O5dO2(eI88mp5%;E$Q)lSK&2wJqVCl!Rb#Lqr7^7%&+~ z2@B~=?1YkZW95jIS>%#|cF=*D4Ps>YrVLfJmwyFB3a?+x)-C{yU?@iHml@<3;i-13ovWG$^$B&+P)VL+fr|A`q4lu=J zQB|zTq)1F?)b+OG%!$(@h?I0VH$lBJ>&wX4SEiyw$VjYL0oO_k0Yjl`B* zoOmm*J?Y`ooh$hSj0?TUR>2FO1)F zbSV6)`WPM{J?Z+6Bh*F9z#^XnS>xp~%HUa;km!IT>XP*ms`+>?^lX*+Hg)sf5LrPf zE;UBNSpU&8ccD2^4kxPRW;3o}b_c^9wFjMH5;2c|jXvIzLxOJ7OB^|jJI~#QW6{$; za2jP)O^X^zW?0VezE|5LL|D}Emqmhz;v6ufsHAB3ur^k5DvzZVOI6-?!!yCc~<^nln>Ne+Op@;@tr~WM9SrpYCiP{pv zxrUD2yD}-mAQkiWy$H-JEMwtmPOphkF$TvWnN3CD=q}1pw@r^=i3Jz_B2KESr{fv* zTVsG?nw%!#}C@!UtjKUrM5) zTE8gYt5`GpTyoMcnTJAwRyz5-$v^OVnWl7}H*`N%Xt86^yjg7xTUehdW|8 zJ~f_KDXQm)Wr|R%@_@SUgQjT2J|BGYsZhbK97HhTs19>`l@pGFu^n%DQgNeFR&uD8 zz0y^Cc*rCIR_gOh&OY|XTP?izo}jzFnV&II-!6@@{3n8O5{u<@{?+>XLy%G> z)+yXib9u~B*u+zC-^ulu_bnb}R?9hH5|#C_*b6%GeSdL%url2$-oFo~{M10gVu9*t zR-vIn^w7aYl6k>l31AnYkZZy`xi(g0*W_}W+}tMEc;NPF4d; z_$-tH@Lff_lQTN+)9b^xzL8aZh_yGIxs8`pW40dvJ2_eR#@o&;h~WT4Dm)*lwZSs% zw+}$)kvg)BMisl>jE4RRWm3^qEwv#=;F# z-5pwr_+7*J`T6<#`}a<_v}Z-?!}V52&_iO)xrOv8B-`^@qx;uKTTc()NjkzGlQ~t= zH<1Qb@5%GIk2)>^GV_O}m71m#%&Pk(FFUWMtNM253;du)aMpH!g-6kM*{a9K_)3i~ z0-jT5?fuP;Mut-O+FywGnh`pHv(v(5{X+G}(@fV*=C{Ji6M$@HVS>%lls?6}I4NlD6~g?5Fnw3(RSnDT|N#-QhV{aH}8VEd-+uw}2$>g@@_+s9`2 zH?vlH z>sjcL;ss0Az9y|lhJ^jTe5CB%$fdIkQJh!#c#Aq$(ZOm1FqBhVY=2fW5v8Zx$=WBj z=oW}@Biay1*ujY!V9H!5eEP-p!gx*wh|d#Hb57cj&pFgN;eiIRf)TCOf5bI8N9Ba{Kv!U@V!C(@9 zC9^%OCuQy49sOv6_L1MuK_z?FmG=1Y$XS9X9GGIYT1;c4)*q50)*e=BE?(8ztfrf) zVEi@KI9twp)H=F#s}|&VMPC&@)*@3HP9D~_J`Ddf4imUNZ7$=cv!Rz?(rWayE2`5P z_iu41>f}6hTo%!G6FPV&+cj2hrBNu?#J)1`qM^QwPXL3>$N=(+6|dlNpjrE9?qw#TS@Gt0EE=QqeDcL5TQtxTW4v>neKxR{qp zY-+ZP+)kGYA>Q_^J)e`NzjoT|Q!Wa>%dg4mC;P6ht{@^Mi#ui5T(UYY3o^|53MyXa zWrIRPU9)p;>x}M7;Bo@g`k>wqMq=4)MbIW2>YJLH8W+7R@0Y!l13%sknOv?`?fJRS z2e!7L``+K*QMDR8J7O{|R?tqNQl8}>x0_56CPub8Twh*ZT)R&iTIx7@n}0S(CL3x8 zrtVgvjaG7u?moPwdxqmA)%4c!^g=uzcJ_a5FzZ!Uj{5M_Z0CH=kBELJDv+db(1IRs z{t8q-%ZKiZ&%y+v!Z5K2f8>rd;z2|zCML;0s*Q?twl~Hom|HBvwW`uWR^h~*OhsSc zO)PJREM?hSa_)FXg|Dt86IvH^@b_@gZhG^Pf_2meH>$^L?f<6BwMSF!`@F@aLf>Z& z!T?~)@-nf;R5#S*YnT!|6u&G2nw+N=Rju^ zViRCw5N2fmzXScM6GBOGqlGPkJQqnwxG(H?tzYTyh({zMRurJJKV3xRXb9&uA%hZvf{5wdroY{;zqfBPbE$J);4arTA)37d0YSB@33z3F?1?^boMZM z)%oJx-SK=XU-l$}-NoEbzP-xmqM>hmUPOW0a*c0X+a4cOtT)<+dwZdozOsI9c4ge` z_%?T@e{U8s0gz~ZR%X=j3h<&i!Z@$u(IOJ-+_#ZXjZd}U#$^3A; zV}pa$+P+yET|?T=8p~xNI|ytY1yg|6;;)GYufDxL9Ym zj@w-HW)R+GEdEvEc`qHA-G6#?h3ury{oPx(T&B(Q@Z@MaPVsJ*QtpqoMYPy{AL8;^ zxDJ&xeV-{Um5}ags+|(;n+bIx^_48^kFf0)5-vQAT;*qGxziw@4=FaQPi*+oi_V`d z3gNBGc@k^$2`+&Eg+7Cf)!D^DFWK0^4IOY%&(F!X&8by`rq5Ws@p7la5sriID?B6w zl{1W3$+y^|+k*+E^{HlAHVLV$f^btA!bxtPdn<@dsIq+YiG}A|AeuI52`mV0T5jbj zjzxU6WhKP3TcxJ=*`6fMHZ&D<+Ol!S=vBVzw-J`_)?@sYkAw8@t?DDLOU8yV@ zp=HyHaauWkDc@QlDWZCx&HN~=q@6W}6*~Ee@t^sR<@p80FMaChZEPuYG>kIJeB?8v zCVQdh{y*8)L}&kWiQgqwmO@aN_AuBfRzABFPaz4M5%Aa2t@`hD?v(d-$z}GSgr-Mi za5zDf;Q-;)q;UbsWxQ%V1@c(5D3W>pcF>h}3!MIwGKQ~0NHavOBi+|k^uhe0t!p)^ zVw!5D=K}ak2v>gH@{59NgC2eBU6m!}+o~zq5ksctm$?I23{p{iD`DJU`hcF?8k<=WT@# zSns$|9IAcN(!vsZO)X=R@ zFMVv*TsEsPkZd7apfR2-6u#$kDhV(h*SfRIFvRF@IkyQPvFT)Za|E0t6Mb)nofA}|Z_lNVwe=h!<%)fFvp zp%!Ww{kg^+YtcoT1E4A0r$v}cOVL-q&n^B*nF)@OtV8^96~%-Aare(#_QxXB+4ai6 z1Hy{^rCOGLkLk``f(x|i^up&+^G9qx*8T*Kh$z)@nUwUg|21?mUC4}Jkn3=U;%Z$?yQiI)mj{0fz1V;%pW5&&Va63*Ff zoNS7i&tc6^L*^YcEP*)LR~1Tz&xDdPzL$*vUnL+*^HObasEc? z``k|=hm?n_VY;4bJZYzXxx6z@l=vuBeAG`y@+;+h?kVey#B)si1+-nMx8(jq7Uudh zy^zM)*oS2UJ{E`0lpCYX#^NRE za-=ZNRj`#$IWEttsPujBk5Z%e?T|;eMFL;|wy7l6rmGSU zT3$p%THn&dh@H{14S(p5lJGv8d_TFX06d)ue47dr;oMwhSYyN_EkJ2XZHmO&SL^I9Okd(imj}U3NTlM2}Y)=27578?e9mz;Sx-h@|0Y`tx5PfZ=5Bm(ukmE zWK*b=>9+v}%;Q$5P>E+1_I}RsJ^j`V(N%QI;r2gSQ|6zW2^#%HOq<=IeHJkJ~;7=yo z^8CH_rLTZ(5v6!6Yd=HN!PL@B=O{%0NiK@O^ifpx^+z``tVQ$VjPnGKF@Iv< zz@)-?g>wA5k8+1!y{TaZUF8dgcU*uHXCi7u|T52a_UUpZA8{e!}YTTmw+E$*NBJ) zcSAiY0E+Bv&3CtAXZqBX;)TqoVNBrkRL%$_E72bE6-P4MuZE5LF8{uHt+O^E+?l&S zcA28XyDSEJ(66r)oQ}SnwM`ZR@)m6i5_EA|v_Iut=>~8zfB0$IRJ2TXaa4e;66 zgp6=*~7M4O9gbf9M&s&1`lVF)3NR15Fo&m!oit*k)? ztSYoT$*%oP?doN;qj+i}P-smoS6NI*`ZStS|BNIuP|??5B`pBVe`@+1IVtQXuUA!~ zImYq07a{N+7ro+8k^&ifsvL0dz=9uzoB*3-{YbRFltHeW+9^_DCiPBG##}|=1imaH z{>mqrrAFVGVYgeXv6*;#rbVRXXSAkx$u7`Oe{ugbA6V@-Os7M;-1+^+ZQEZ$PQ68} z7ba@Z?M7~bo?G#4e-c^Mp4E=5%7Oc1stKzlh7MoACLPnQ7^hJ`Rcp=mVn4Aovusf< zRg`qjOmyiCsm#^vd$A`w<4s2^4Sok+omHXj{WcmY`a?CpFB!k8bUKj}`6??1c{k*q z6(_uTON32(F&`(YG441)a)j8Bzjm|qm$mQJl@h$tA0#~i_C@X^8dXik{P8X@e5)W) z2mXOz2}k=t$j23|`69PxlzFh-PY6ebmBk;urineM9~0kfLKNs|BH|MDDSw+JT!ph= zdKE52Q>4?*-G(6nbqS=a&*-Po)2b~XbdF(AE=EB-z1XQoiP&}Dtt6|(u_IcDy3W9a zzkB%=w^Ph%bgdi~3<`vM)2p<#ois`QE#*#FYnP5sg+wjNTCOh;Q^t&D2h8ZTuSm5q z4sXJko^tI-!Pdwqu+7x}zWe=^Z3w(^KukC@XNdX_@d6Ho70%CXq654qR=W~V`#``| z5@cR3+x3%N9}Snm_XMi4{RR)klrSfu)nO@6{B)xq3%jl7OVDrXQgjQo>Y?{xovI%+ zST0Z@{>Gi}$$0ATKjC7BMJ?zyO5|1S4Z{@pCp z)SkEd1cZEo`ho1x2@;O#1={bwO`C!}?|_v0YkBcT^*_ckHo@*r+riCpSyW>g1Fyoz@Tox@pxBoe7F`bE~t}GAPF7-naw0 zKP)mcdd6>mUHrpvZcG84KGGYVmw>B+BO|L0K1#iw*Jhpbzfz+bVd1-0Mj4xh9s7=u zh$qN-^Yj{A6pUfx^qGF77xS+t6QG0vFW0v)t7jI~Cl8Q;m){XNO&3jv!XO+l6Okd_OIzcE^v1+Y#_yreJIu!dr2j=aZ4+rLk zRun}uW#GkjtU3no3%fO1)+DVK^4N)_vH>k$O3sCTP)l)wNqGi>)J$jk6k>iFG=mnX zd9xHaUJ2B@T^?_%e*G5V0}auVSgP?cpY4UqgQvv718;3R@eVGC72njCB$x^nBNC|1)Y27J}3F*Z2!h)fL-(5P@0~desa$`<&xImxOSENn| z5xd%k!XJnd`rJp&nUVK7D!K4hcd~kl?t?95WX*4fq&rhN82Zf-Q!^Ex;KRRN_Qt+m zT_>){r(=DFRTX}?GT7V#?`kzUOP#4?-2-QLhZubIsJqsLA8WZ@b7`8)s^==ZGY#X4 z42_4+-rdmw+)BaZrmanr#ibt%xkk{N6(W`(6GpJvnO;*DPMCg?0c=&g-xR7WnaR5u zo4qq9C02JEUyB6IHBaU>5gC+4isYVl%Bghp+;U6USj{KzXK;29-M?Uuw*iXRh`|sK zceg#b&bK~L5|;>OGbxHOAjfS@AAb!_zFL95fDTSyLV1(g`Yip{Di?3^B%bV)FgM?s z4cCJ*|Tos()|8v&yJ95uDzYs2*hD`{x3RYIf4PsHJ4B95koek9av@&;OQs zNUL+Nbg(K@csWi=+qDIaEcvvofb*Awx|h7dKXAK$8w@YLte0(T5Utg6aX_lxlLd#B4)1Z5sc;e8Mf2KVmq9^g%|ALJ8spjW(MXZsoi#$ zws4O!zKA|AV=Bju(?Q1 zvrM%bLzk*jiSW^*oLU#>7F7B(UMG=EKeaf5FN5PS8>~OD*PdJm zF2FQ+RDGty)TL1n+2c#`_s5wiOH-PtO!+%at?D^f@30}qIK6wfTSFRm-b%cP!~3G`-^ z9t`g0A&EDKe=P^7wE{ucYMaVp!9v84S-`Aec*9O_^v>+k6=DIrzY@K%bf--L4+6Sm zW}nZ?0dfIlxV51?yrz0Cmyq*I3~rWz2Zc}kHYl-EO}kp?oLmtJkzK5`0=vlvySqLsd zSLd2YLBYby^q!P4!7xFN8gbz$J+{G{LP*er<-8QXY3^MMSH+b5&aVx1FY0p#H(eRf zdi->$@i9pN&4~9(^cb_zM=ph=E>SkF zhD`&{9+v_DYkP4*y&_{HgSqgbft;p~<3V*=K!^0$6PL$(?2k@8^>n zs2kQmN$20Yqv@;y7w=vDAnyA8B~zLi-@1=&V6yIiZH+=^js>BXkKl;Wck~w>{W3mY z?=<(Jbdnx?o-BO(!_~Xozti0|ief>z*we0&eo5|txE8gQ`x~b-Sz30@UM^(;k(nO> zR=vC8UZ_Zh42ZSJK0jgwV4GYY3ayU~$GR0F%SL#VWbt?!=3h%Wp2q6LUbVlQjWm56 z>wj^>daiu{2zRq2ck%tRC?G6U#yS^?Nd~c9Jc+lD-fI4yrBPkyKSU!>#Ryj^28H^i zU$QJ+7OZC<)1_1Ld5jSaxr1Qof7CVNZD&D3?Ccb1R(hN*CVHH>X+5!KOLDE|=bf8` zZ3c?nJ@TX9mUUtuch*H3^!RbCxoj+~Ui#=`5%FAMI=PoQ%f2Zfm)cm(flIRm(WC08 zHWe$28GE2!6cLBs)!!h8)_y_bF=U4v#7LM_C!&qY)={Drwfp&(Ih9K0_3xSmLvU;z zi3bW6Sm@=fCEiZ%lfb8lBO5oMts3Swr8N0;+5}uAlq~+tTHiZ8nUJ8V%upospRzwf zhN4_Ad3=d~dd~D^xS%~GATQ-|1)jOKy=~^i2kU3vApL%B2MukEO5F`|t`#)(%Brpx zB!hvuObZl8O53w+NcmAc#!uvc=BPrLt?3$kfOM4|Sb|c@fdi=xb3RKzt<^@51#`oG z`l%3k$k&y|0q6av`OlVoXEIBbFYaS9%GAPdtpAKY22kVqaP*28VE&6D4UI$pOWX?8->R@3lD5%H#^fJD!EYF`C~F& z=$p2;0rw)uICVB&b6TmlaRHccx8YJzxp5;HorS=D+00D zU)t+Yd03jE=uJ+QQdt>BVQ;-F?lI`y+6R#Pv$~C$M-xQp2}w6{F|zf4zm7$*~V7j`A=khdfMv%1-3y1iR6AEj!C`6DXxi&eGuy|=aFmLKyaXhpK zgZ;VvfJ5@c&yKFg`}&UK01@AQeKe)hiibuq!#Rega@C@jUHi?t#0vO4#B#fyAkR1xMTTD*ygyLGnH4C+GC`#O=+ZYl;MlVN5z;02G`^^y#+1N`+M zgk_K$h4v_qdtidl;(Ji*kKHl~G(kpOEEZG*9ka(dd8D@dmvvX_c4ew1QL0x1Q#!3> zX!a(olS)%n9xDAR{&$qX++v$wMY?I?4}Ub`ZsZmA=eoNOyS*&Mg@7nWAoAG7FX$Dx zeqR~&IAXEj#t>$?2=gdSQ_R{C6n^6!hYapBEm<99T$}w4;SQGG7d%g}O8)T*z59-d+ zx(!Tvvg86KmP83YEj~}}^+0Ym%p?VTNRIYf_12ZS1p=URv`p9}jiL8f_85w0k6ISQhbmR-F*n?ULI_OM;V{{N?}&ok2Id2lJ<}}k zY$ZgV{p|I#yg^}* zByhrsR4GY~+lY3It!NPc9~ zNT+|F)fh|qhSk#uIe3{2Tt6Ex;YNDdLiN;!pe$1eqic2bUo5`hN2u%uxk}DxL zL$hQR&+e!{H2%$y7t+c#hj*nm;6~f0y-!e3xA`O}gSaU~pT1?L(L)eIWREGHbg?R; zvpf`vc+lMJ(?iH--gL91_}RV!6zQ2_>xAmD=WRCQ=<0U$(7_jtcXg|AijsD5Ldddw zo9t3>w^eHK`17+13e!mgWe{k9xf%0lrs3rsr8qd_X)mhw+@B+mH5Z7`QW24Kg8dC; z4t;l#fm5^xQ?ST~N0hYj0j82P$hD(n`HjOGnVnFb16b1;#Y7)BU==Y;28S+My_?e_ zpi;6CqJUSh>q?uOHaLj zRJW8ncyZxDk_oZE2Ax3&t1+`KK?8?=5)(SlKH7FZUfo?gfi0^xyo=V+2F_kE_arbW z_KXtp<~=z9e&Xfolm+4Y6opARQmzS8beCD#qT6?7xv*DgjAY7_wt&7ik{v-7?68UV z5*@+fR#aEGJzoEK3^^uY#KHM!T<6LP^{zcd zVZ}(VlQTYM@Iug^oM@NkSPY-w1b`p;=k6z&;jf)5Z7844rNe?zQCXd_k_O+Jj0F#U zcHv+^<4lGeWyuY<%CI>!_Uhzz^Nf&t!Yv~asqHYbvB;L}E+9nNZ;H)Ou>h0V_Nq^5 z58YQiWB{yRq3BINij<5IR;GtK(3+FQp6P`RNu6(2DE!@-yXa?)l9mD-VNfrVc9Ch9 z0ZiP!{9aUcZLS;;;nl#LuN15tRl|H2O2RMqsYKm62^_DP z4%OVJGeaH+`SoSpiGmCKBh|}4DST=fs(t1W z?zZJej?r=C=@J_%$JEASFEpy`KYsQ*04@L>1uzkVKl>rPqY_(+;3@kW*6+Hu#l3h# zRm**td`1^~g0Q{VSbf-;SN-<{WCxon9K^ywvPYLh55MrceNA@MlE~X$7f3Zm_bR>^ zw-SR}b+N^}zFzrerp(0>K8J0Q2a<8aiBwj6V!`cW2E7d(SL_UU-N66z4@k4XkuG#m zg1>ELB=2eB%r<$fGwtTa89si53=hfXx99OTPQ-V7(?Heqzvkf`UR3zF4C(}GimjjY zWMM_23+c`qbSGc&j%a<~og1{c2Zz*Ew_AMeB(W8;m*5scY47w$dJYBU%=fb0{=sk- zZTj_(g}cGf_naMD&C;2NDvt7E!Cl&-GJGm)(-_h)ST+sjvmVkeJ9@>q5`d+&2_JF( z_4Ixyq-h~hpo^_?;=A0c8vLA1nc=;=>>%F>EtB+w z7=~%(WL1y1F43`ED-&uwS6!Px>fO9Y00wJ68R3AMnvm)7+?;ik1Z2lwq)JR z5e}IV^>#c%;aVMxcn^>IS@D}6m7USXCq=JorP{3ru^YgQvZ_6QVb=2VBcZfT=#uE}hU4`jOemB^@4=z?o%- zl-2lrj>OS5@%B)t7sfJ!32km<*g?zwntq)!F=rZ)Z3rvzG0qt5U zlSfP~2j6UW1GBu1lM!tT__=O}^~JtBist;X;FM^$rmISjj&gk6eOg=?(SZF`3pNJ?R6~bRb!8ty~!npp3 zDa<{+N?n-X{F3RgO*(~zjHd%*My0d8soa&+RgYRv&HZ{=o}d>f}7N1GFqJtg=`%-*q*ftbuC`{7G7F8>LPPcmn-oR@7<)SYlBuOby@FiZ^}i=w|M$D@zl32$&@efVa~5NGXAd| z=(w_VT$ZM=@(MDSSse|g#9_)tSV7>kqh~Ugu=yA$jGl5U!58E+qt}(=_;^6<6{*~x zq4vV#U*Eh`!;tA2vWM$g1ZEnJ!Qwg1T6cIpDqC!yNipt#1r0zHuDXSh!7Fd!i+)~{ z={Eo<^m%lUzN5EI)_c}PX_kkxv<(mGv5oq4K(HjjE0S2HP9NNI7e+F1 z+AvaQnQIiMR*a{&g9djO*$F&Za`3lTX^{Sf!<-}J?<_HlK>(6<*R4i}brEkxtTL#x zO1uZXDJ&#$d}#K#!E&Xl!E=H%RyH9Nx~;zQ?SBf6Y!ghJb={0*A5l#;w(1@Q3}+Q`7Os8BNt=r1l~-Qx#|xxJm(qr*^u{DgZMy94NpT$ zH5LBVk>$;2a$~CVIY_h!N{B)=(i*M+_Djw3e>LQ5JED*a;(qYjN(h5_w23YVU#ScH zok-6koHfd_%f?R@g$%(4GJMmHbAf-6taitqS&F(x7gmKV)-NV=|1PVoQ)i%`KJ}(%he?bY;M~6 zIGT`gx~6iCo#$V)RMpY8MR}aeb<4LJOgX0$|NGG`0+G{`hI+wc-$ck`jud|C!dr_B zgOU)vE1HimOo12atO##*;bZd&qqP4dami$na`A^O$KE#z!$#nw7?O;pudg`3#uEGQ zqYdz?exl(~bNiLdY=6&w(NN~Sd zx>_lt601b}CiCrCEcnmbQ*g7=K#ic@+GuzUWoQ6G)Xo}ktmm4pJc^?*{4>20i#d1s zX+kWH_OEXHRtDcy?Vbyk)j4si9$EF2A%SlCylJhjyRF z;P@+-hG6D7IJpKG^_A8a>$$N?}0>+&gJQ>P&o->mWOIp=iz;94lud?E3cPj*Wf zt#2b*-M&KKVPA-!MDIJa^$LRo*x2ru;3}0xqP6ku=i1B^Y#a=m^y?SIpgqJer7xaG z;9Qu3u;@dZXVK*2;k*v>+$Ii#A%zvrrt!*>a~Ibw?vi+OOw=!^va(!6gq3M|h{*(z zQhw!;#aQJ&>>_l&EqVrcmcVACRX*H$>o)vl%6K@@6seauTqq!;a8o~sjzj-8_;CGm zx`wE={)pP3i^TyL(sJxsZosD8tOamYd;*E*l+L6m@)|JyPjejRe>gkG#mcsBi>4~J z?Nn^rwpFoh+pgHQDzarWo(#$?cFtida>ESgpnhUn3D>yo}(v?M=dmq)oWuj}1Yir9l+>%aGR@n4~ z;8|ERAYAuBMWSRTdX8+-{HrfiwcDbugA(GrRK+AuM5cql%8wKFj6{9%0!_N59a#+g zkJt0$-7D{L-m1!KnS9GZm>fuJ=kGhRN#Dyi)M5#L^8*U-CVl`KIwD_Pyfuj06^ z=>FDx%0Fhe>AlANk6hNYn^}nY>smwARu__RVs=o=ax2{xal+QjlujTJ-jQl^hUvxJ(4lrG)YOok4^$*Q z4=eRWDA}odho_vajShAtC)o!D2uwWF4R_onZ@x-@!MuMJiq@)vhx;|6W#oMC7!!v2 z)dC!ylg`6os_S>Zf6)7KU(UB5^|TheC3=p0#E?2g?V_2n;O2$B#BDSzOfHrrT}s8w zpmH%mqcqC~6-f14L0*d*%6rbu4=_?Cnd)4^lJHKY!rBx8+5@B?L!w-J3Pcp5;jrN( z%vOyKQqlIi=YM0xE@~HxT~dCwrBz_?n?^wvpP8*Y1A8|eKYOk-Kk#2@cTa8Qm*27Z zxt(_E~XpZE7TZq6j%lVB62itg~C zn^h@1Cn67dg~02hTa_Z~`@q)BAgav{N3lDPck3~$~QMwUsnjBdCMRcMRYFF`re`6bcz-fN;hNE7pgNa8q&+O!KvT;97DDHQJ zVSVha0837WHS2NKEKs$uGU3;|ufI9mxq1^QcFY$rvmR)+d2O>5zf1RTW+2mTedY82u&LRSH6TQFXzu z&WrW>{ESPrX4&6;r`tFY%c3BsrdvFrw+Sy#E{Kb7^Fe|E3g0fr2O3IpKb@D#{63=C znA-w%1!!X*=eIa;w7oSRJta?8$l-pXRx7lu-Heder_XUHG^NEY;w_nY9ozytX^gJm zMl>@o7Hn3L zW!+@4$h5~U;68OG>K$1FFOUq^F?Lo1)QPTgbG@iF&$tssCS9HfyA~<56>-9wAPPOC zr_gRf9yjAgXXUZli!=ZtSa3AVnA%>)l}2=eZj%e2DGrlr*@eE_F-_O6u7%0+8k@`2 zaXVVA;>Tv~mO~BtTSmD>&gWkCg_JItF}%p^R&2|H_I9ewX)533Y)OZC;w_k?liF^t zm;tjh6x2`GUv$wnS#@__i=K%;%%I6h+mJxjrz~#z=f3A0rjhLNwyi3SbkZvq^?EY6{+KT;hWgwZoht@8x^XsTKA&h+w4+SB9_y+ywHPOr_*wbJ;!xP>d)==p7<{fa@T8gyywB6qT-xG_hO0y;i#WF2yZYua+rG{Io)PX-|ZEBrvR}6&Z-AMEjgZHlX!(1pWVmZ z%my*n*R0Kfbjq(?bgE_w!PbBNdE-a!9F2vn>rgupuW3S%?;N+{cHVxQ#_ovml~_tA zOWmB`hR+kv%l%WpaxwLDK&qP;s#KPru^&zCj#z)AKXwden$YV|0LH6)4dmA+d0rfc zxX)c$uVPdgnD?-p2p_-od*zrpb*-_%)zV8dL>RKd<_GX6ZicV%2h~9ypYT(VO}`0c zJp=tQTlx8cY~c^lxU#xaD1aGXjz_3Tm0#>&xM5?WXx`aIlp_fHCqKZ*bks8@`v)Ou zOHG`8N&=TtWj}GoW+DbhSJl1aXf)F7W%9fKcIn$nh0S+4CP$_=FzpR!yM+wnBRzLO zWTyZ4JzGJcLoEpz17qrR@+_|4F z&=P_7^WolddTs2U!T{Ce7y7gw+Fuxh_BPf$m8Qr>O1HrWw0*GgkEZ8_hPaJVIMe}h z0l08-HISA)EF|09vS!q%$Tg|a%}i}X1*Q0Fp+NO5c_P;rN9JTD| zC7?r=El0;SIGzFNLuh=yq4a+Xku;bu=|gdczBj!NS@dg+cP9OtU%4!et~mTs0e+wK z*u^gUAU2Skp~TIVw!rEW&q#{3qD28V*Lwn7kHw`fLbVHZgkH(a1;*1C$}pq1S)+;+ zUUI(aQ>#CQ+j(xC9ka7! zcq7YlT#2c<{U7Qqt-L&VtK2OmpVoykSScrgpkf+ni3$qffke@iZnQTuZ9$O(LG!4J z0N7a9YXV?YOeNooZ!^kX&hTOr&TczXts?>+)oP#@U(@q|EFR7;f6K3aZ(zl901dI` zgT>+5X*I=>sdB#XXLzs)7)CVc-6}q_J)xvPlnHkPrcVM#UB9Y~Yb5{CLEQGIIqW$! zV<2Dr^6ODu@D_bVT4qF`p~8r?$4z95L9g679(p^ys%W3VDVCj&CaA#2Uo!sGIDx#? z_gj_2f?$ISHJ zHJYw4ZPMe!I~a18<-w54OSt>&uQ!ArCCdXDSe%xDrhj+w4me%T8CoA&_6@Vq6?dc{ zsNdH4h!;XJD>)7Y)t2*<2w+RPX81qCu{|+f6$pJ+kgl=qz14)OaLTu-bN1>#nK`Y~ zu2+pnDV-5fmtqrvh^@C)h*guFTzI{H!S1_Hz1x*Fx_6(Y8pB4+^|wvtYqqj`1#xYd zs?%6dSlwMmgVp>Nkj#8`*Wwq#q=aAbTeW?^%TK|DMPGQHmjzyH+y!S-pmSD`bu zc*80S2^Gw&&%s}G9pgC(h8hEHGH^h|-(u-}a@n=MZNXW)%?)z>lo2%ZTPB)U=H0e?LK`Rd%(010e~4HC5JBS+@^UW-;zywj&aqC7ik z{<;1h9qTP}aG0#*~)pTP8aB6;Vf z4&EEt6*s9v?sRfKC47pxwZEbt$lL%@4$YB;x_+@eeelz$Wvz(7ox6-~=fq@Ow_RUf zPs#3d)4)^UVEBjzK;H&ZI?z*G<}8pn?BC`^ZWwBXk?584e#q($?)5@T&+mhD zbulTZq~a8uMb6_Cg@t}&B<--|Wj5-1V)&s{2;#cCXv6Pj`&g$Wn8Yihy%t3&@^GJV zymzT=0192MnS$;Y3FDt16U6hZA#6|H@P3>~DC$V(uUXU5lO(2RkVAJLvq8}hgm*va z*I^FBgzv-Fp%K`L#yv>DqOWR1Jk!bKS$6a8ry^vap3i+qX>(tcNgJh@hu}Bi_t_9p z5i!$&A!LQkzr{Y2hkr6(^gj@7k3CK*c?(Ql>Fh%o{R!t0>O~~%{QdB&FIXlg_*sB( zk*lAsa@)^J*^HF*Ec^oA8C`i3N%Ig}wD1O7Lp5Kg(4YYcVTue#?N*!Vws0w&`Fi-} zpN&q!PC+B4chjxlZ}(Ay0(3UOc#rh^r($W4Z;p1YcLczKy)}LCqgWnK6237Fwy81PweuxF_J-zIZ^56NaWKAUjpu48#tVxk zf9%9P`=S5E&p0pF%l-6QHxf*;tFKTC2S`L2fL~ME{HRS_znk;8pN{X_kS6nE@V2@QTi5zWU$M_`%95TUNR!(ZVMeydY0 z^XWe8dU5bxoqs-(TUq0VSGV?R5wOUQ5p0*nuEv()tW?iCiOdl>yjaRxncLI(Tvp<5 zTg&fLbv;|O7HW-j$7KvmL-5mCLEh5gGsDu~$*Jcr9z$cqgtq`#>KG5h+KhDpqKb_w zad@K1A;;>IJGM$}H^xx?QRyzl#_YHf#-$eQdn%3khlJj9tdGs)MumT92`4yYp5-uk z*$CeEYJOH5Dpp{CJl9dBl=n>6Rsv~J31*39|6DaE0;mPQJU5wl?o#>4A1Ybnqsl_c z&Qm#b)skHY-}^{*t;NQ=;J<_!{<}uI=hoS2Jx9KWQrKOH13iI@jK5$bflVo}Sw&sd zu5ZB6DG4_FQ?9pxXgm~(HBLAA118Kn_fy4Tvi>L~0OT2Lf#Jh- zIoSj8x?0YW{59#Uj<9{l6OU}av$9xzmcO=8|1hRuD`;#Yt_ZG?EBgQ@CUZy(Kob~p-SzX2XfGfr10IJ~i;0|xlLK7m#d#hSp9A+?$9CPo9-Ir@ zTdR`{(^WO1Wn-~-E3rZK7z2tB`ZPlM?xa3A{`!!9ijUik8{Ked8ovye?Z6S+dQG9} znQY+n_P)9we7NipzvNli&v04KLowAoKBeOQPd;;Fsg8REyM)F2qIIYb75B}F`a(x_ znubZOde8L)Ii=Smt=;O5$?lrE`Vf2najLE^0`_{e{3jrpl^2ka#n z({lUB5R}+uMoWd2=t{bgB!qd=M}@LFYz*B_jSwh!E|qQC4=q=fk6l#NcTqEkxSO_-xqK-Mk9tN$6gj-oH4$h#^*dG z!B%fYj9a(?0yV%FT5j~Oz{>*l$!LXzhn04b#1BDz|6Sb|NS-f=SUbyVu^9q4IUpK_ zei+;Nj)wg^Ie@DfQ|_sGr3v=%^B>+d`0}&y3QlvtD1Ly=v@|)qUjH{a}r@Bp;CY<`HH7J;;*2 zA|O8CNp*cD=vaUvOQb}%LUjT{==pYO+Db_^p33SqwbYQVvkg8?l80z{B^jIuD4YLn zK2JQ^0Vwx-j~G2u7tph4Z;_8yQ>~2VNT*Yp-2W9nZO|VibT0bEmCsy3Bn6hN6GzD1)_vmjitb?S=aG%D4FWIAvkBtL1^52V_0XF}#lCPV1eoqHh!$xhh zpQoz6`BTaRexB!M^-T1{dCpp6%8-=Tn#7ds)x%*Y1yGCE#OGfdpmn`O6+5q7hlW=k ze^BrBH)4L{zmZU$*-aIhTQ1?Hvb72nh&+hT{R-aZOPcIzq(us5f&AZ92Ql5L!Z2!( z{O7H!e|1v1PGRiyMavQ!qK_@ZV^cQ9>@tIproWv;s6BRZYMb)vclxGVON{ z)*GjH{N+1xhXv4|M+sM8=-#bVijs-Quwt9$2xO5T^m(jjm}42T(rZ^Ess5}3`6htc zPt-e%O#ViRr~3kMIntt&XV3Cf%unXO*@A!t02vJZq)<^V4Y%APb7)m*R-E}OSZA0O zm?Nm$_fzG=<%1%{abX^v5*l!*^BRW8m0c>Y_G=HrJ_DLH`89dIz&>RQ0Zf!bU6#eQ z-K=xHf$^{F3|zK}8P6C!xP!y2Op6T&bUFC4$ns%4qfr0t*X%J%6=VlTiZdUTL|xm; z7EwQR^MQ(3(70Xi&g!g`)_Z&v6H$kQbo%N$@Q};SG>E0MqoD_n($Xrk7#NLoPf_aF zF|QDActnH>zV-+4=lVtg8~((jHdj)6vj@+unCstk4K(|q24L#ef_`+`3ea+==MxQ^ zSsxqg$2)}~b`vth^EC$T^A;6uSk&IPe>47s{G1kAUg!qjs5EgK?#k|WeaBwl&es0HDUWt zSDku~h0y1MEn0uVdpN9SX#7Enb|S)3)|$Z+7O>X&)tz{oY0`VT;+U^25`oE%pI%_x zLRQ$W$Sg+?yX;F7URSCd=ow=Ys_1)plb{mMm1dLixbJP|Pn@ejv%`H?dEd zj^eKHet5X%Iu&_)y)lBMCb@qHp19Jr7Y8#OYK^aqkhNS(L~pqS&s}r&Pc3Xu7{`kcT<@s~~MC-{F?q>J>S;4wH5kW%>n*AAJ zn}T1JSmGc7ia$WE*2#})!T7Ze1-J4DK!!g3F27EEX1egXK@^uEFFus?US&zl2lCG1 zFgQVsT|t(-VV}d1XY4-FfsGqYyv)a$ZH&2s?4PDK<69MJn~pnb#HSvtA3UVXM>2hl zp*SDW{yBMAkI~zMw58i~%U998L!n5cGNJ)?uIZud&VtBzs)opB?BEtG{Bu7=13aCo zpN{?VLOI*7v$7&eJPxxbA9pu+i$z4?se6cW6eeP{bqou2xf06jxD)3Rq%sf?9A4##COqC6LwsFU<@Q6^)+PGyse?k|6)AcSUlx6BJi9eenKphyp30SsNK=~@ zf?CO3e6im`U}ErZ)y@dfI%;HlPX;78o6I_2REasoy52^8M40%X8#uZW+YGe6Je49N z%eZp_YmD$5jj{{LroN-G9Rp|t4gYwhw}LMh6V{-S3#RmsKcaQdDJn+91m*4{i5%=Q z)pM-_XS?=m?VLL0By8pC_4(i41lzq0d`ohRh9+JNqcJ{E=6#vG)}B|da+FN=pPjqu z8XQ=*J=c;5>{yQtNo|uBbN0eH)bwQrj`Y81c)VM`kYG}LQ#yC@v1bK8Bn#A#bp9oxF5K{@I9?C4l!9MI^z2g3 zKRB+)QRUVKQ=* znhqiXi7BL5B`W{v(?Ut)Ku2w=TgfnSM*05CWQnT1yUUVoYkc%W!nE-_wb) z)lw?Ze--?ybBLx@sN+=}hUX(e$L&U{RprVkZhwtR-8Pko3YGU)O!Ecbyd%#kL9H~k z{)+3m-nLUsgl4zidD-OeTTpk@^oaOK*cjJOj`iY;b!DFd-I&@FNq(0=?8 zZS=s96>m3J=jQX6T6g#kx0v2KQC>sBPEFLb_~u;b<^2$@O!52^IQ19=P=!-j^~_RP(iS+BjU9ylvT7y~>oDvm`WK@H(h@tI@s zfzdtuf%wYa_$ecO-U&yziMfyYqjei?@uxT zRihGON%5I6hLs6HHpz{N?s@Y$ohv(Up6$zNNija(tu+FeOswCU_$6*=E!=D+Y3Aht zp9G{i@TVz^*~8X$%Ol*P(4ZHCcmM}mk@4^(I_b1`K#o?JY*`H)_M`)c$}uQ;)EvG< zqd1QuW#j-yh5TT5=Cif0>9A7B^uR=vu5s%uE2pciA7>nJc4B{m{Eufa+&%9FN+BAp z(2l-<1B)Y*D9p*NqcP8>V0nW^?KRt3qo^WYsL5UOH*5Uk@#U3rO#+v>+2b7DLt0uo zc-ak$YmRexZ_Zb&P1X7KyJmd31vUNGZdAAXjJm``+>>%h2|{ z5jBZney(N}S{sY68c1>fC}zs`V1MxPFF0$ za+c4@2f2tEJE}3tdl zBk8OKzoeH4^X+!Tio`(Y7F8a}^Dg6sF{&n>ax#zJNpKN=MEI6+mbQi8_WBk! zlbLAk{B_%3k4ZxjZ13z;=tT_C!V&wOSCc)0+VAZrm0T|$$L-A>LH1Q4%Y}7MA+tml zBm~|aZgQ2f{plAy(Bl3vCdl)N$0AciXKrbE_E9=WX#}CU(YtOhKCt@~Twh!ah%bIL zo#07lbjS97?bgBJDhl?49+)V^Sj=8}ZI36q^KRAv5MD?7a)ekyjiFbdHZ$%zc^{gF z3`M!yTkEeLa6HzHblM`~@Yxb3T|QfB0p%W22?}~>?9HqTPN4WYkS*)16@2>5CbL+z zYvhxdN!rwOE?pghXPVA79W!vfJv>staKCtejj&)4cG0#h*-V}xET*|`9mz)MD$thH zlpvMKcKxyZEoRnAK)^K-TbJpkreiH+{Vn&buV}29O2ucXWq@1?IkKUJVw*DPa_BbQ zC?wOs6X&zOC-6Zg@z?&*TFnQW4CO8UMS>H$WQRJKu=y6?Bhl}R@y9B%U~k@Nz5HHE z6r!=jlXTJ4jvP|>Z1qOXp-ZL!X{AzO6unEU!ZDqs@X+{<0*50>>^ARFlf zz~MK)kz>8$n5LG_J0^!pnFQnR8QMmtO2~nFM@;UeL*a!iS}STxnFw6zFg5`{LH%K? z=WnJ1LvmZFi*QoNpv@qwIT$-4jItUp6(gXz=*pjo-?@mL?=KftV)dTGGsEtO;9J2^ z8<7T}`<@hUYFo_!5>Pf+7~!<80kL$s@FYW|z{JH(5hG8~OJRoL5ygORCv6{fbOK$p zN>J`XS28l@vh#qpN*gcxi2{VhsRXNXMfOY1V8@z89iJI<{5M*ZX%=Ce7I5!w?z=D$ z88YhTmMU&<7FjMbvqtb*q+c*>;k~91{%$DjwSWOth(F*ePYT;JE>p+D$;Z*1SIhL`+u+&nV3cYm&O@6IfU6cIoX6n znOXi9$JJpulYDV^r@o1}%j}sVDjxWH>}4UTmdRpL+{7W-PGh7l4$_7!GSCTYXygA< zvh``pq)f^q$Fi?nBhtG=fb+oaRiN(f+eht%JKxudU+$Z`z^t!s@7G7;D5}C5avu>s z5){}cG}oLz!_8Nr3=S9!CS+jC4-RNSNvJmJAj+?uK*7Vj+K(^u{=OQRF*Y70jdunw zUyurri63j9w1FTw?2v%~%;3-Z8juYCQG3p5GX$NB){x<_m5>Qmh?k)Iw;0?otkhT7$6 zhJ`cb<&>15n8#+AuiDCsR{aN$?)Lne8iF1SJJ!t%Pm8E#bAk$5_&8GF-AhML>r=}w+!UO zbae}R6KdtXMR}`le~Mj4IiqNT(YYyH{vkdjUi)RH@)Y0=#(Y(v{7qj8$yv%#3oNXN z2kvKi4Y?E1io*jOj4(YJqzyX;#K~k*QFu1Z`T8E~Fn!6jG4NeIX>a*1?n%|FLPN&D zTE)pfg{S6`H!Ljhad2>KOI{Jx85m+)_0PR`SK>jw&?PP524#=B!C=VfdtWbc$>#OA zRdI39kZ$N|ir_Xbs>_HU?B2EN7XkKhf3v%KaH|DN&L3x|r^WtAS()!%bf1L{3wOBb zA!nk1==RlrbNH5*ZwvI3l1#nW?O^O|_ zS?ufBjdZ?luY7T5SxTSecN`#g1E%Ahn>0V9_aAtAOyRs+>I5(w zOon35Nr0N|VkruM>iN+}X|!&j8V@9?Hu!Zs;&#WD(N=+K-#)~KD;{*z4NvedncW8 znfyqkFlUpJD=eEKbk9hk2``}1s5X+BY%d}#d1aC*V@IdZPMS{hpd|_7VwinU{Vk`o z$VP0S6B$?At==eiT2VXkuE(M`!!Fqvc~2RUxy@0r_)(HAv&%k>%ErPYXVd+}sOZ_O^>EVC2 zM7Pg#Ua{6csF30erzgWQunpBrLWpuJxahm?Bbu_n@lN+%#?_O_#0pU&Vo7X9lfzL*eA`MZ^i$NA;sp>4pbTyz@Dtz;gEuvwRBO*?DN-2=)tuK%7nty zF4Zf;q*U&k>1mt7<5V8suHG?XUF;L^w|Lu)%NF#(9&xDhdrL|cI-|v>AyY%)u}^XESvZ!H_8@%&%Re~2h4eKMx=g|q8%Id&P;k&}b48o@ zo1Zp7>DHyiSTf2Qw#ZA%oB%O_G8&~uq|KIOlhRfrIYPENz5k;?sg4HWdu&r!$k{tr}pMca*OCrhrr@o8+kA4C6~eST4MS$EPLItfe@PmB;BA6XZj!IG>PMMh?UHz3qQd1VYsI(WM0O*0}D>T#TNl?zF| z2on>?O&J4T@dj3ZOnbH^CB-H!3=4>6_z|%gOz|G0Kd!FkH;MTb%Vr(D;_3gs>Lpvb z%9G3+=5bq{0&iA41-f;a-P(YQIwVjUdU|%PWY1%vA%ArF616_{5uwIzoHN2t&mPo2O3YV`T`vB zGRMM=nb>#OA@Yi$en6~lZ)auQHupJ1g~1?A`I+ud)h)V#trqSg1qEi4@z_fyh4ZjA zjmfTP>_(6MG$@DJn?1rAQt5HHH`I+Wu?>YU50+nIJx_6ttwt)arCt@EkrT+;*1S)*yMQc5~BKyA$0 znKssygrUjk&e-UvLAKZG)um_-_`V@u-*sKqz#^Fs`@q6NNm2gSQUx&eH^btW2;u(M zguUMC(bO}lAD5&4RZ{}+v-hb^bQQj33oR~jMJbnv{Ca=+B}eS^Gz6@JRQ1EVq&uh|MY;8D>*PHgmmrStb-@2& zwfd+PQDVo;aF!{JJ|xy^@9L`@u`%_xnOPpr;mVdvaP z-0f)D6QA_$Jj5g?!wo`GtJP9C+;!fl!Lb!WqHc~J&4ScD;bs_O$q+4xI3jKW3+S71 zfpGVrf?xc zReOjaDriZxeusm`TR_cAL4hI zJ-gz{{N~Pd(xopY@aJ|Ep)_Dzcgl)z-)ATiN@(6V_pz2h`f zIX+`a4&E|hd~EF=Y|XwUcUyBVW~W9<3J3F^j;S{*u;4Nh-r~GS-6TgIfVSSbCw%LH zgS_y~55&%zt5w`rJR}1UPK&wF2Q=Kw50bvFq*NtIuOz$Yv^7T>^#gW|V)QeClis^O zSrlJL_1LhE(7T&i?<5=*8?SfiZeKWLc*ZeMy^C*8*F9yec_178PbsX~calTD8;ATF z{vrRuMQAqtt90_O0cLnOG}^|)@zkLP7)9hyN+Y1-h*h5 zPddc)tn!CVpukZZ)95RgD_ds2zIZ|XFyf+U9lh zvB1-T@~qErp?$65d3`KRdAqLta>27D{Vn(^TpxZGPBc%2bwjgf;!3~gcc#Hh=h}BQ zrt%Ugu2+`r_qJ~_ojsUO>$g`4*sbFu^Bi64u3_A<8Hg(Bx5Zu5BmqIV;SNYo-lte$ z!#KmgBLhHVh}T5SUaLs9#OWX0QnM!Rd&ur>-0mTW*&-!>U6_STm(Rt5y=s#HB{`WFAiU{{JcrRs~ylsUP zgqV$cF*=9F(JnE?Tfa-xMO|MOQEWDNK;_SsCJ*KWh&Xdjl z34DG+6}v^mNlQHs1J%d{3~x^s390Mo(%wz_-& zc+n8Q)3IL${mUFjwjzGR+nb%A5a1o2A_A6jKvO_pTM=Ntx~)3#d|yu=TvkYes9T!) zM*xzH8PM~+a^b@-ZlLBe-VAr63!2dVlL3wSo=Ao%oMcq?r%5q9|fzMI~TwbSs{z2GZVw}PIzK()9SLJ z+!?&?ULyRyf#xpFhPNe|KQyP2v9+GZ({mFBxsC1NF?weLQ_X#S>Bmlzd;0Kqz$=-S zRt#176#`e9(U6Vn{Dt~bn}>%P=$zN$v=v~>VE02Rd)5(?ISbmI!-|x@hc%F29IU`V zZ87_$h4nNw-jZNC82IC7h)0aSn8jPfQOG=c$S~iVtXFcm*{5^Fni|&cZEOXg5l$@O zFKD;llw`UelS>~zyDrc6c$?;g-w9vbJn4chSU{ShUkaPyhz9X&Sc_K|URZkuu7|Yb zs;keMawN~B9w!e;DQU-%NBHMLBvRGt7B;bjE7h-R{c$(ZjYJJKFIgFQan?VsD@5kz z=AJLX>m9pS!1#Z3CH3`OkU;Bi$;Hc!`k@F!H-|rP?r~DohMtuu%^Q=PIXgxAlD2~t zCPZS3ehPr$gT1q0*3yRWwKp-W`%aq?#iV5^I&yiXIr|KpyHCL34T-A@?@T8tPPm2n z88u93M@cvC#LC&VFu{@Py)rr&nK`I^=v+P4Q#xrtQMY)?#|)0Xick0OoJhKKrh=F# ziny(MMkX8(Xjr*T!3Vrm>m)-|UDV<; z@D2X4;??@m$Tg}_IoEH_%`{W6YY_htR-=H8*InzOoz*tnmm$@-&aJFpm>@r$y}djvcJWpiDAy0u5aR3Aue?WU(*2xCW*3$Q zb{_^c!CzsDLFeGU>Nt-=U-V;i9P9IiR-K8rB)SRp-9@c|DqVsX`SQJ`j@0( zVPDth46gG}+Hzo#RS=4Esz5xKM#RNl{(kmW&#@&ed5UTD~iF(9}c* zHT>ELWzbW+ISE{YK;b`P)z;2_KzntzX>_KYo(+}37{v}X^uUsqJ11{AgDr~&inI@>!q@@sLT~A^6Ps*c4RN6hRlNSOSgJyY6I(9a-$ZC}@6m|bocco(^CqUjAs~6a* z7?O$cu-5lmwfo)GXsWkxLVH;wl6T~Vy0qC|+DXz~gcI&isl>}e!;0`>*~_lx zKw-Z$%s?TJwR~^uC3=?_jiCq3EP}^|FT$6L(Onb%9uK=j@VjLlE0?D_ z(GMhN+f#lJRYyGZ$=+}}n5(m{h3EA472C1w70YEZINdzfVPErgM3wyL5gHX%-B^>E zfLl5?=DS-$>kj#+Crk45ft5VKab_NaYVMaRpL3%lS^>yBvuuy58|O9P73%<=Ruowz z%{$-++Z5a|uTCi!5q0%;Ivnyfp2aTwPTfc-xqGP_#_mEP&p4M9F5%|M$=3QgAil>k zM-tSS%0CUU>u3p3+cb?RZUmR?^~&DHpY)<=1SN{9hW^>ya8F{5CRaqm58PgUaFt+@tK_z*J|U{$tUdmd5qv@Ftc&ohyM5XL{-cM-_JaA z7Uy+q&^q8gh_j=R?E{S-Chc^udKKT>@e}%?x+qNX4iJ1El zj7a*cAuxZ*r$(nqz2G{ptck`i&W%Ptj%N>jhHo}TSp4!681XsShsF}inCRc7k2YCh z>j_09>gMgOEe-*z)N;2C-UOu`re+@P9^fuvc|Hxq=urw5p~&W$+UE2qQ+sI^Gf9{W39=65>FmMO!6YtSzP7->Z zLwRlms7qL$4>J1YYSMZdf;cfj>C@=!9Ag*0A>u8hOHC5z+r^{WI5anpI?*`X_EZ7; z<1=fGzAKix!&xN>L7!h5{otU=>a$po}0mtdR^%87t7oCLpD%T)5;NV@7bkRMD7}qT6hxNNT6c*Wg=16Jd}JcFjB;Osc2Ye!&ARFwiGLjt z4?iL&0tIal4Kdso*ccq}np5tDe86#t+b-Pgn#Hr#DqCCRK;Uw>`r`HJp52qgfaS&< zcOc41wpD^_%lgT=fq(&){g6qmJiJ4&<4rN7%UIp-B=-Pz^pmmSvb!_jCG^W>O7xS+ zIohq-K~QSzxPy*x+hP6JFo}!0wx)ujnU8?v8WxN+dL$iH&rK0w!0UZm)p=W0czm?& zkX!NnUbSoKIbQa4x#e38%X2y${1(5Tkhc*nG$(UCJ$vLsMUT+7c9%)$HIAoWeN#LN zlM50Q=Pmi<&FKzPM?r}v((XE-61wmyOVjcSt31+blH^PEcsldrw)U}zW$VyCC+a7k zUT1Z@wQoDl$Sb~t!QXD@fxI24%|R04wmdvX%Q@McbhoD#TKP}ast<3m-mohRMC-E) z#Ml4@jBNrbNlO8whtH53p!n_6hdtYY+0vz>owG8NAHdMR-Kl9;%hh9{qou{o_B9c&J}#}Z zCo?h%D${QhU&m;-%Vr-azsf1tzUH-;xfEucRGTYtM{@e|$4oS;jCpBTQ_&J1hWQKf zeOrikjVSleS!iwh&D@lhnGNTWIDRoQWD7l^XUfg2^5=57DFn#&J1mU(w{oI3ZQHhO+qP}vpFMk?U@z(k>L!&`zV!S$(6g)5iMEC9{Yc_YJ_ zs%?(s(Ri7c8eHwV==Px{61im<~BecA8c#&)5DxMv?R@OZLqyIGl;l1J;gFK>e6DBe517pP7z zul^aCJqQl;JiUZm0HO`flgl-M}{%qqjJDQ`3cY3jmGH-3jAb$UOD<_hB zuh#xhaKuJSBt2QAobJ=!ecK^!{yad&mRhadw(6O}pnUd`8FJAkt&4}{QoXZV(sjmS zR}@O$HBVK3_AE0!8yvI{`6`=h?!4vg5~k?phDZNPn4VHOW$gNVvC?1gThl_C2c=+s5oNR;nZHd4p=M9Bvp6Yo{*2;mZQTi${1bwA_Caza=+fW8~22 z7XlD|};l|-pW35xMle2H6=m-g8NLnX%woW(T8 zX{X!8?fE`Oi$7Z?-xcgnipSdAwHI2XmFFqvuG$mZ>GZ1f<(Lnexc|tm;7`| z?|i1E)xHR{RQ`WIz@XSmncvWN6(Ms0J>jvfw-57J@Q6^9B+ui(x(YBhF)u&E^4G#5 zR*aA?;4e|AY1cbnFt45EPF2wZ-&b*c^0f2JHo4}Rvsjb+r#P+d@;0Mrenb~u2_Bu0 zt*?Jnk9m_C^)pkHq?Cr0ReK$`4Q`cQ{QfkZ{AMpGA2y($Z`t&^Ps zLwP?|Gh&v-pLbcxupELJsD6j+l$f+sT0jBE$k~1y!>*9$di0gl0+QxENsR{ItTaO? zAKCVmr;cfeqRe?tdR=xfZe=*$71Sbv8Yh$C5Y9LlH+4LPm6Mq|NCQ^@LH1<}*@eS@ zHC8J}GnPnU>Lk>Y85fl6#&{ZMl=tEL)vA*0W=sdj3=NinV*>HSnIo=%tUu?Kg*r|w zFZ__@HOOk3AJL2Bw)G1*hYUvo0iRD;iS(M3igbp8((8J)(W(+!cSNnvPb>=2uil;H zAocRnCpe!U0V|ap*kz(RipSKzrr_9y|FlP&?8h->KtDm(4HpJcL<(+L%(KA6`LW4( zmck4W0}s>BT>)tu^gTlLtuQMKSQ~(e&8;|bMy=nOWnp6F<^7>$PN6n>^1TA@aT^U= z-4VtNaob-QNxPc5udVh!Hl9=f`Ccptxx-7N2W^{k_)ul~0dEU466k0@uwCNAU7ZrSmG*E$20?GS)J4Jnf;voo4^@^m+C39N?El7h2Q7 zE<3eu3?rlfW;1EvcAH02tRy2HHRBb;?*la9a@>jEVZ9xt7e2j{_S1;6oerj^rlh#u z2e8>GvN8(|miDMMgaa7j91!A153NL^Um1asOFTm6mX6gn1(>?i12}HFaF`=L%K4(! zxL8aiT?L$oP$RBLGt`vKEPP|Ugt1q95H*L@J&78<()Lnt(iBBYk;}H&qCa;=7=R9R zm0$r}Bg|p_s`W+Wb{C_6X>Cko33M+Nd%{;K2BsU?22{-C6he+{-R#7ZrI?jgKdE$i zIHHLY?$^`o2bf1feTMY~U}sI$(%gsb7c*vT@rtnb(8}nD2ZdbqZY`<#t+X^c8Y+`l z2Gt&hnBlQ7ZJ`O+i{z;#+&---2qTj%04eGd21c>j-ZN18$&M7g8VCa7GsPKzL~R&w zupn2{fkeNGf&vBL&ySm;SK>LUJ>;}9UDlBMjMfaH8b@MIdVH2yZ7<}Y1oaVs{Bdz0 zd`N_>s;(-pgd&`M?nVU~ZINgU-KMJE2G!F`>V}9V7=tDQefifGiU$T!M9b079mpJ( zm95hlKZy3Kuz4EI2rn_dChS0x-9)HL=CoF5q_nIn>&f&@5V-iL@ylL52c@totMcsCptzi$h`J!2idU|i^uB_jXW<2B@^I@@r<{&%Ladv~4C(E*Bc^B2X*W6&XlqQX;Iajnj z>{8UuXw{n4UOj_@C$7HF{We6orRdGF+j2ICD6Q3+LY8nVJ=h1}2&Ucp=>Z~lTwS;D zJ8wPR3k7`jJc#wQmDLZQGzaiZWQV# z?vl5=z8VbsQ45sY5959LqtN<_=_6Y=oSsaxFO(_34N2A0>qZ%CseMiV(SZ9M#w(5y z`h7{t01N4*!OWh~k^b!ALG#5Z(+=3NFmR%@$-lKr)s?D>o9T4HPXD`k7A>fxR&W*4 zeB1Bcbf)u+hYTQ7};+)PR)6<>923QD#6Txgxxz|75Xl6E_fw;e^>IVp1AFjTk8d#k|lBeR`COl`Pv9DdYfM}_bb=+M`_@0Uj`&>gXWg$! z?Q+zmtNC-aW)4Te7Rb>3E3#^|@u|#{h50%MaV9GLIF0yYexGbnZIljgo2@%l#vkB3l{mxMSP1%+}pU@ z#Ww?#36_UKw-r+!n}CM*<0p516OBob9MtT0yLcv)um9oMMIi;IjTT*1jsq+pqswa9 zsJW5Vu(*+YT>p+E%gof(N^srq3|zO=1;l&!i+WVf~rq{dE)+B8K`n-Q0&Tpl>g@ z5f+?7k!#tc6633W%^MqCJ;%*F>n!b`M$DB# zbmYknOuPF#9i;fg*PM$2B~I1EbZ98KY`$x4{UVl_m>4La#HEWb&9ty6Z+uMcLo75- z{?xIG2ZIe>ipIir--t3Nqb2@wMhC({ZyvQ z%>&xK-hFF2F`qcbKtIjp^<@N(hRl&{OQP?rjRHT=GvJNsLRp_7l^hS)7|Z{Hb^1%x z-GV80AIKw+R=1YUM57>AHrnmY!_8QSWhO^Jx>;bJoClWr!m2%&s=hC*wLTP&Vn&cv z^<^X|?~3ebrJI6;T2ZZfm5s3dbo7LQx*BV-W@UM^P2Sm;ir z%PBbJktPK6^Gt3qM>u}-FuTq8XHPav>X)a7hR5G`GEw`4f5~kYLsm1Z`+J>V0UzcF zjZkN5=1apQ=Z(q(AS!13#D=M3oJQN)I|B@kR#a?`nBxkkuqpNve6~kz;RWg6Ky7UP zgOXROD~hxg8!}8JRCl^?tlH;SJqOZ1);WpzrknT6#S%swZQ3MKMN28j_!YmM%*s5} z$XGW>AfLnP(vteHQqIG%ex?laM~frghM9a|VPJsrrpSS!sOHk1NEUZ%yX-8&_GGfP z@gf3RO|u1krR@;9xTNo6hf^Y(S^^Cll^j$zQd^u&JE7o=m$(# zV(G4!soJLHtu{Pf3zLq42pm3zN$H8xuq1bkAS^%-o*>}oRV?>p;{u1F{AMCT~ZQP764H%jLF?ywM zw}^3Q(bF;}9z+#hE?{aeh2~+ZoQjbO6QquI^XA)<#vrtx7!&ukpot%AiwT_&t?b@W z&ERWL#Al4t%bKr814K?ThnBJ3!j=C9a76vOi& zKLhS@dhR@dSVKH!t{!rw@3b-@R~7ENZ7?YS{DHWh5O{_#G#G2+U2SbNYR zqD}@FJGWJFmuNYwWl`7Gg%jL)4?V9CK205HgF8OFc9&ISr z0Qb}TymExW&fJ}A5%a&{d|hE*)5XYQQl`Kx0M*uW7Kb=rl>J2|FBWRhRq4qevyP>~ zaQPjV|57#DZL-vjol+;$@!O3N?d16KJz2*o>Aa+4byo$4nnR)6g=9m<#X4rUaZJC& zMZk4%;lF`-NXLddI9iW=-I+{j_Q$pUuMu*k5&Q|v|5W#zq3#jvPi0hK(v!vgW2+tJ z%+@jX(Oj`Sh!91iHuWY!l5o!;G4DMb4a|LS6;wi(-X1v5^5f6S6JnS?8-~%30iJ#Bs~h)0(t5RYDPfj#Xu{hQ-gOlvx23B zrQ`+rx1e;&V^Ooh?{5Wm6YXC<85m9}GrP@VG;~S|3KV)E=`Y*X*c8m&3x((?$C}ok z@6*EVP*w?C-cX5BMTL%<;^N|J8TokSC=Vl}K+>6r!nzU}1c86kkw~?lH|+0UTW%?S z&Q5{X0dI?@0fC+6uguzyqQW4SddW7husGYJqn%Rg;!U?@F{jLJgr++|;NWCrloJy$ zw@bP-MsxQc+6>)kQ=U+4_Y8@0ZhD@n4VWt5^`keoA`Y;IlXhgJ7qkrlDGr`NWI65bS%c^ZL40Sx=>h$X*gx0~xNkv(QmZDQ3c|s;QvPao2 z_PqRFe9aK%O87CtpWXxf#Q6B_T34buNOs%&l)be4kj7q*%7pIZDA4>6-&DxBB{{ix zmA%E4r6g%rb$hrkFL!#PcLI2U12>z0z3vo3Q$b+K8yurGpXW!s!Tf@npcfXroi# zXmec;$+zt>eVz?4p=8n|n;aW#e@p#L^*9Aabmh_U&mK5BVG*ySpu@{ifl3>FVOQzt zJRm(ctz0x~m-Q1u-P$Fmh zURSJ;KZEQfSZ;uN4T9Z{yaWxMN_>-zbdoX))aNv25dHfj-gr@4W~O(CM3~dH@n5Ad zu>9ANZVNl!QMJqEMq4R+{yblcxxUGB20hp5f^B6hL>_dq6YrX}<6}xVEDUwbt0()} z=vm^%XAdge_qy^0Ls8%033}9UeZW#^yi#N(P{0n9*Evt$LW-lxb1A^|IQ}hUzp%)K zfPjKB^Zq)IlxgcM*$M*@w4h6;Z!Ell$DyxT#Nej;JV9;_~Wj(u3otW5T{@ z2Ha=MHZDb;3J2A5Kv)%KoL$ad^J{Iz|IYm`^_MAH2)~R2>CXH90q~V``8GANA~Idm z)7F-T_6-ss;*1=a?)tfBa@XDk$ppb}N_g9*+o;WbnG{LSli$o4yDbT^U3?D1^Im{dRvT zP>V^%)jvkGs+UVNlE*ZmKF~cuQ1>$UKs_7jED#xf8t#A=y?_8yfDblzw*To~@x=#b zJsnpp;OpLd)q5aUhol?ye3l2kW+QpS0_YJoI2Nc3Ivro=SebPspi@RH_h~c*HPkC1 z?%;1pT++6Q$9_#s_rZVm!v0w^w(pyS4MOF}n6q%~_M_QS*8k^HNl@p~Rt)s<5jBLy z=kx?@KsX+sJbHFs2KCUdW%h5{{!oLUo8mfrQ#TGrLKS(oZ&X9^R#DXH-CzwQGNKld zPpXQmku`C0K$3*>Dv2@FPm3=rKdQ_jMjQ44-4^*hA1o+_Q&|2@@9>Vki@Gl&SN$%S zFOXuwZvp)NSOtgd|5L5l5K%+cTMdjBLu>}_gU&$46(0PByE0)Uawh%U9F$08_?2^l0;bz*9i11@@A_IC^@$wZj^yrxx2wvwVw;{EGpX{V_e?W8PUs79Im$g^+k{grVF6?SG zOM$L?6JQ!rH}7Gt_-_`jkoA`5i+7M(w(>@ma>3n0PRl(lZDft;y?t}@OK~oMr^dU? z>svFbDvzNB_A_>SD*SnIy9c9)!o>6w~R&50c8<&AD7>sR;c;TyqVQg4>W25gAXYg!l|dQzIZxD@ydLCGl7e^03%z zdJbSKH7ULkh=MyT#Fj+x^r-G&_+BpB1vbMzT0xP7O3~UVstk)$#do7i!SX#FtsjV{ z_v7`TozRsg#_dz}znB`^`{%KgsLUw_aK*-k*ka?i@^eh{Op;djA>eh!lmz)0f>|Ev zHh3G_Os>4LMSAyeD@&E*=XeNM^pB)Sryvx}B!@)JQ@3ZDm!JyksFJ-x=EJLE8!N%+ zrjI?*;!{Q0iQn)SIpsc9f`d@j9|S3Phoe*+?lYpYq5_{p-ky`DC`&x3p@v$FA z8XpCNoT|=GUTp!L!3x+rn9h;0jR4^d6gRrh!bO`{-0ZZK){32Xxjht2sP~>)g#^$T zXK$*UPVw!4uQ3!3uAqf*i=LWpGw4S3os0+XA+gGU`=!QOASn%JXSATiW=_Z9oon#j z$LoDEhMta(d@w7(8&OLm;Ty|7CI+pSFI)gV5>sWfpp5|P=MhN6SL)Uma2uvOA1`Cr(fb;)6+x4y6mwg2CR|bz@2O0gg`$3J_!}53>tJlb zWeGk|=JfL(DmE7%hmcAG7Em)x-N;nRg8PtIT>8xDOF`xkj(bm@NEn~@lErj1XgqIY z2-53dqr;fQD4E!sk;v9thLX_&YiUW?Kdkt;`tmZv=}VArz`TC5F-wWfwda#j*v${h z-{X3@VkX;>QGe_+1cHYMekK~X7ilZ2z_YD}6NQpatV1A|?;B_Rhh@=3D&q8v89g;T ziZ>`y;+9v`*v>DJd%O;)-)h4UDbg`R{D|RLmL;BAEu1a4$Y2!O=A0fZH4G;FvLSvU zZm;pF(btF0*Bn6&hN$9chg9`Se&^oa{6FJDt~{?ote8J zaE@!!up+T@b$mtH?W?&;IItY#RK)0~b#N`C6UVm()FIW$c%=?O^b$H1>T4F+d;zIR zo4#a^?;l>?Tj9jClRAVo1!7%=(l86u>R zXT$9;?Mh0n8*Y-%5GDNO@D0CwirN*k+46sJdVntw3AijyiIH8rsj(pj3fAZnCF+8F zV(3mXgaEYVYA$+A`;j>(aBZC@pXmat|gQ6~j!VaN8j3{B84& zQU14_sJCX@RJeQgDwt=1S_!3_L^nJMk3v+lFgN#lXYn-?RWJcEjlg84GH$Pl7RXYr zL@98HZH|Q$iR9Oh)r&KaoM&=vks_NY4T(B_T4R}?t6e1RHv0UGpRr?=C_A;=d-mEY z9N1RRZjs(eoB)d4Xqvi*qeJMw+^1QN$!jRtwd%=Mu6R0anodL zFPkrO-vGt>X?Mi^6WS>D^gP(WMjI&o78Bd&RM)z!5^@Z6DL@?~6><@3GL*MluZZ$p zrf+P-^N!WeBdji{TxVMBD153=Ko4C5ReR@`Fp+xyFq>Xd`MoJ9qJ}L@f+`@RcA+F8 z_$JYD{)26V`=^pFOQRaAbMTS+_VL9`b`C2d-yYR9rqE+VqbAq^t@f5_v`u}pgL{%) zQ^rKpd1>-NXuP&GN3kEIE7dM0)yv{xnwx5$u+g!FHA|g#8mmQrW-`l=MpjmK2jdX( z0}$4B4dBGn&_?yI=ckn(+rST(30^xz|9N1(P^X*6ENWrN8U>VNrET?b2~V{U(=d_5 z$7GE$0HjP=??_>X=d0gufSxdtDYGe{1mu6jO1MpaeKKgNi*WK2G}rp?@H+s z008%Kgt^wk z{W;NdrncmDTvZ)XZHT6k!AQn+Mjzg5vNIi2;ly3-^Pv@vaX(Af*K)FVp(svtnB^y> z5FKQ!BB#8;wOhXl?ng&!eddWdWj#(|o@P4No;9JB2Ip#-wUDQSbQ)7?$4$zdW9ujr zSbVCowv?0qqe3EnoY2ycI_#z#@)bW){lm>#iW66xXkYF{i9(qpvId<^W$2b(am;AW z)Lsnhx=W|**>}acv?#3mW9j=B|KspT5RDWZ-;o^9=$ zp(K-_5`XD(7q{!h#N2eh1ja_>DXc{C_;eWa-V=bzTkV8@^}Y0$ z)>ajOzfY^Yp2id5mwVy0I!c(P19Hgt9O+uNd2&4*sSZESAH<-l8)=Ca9z{=X9H+Ql zrMV0eO*RfEmQSggQYHrpd4m^oV9_8h$aQhAVjrMcY74JMmmNC;3tixFPJ z>tHe=qQ}g`#xs^e5N0}GQk3M|#3C2d77VkA<2yC!D(%`rh(wh}SR&D$Y`)YtL&7!} zG-$M%=loVXmTHHjHdMxMJ7Y9;0WxhQB1ooseinbr{5LNefB}8)Fq~WpdC9z+^@jr_ zFYOt7loXlh3_^*-hFTS5n6O% zdG3X(*k(pKNP_hz3<74 zDHYg!l{~*1(csf)BcYb#cyV8}=uL38v^Io8Mlw@3{lk?w)L8zIWq8D^ot~ky+I~wI z&muuE(Lhbb4lbo(v?anF`~36;S=qwx7PJ(43Ok&rupg1=ZrVt$^LoXht-x^xF;q51y6 z`0>GfZvjS0p{*dG@N%c48=k9*t+r_5{Jh85C7PlZ?0D2~a#s*y-V>g@!;Gawr`ti3 zL*ku1+@vknWFGt}iLz8(%89&e%C0LnYCc*2ISaH=#9TZiYu7;l({=)~he@&r|z! zGQMpc`G+cG%&2-XeUX9Q!WxUR!_(xbDTZ7_sfk4=sCT3l>$>sI$OShXawSF`)W#_; z-FZ17p-Q879*u%<_K&0~b<`fO=Ccjh`gL)fo57C@%`Edtg{Si4NC;g}{-T?avK0hv z*?!yI^)S;utqQS?TBuNI{iVLYdzL)kuIj~+Oi9HMSk2d1ln~n`r zWN*DO3$~(QB6y^$>Ym@!?Fl7R9l#biTIK+A%^`lQ5R zN)g<~Lm2B8BL$LEdH_zeE-la6QsOq{(f@8cS|XI_9%RF%i@5|~6|H&~h?TX*4ZpXv6M zezE&rIk`6b8j8u#{{Iq11#8=^biPU+Pt0)(fHS`+JU+bF2M+MlCPVE) z2yUK&JM~2WMN02BPziAF*6NPyTB}lianEPp6kp?hc~l?h|&^ zh3ExLY^gGic3-o7H5&R&epdlzBuW=84=lPIUGY z(kxweUIKGlp3>MV#qWkK?5*fG#6Qfx>pzxgI5ErofuGt<;+h~!0N*E3u@Qp3dcvO2 zbvf?!h(Qe3v@+64_ULU~b$ddhoie7oxIkb6{Y{P{ciM z1ljTchAMy^h##>U6*tJ-v}H4J|M6aWDJ zU3KI)TcB?`tQ>FvZX|%Zc`^1C;w^EFd4j@ux1LI{@ePTQ zD0&o*2Gs`jj_`1asZ*KMmd>NX?d6-r;`r12N;`R6e^Qb2*Xn+nN#=r%gzX;#rMJnwl9F0*2M{wX9i$Y`^uE?2TTjpTs%cfC+g30dm6X)X+8E78CII2bqU}Lz zIqmcreJE(O3MN4XUEQ5O3V>VE+^=_`%PzMF{)F6QN6qjpYLaqtbernKS~<11)`8a9 z#jn?!7>2a$xWTycKbQ4TmenE};^JZI2!WVM7xUmyDmnv zG!5AXKw=>7hprKa%li!v`*9t%&}m1Qv@@pS?#Pk9^ zNr0MZf^I}p9~F*c93&|LLtuNxwq@rC$HuzEYEjZy?>Ur){w?+p`(D2b$u*}5p02`eS(}k84~nyqx)M{czhDJ$exHcq(-iXED=VXSR8qA%Nz{ zdYa==6Qkx7QZ2`0Z_`=kYHORgb-sa9ySbPpM$L5&L>xK8eds#tz(p*_2vQgB`kTB z-4cl~l1+8cmoyc_SUEEhd}0>YmnJaF<_zI6*V?X}p*t>A$)(%ejXh#DdZ*klnRRe= z*Xu%{m3v3a_5p(`+0|S>3h*@_8&iRnuAs$YFjzclY%?^3gKyW3`!P}Gc^Ua62k;xN zkc0x?U!LUniEoeVj;*9v{_l@z{E4U}jp;boUm+xqaed zKQla0fkeX-;x%Oegsg^+3RE|fIih>q+HK|_wd!M9Y|`sCq$6hWJmB^Ijj#tT${Zg| zQOH9VDoz0KybUd188s;gtB&Ne9b`!-wP=oWwQWpzS)z0EU7c?1QKub6dc$#r9((x|d~MB05qRi$xglSpn1km2I% zshH%l$R?UUWIq|(Tn=AW#1Tag&c4QnSNP`_cF?Uvd&2)(d%oQQrOM2C!&=q3Gy;_L z_fe$cQ*Oi@u`{@OiOEMHcixb)Rm&1?@Yy@~>MrMwa}tFQNh)LnrpRL*peo|`zMnjo zV>bHl_UM8@cAm13L7tE%>Dimb^16In57QcrlZeR+K<|aNJNx{L=)cVj7Ny~Rv3JT5;hJEcg zI6&=XWfww&wh7E*)6@gmI2N6RNZoRCG_brjCqfa@=uAO08X1AL`f2Bp*P{I3Fy-{d zF?<g5K%Eqvr0F7bzJXH_=V@NW&6V(WkU1C@+qdLJEEb z@oih@!yDu;>Xpswkft}KD#&>$k1hE+&c@(ig5}_84bD$yh8W)^Af)O1N79eId1){j zEyJczfB9`R3pGyslLftC{`YS_Q@3X z#w#(jJs>tn6mQeC{o&^Tk&xKib!_O$#dto_ADdJJu_m}$7&t#lbD!wwD8q#QMJ~>7 z>x;0orCuRj^s*Cm4R|%wI9#o_h99DWraK>i+;<3k^pPd~6Ayo@-@|G;5#prf!VGh( z$uuS^d5wa}{Lss017GGY()tv%9?WGCDS?oYLq#JyXyDd9Ad>T22w=E9!-+wJ;na5C1&j-oR}HlF5Tmi z+oiNyr*$NJF+a7KYKUpNbv`shN10W#Y4u8;K%Nf$eVXo$+Oa~*uyI@#*7(4ms|aR9 z?JmjnIfJ8>bkceZU1&Ucx+j2p(YZHt9UyT}7ltCr>`1bup6?IrP|!0|Fjd~w^BE<# zQsX%SF)|`dR7Hjw>zG*=ESW6CqyWEQ6c*jB;REEb0btJGAi;7~}Yj)bi*uqNA&wzQ`2MH&n zcKi}v1Gb6CBVc*QL)`Keo*P)cdkL00Q^DlRfglf}7u!ipP;@^0#l?tG4f81Li5YxJS2K z;`@O#T0xR10sG*$`i&Lw4f!p4Hh0VCcXL~J3-=#|**_6D4E`T=`M)VlCU*M&r!W~s zg&3GQ*w`7_*hT)MFt56tm6LRq*rdbADPR*8Sc;q?fGD^3;)Eb!qMamNT`QbIVYauS zpkTJcn1x{9VMn}ocN=$ndwzSKYeJh%85|9By(LZ3 zfB_DkUN}DsjmWwcfL}UBy2=5$XEnC?OeIqu$(0}1T$QJE*~{HVbGqf_udbZA938H& zitW=Cl%0;4*MDjBVm1QDqP+X;KNEv3gyTa3`>NTRenGo`4Idve3hQF*Cm z%7EhovI^bzF`tk=kp#d|xQvw;x+t3$>)8byP6KaF^>~}Iu6skk3+z6r+K(kekO<8E zZVST<@~!x*I8rt*`d;HZm7DNSLEcCTK2zhRGce^*arsqblm;)^SnmI*j$i?7WsAlR zcT44+ZO(WVPNK%|xbX(!bMW={+(glWk0LAV>G$~MW@4kxEsjt;rpw}cN%=Dnq|axd zV!HbH!4268F}5>g0qGu>g)`aAIUi`|q)|JePREK#F4YT1g#g9%8vxj3p6U`f5LHjB5Bp;(PU_fl}3l1)-}&aa~3jH(7v zE*ljY62){zZsiiP>=!4U&?~Nlf5oD)xbKnuFIrP_?rNK_ z7f8f(4VzQytysMp>ra<`N;eFTBM2!2c<~?v95$0c)wzbRITr2L0S0&)5@r*W+21c8 z?TH4+MT)a)C#iKo=9TLnD zH}R+34(PO!)ex%@pPp>eozua+k~*i)IVUt6YPNa2eM3n4Lzl`{pnDgvI ziKOy^eG~w73-^z!j~ILvH2igjmyauCT4ey9Pdrm-+k=JB`mCzc6ecn_@Wg3pBxM#w z2ItVSK6JE+6alK+GWze8Ue+Oc<9J{)L$h7ny3If$mA)uK7{YwNN3p_^#ZK*u5i2kw zRX8Dv#4x5GHSpRcKeYD6#u>=PqlwYUa*s9#mI_k6;SIl6fJoR?r>PuF*CfD!RuCv4h1$9!l)`v7${U~d564{!15*;w-B zn$H+vdMC46g|EnXy)nRuOp$k4Q-1wTExqS4ogayngw$^Hugf!VS+{24c=+pHQ(ZD@T?c5u&(82SUtsYM0pf`j*4wb01A z?Kz^uLQx>jT77SpWO&C2l@hcd+5S-QTvZ_9M(9pJtD}qmDw0r&23f8bW7GlP|-A zUP*E`{v|LloRty*k*ZFJmp8!o6x0F^w@e%d?hJweR13o95QhZ$!A@u=5jU1UHpQTS zc!a^nMY?da>fVV&hv>q^_~SY(Q<$(|g}>{Z;$RoNV>E~H2kUGUUPG%>1|dct!`(5L@{BfBiqhCqKaUf+j}JsK_&?YB{U2#ew~Pe=ORxtnh;0w=zmFe zY`+oHkLSsDEi}EIQ6%ih(?{@eG;5A%p1S=ku_G#oN2GeS2k;R44mb!~z9n0*Tkm+* zx%CF%g|!&XwCuNafbhjh?;!+&zygxHF|4#10Y&}~O+d20HOCa=I2&LbA5Z6)92pUT0R11L zn{%ed6gmxd-BA(jx&zs{4JPD3GxX$01x0F79ex*+b$U1n$J)d|VmUtBI_m&M9R`bt z&?^Gro+Cc2CMN3E)9;2uA8a0;e+H`$P#^}r7$d&=6l(&8&P7}X^GAsWp~RtvpyC|& z$9Kf`^~FZBXnk0g25&tq{8_a=3A9~zF!lCtX(6l}Yb80SJ*fYE@d@&-##A7mfF20E3i;r>F)QqTCQHLxd1^MZ(s z0quSdakyrc1IUq-JzAmsbD3!p zj}=^8elDT+L+>t>a|(Y!t?Q|7}GZEx}D<|FxoDP5xs=zvxg^NsB*6SUBmOS)HzTO$t{rn5nZw zBRYYGD&6*%ZK9`Xv!5XFAOcZfcX?!Fl{t;iTbv+^=yX$qW}BN3g;M9bWyXM@sj884 z3nqhz*wz+=qAa@&DS02oQ{SHV-STC6AHTi$5Qm_;g+Pg?ho83+u`7GpQB+8!WuqwE z&X4WiSt=teN>Nw4+nejl1O$M*yaV*m0)+~&FQB_4 zr3xuY<27Qw^cB9-aa7c4+7xD(AGplev5NQSZ^T;eI_Uh{q4aZQuM{&DWX`$I+8q%| z-l4plyXRYwJsA*8l#1 zrCLXTd%8Xa`iS9kOMR!uyC?Fs_~QWE0;N-O2;n3UJpzueJ|_q_hF05OyZ_=v`!6r_ zKz{H{PBLP?ENp+~D_d>4sz-i;KwKJA#9}aJ@wZgRf}x+?CXn=HPr;k%!?^Ma)-zYv z{S%b+E(Fq$eIfi*11N%QVZq;zumh&%cWhX@YR*>Bjo#-jxl!hk|w{mSI!hM#W@Hzhz}o>{Beajfk90chGq_ z&#(ugTs653wNU8Rn!>K&1!Y3UHyZ#E<5AZcfqseGa!jS+4DS5WJ2&vC;$MCMt3Z%` zftN96mN%4)X(YQXML>i@$YQ8FON;=>0X^xzf>UJptX#pPcN)8KvYZBRqB7=Ei!z*N zuHeAlwhorb8{fyH&F8srAS3@babx*s>#+#5k3%dRfl|6Y^d%(1mNMEc)A_q#;dv+e zX0&a~vcEwya+*B2{(J?Sz;}H-+TKpo@gRuP`(V6`P>2lC;rc$=Xnoo+C6-F%DVZ?_ z>z%eI68>2(I%xH~*~yeC3oYwFti_x0hbA}Uk%pKNR%b5V8##5?;Gzk6EKq$uX z`Iqh$?@H6I9wzJA*6o$ZrUy3ju6qxu1-E5Dx@VCFowc6FOG4CFOG26cP5kKDG zvF6cfP_|7I!aHp)^xITfpBYS@90@>7MyG2Nco1u*tnsgELiVSrV8UJ}&Z5`SOvBk} zGxp;QzMz}aA#n#N4vzO)KCh7AyA_5e?X^Yk2_5tK?v7O#J%{mkYHA3sae#Z!s*Buk zfvmv-k#b#koq{Zna`8{wuQ12{GZcfE_|q!EIDm-rUWi*}Yh%sHwsFBt;4VSa)=rP+ z&z*g{X2*bAXU|QrNd5Uvy5JGsjmS0Ow8O;ccNj^w*Xase#CgF9s(9qnO@y2A*x?;3 zoSBH)u{UM%m+%k&wcTn*kooZT@pqBK*aRhYnB=WaesA5u*HhS1RFWR++60% z{-+fu-@%*(+rJhjc85^8W&aw*KHDAmK>pR?xe|KB>dyQ{mnty4qvh=99pZHUJCh^- zOYi>)8SCPAxI3=-FGrV&cR&ODSHzwpxp99w{bi{3e=?L{J7v=JJ0|?qh6uREpZhz+ zdlikVz)t*cg!i|e_kZjExBh?Y|F{1CQ+*6Ru$PfZc7p>b$ipMlP#x-{&`|nsfGIba zTWHhtH@-x8q((%2z(4h ztphlfZ9S}hmH6bS23iEb*#LnswW!3jmO};W9UO)et0zYEdSgFXfT6k~DG#fm4W){= z&DNmUf5O^SW6Y=-Aq#5ujrNh}mxfiV;tZbZ@V+ka0L|!fPp#3q)btT)EY0&)w>3QA z)mPXmBE}7txLSUWEB4uTu~nl))57o$;Oh}le0W<(s~yAWB{MS?%?;tl9hpT>Q35Kq z71qzM&~n34>jd)~pa~;6y6eqnP|&7Bb9MC2SbKAxf+Nu)@dyy#g_Oqt;{_|%bMT>8 zgFRz>2IrW(-cCJH)qsCCXnKWi^chQg(p5t#;R}4=oJPKz+?uZ%KTAvq3U43r<_A>p z0Q)yVc5OToRY%uUJcvpDQ*MGvs7T4zW(K@I8s0p~=V(E`fYg)}2{LBPWK$4`Bg546 znnl4I(6-6Vt@Qy<3H;SvuIpLRifRrT#xMo&>Ll_C)G+euh%WI^PnK+V{7)Uh(mk(t2X5TM+tgS5J1Jeb zs~R$``!dCb*!p~Bwy4&mXxE|R?{KSUzwNxCg?wwJ*HA{R1~D_2BxH?b2ZqVWTmNWz z?2}m~*>i8pvbxWPUxx0na3P_YMFCRHnJ(AV*hZ+^!)uFGi^OX^1xtv4_qmwgVX%Bb zL1eW_%TDo@8rX>Vi5Sa0l?Ls8j_Nn34$(~Ica^XS7v`*N$i4mRJT9|qHW6cXzRYB?QH^X!p( z8;du)iwA55nTp9WOhZb~!qgsWs66?OvoQWd!dOQZ%iAe{GnDbU#y>)f+@4BqP6@p= z6vl@C;Izu(^X7*vrnQ{T)CTH3Z}YrDfa%<(cpaz*BVWMaa%PI7?dpiFqWOrNh(Mb8 zr9JBhR@U4ZotY^wOXnQA`=Y{)`uGYQ?|v_4ix9B>Q;V&z5R+K=!k3-zC0Y^(NVAXj zvfnYL?EEn3CyvT?+ejUL%F+0Pc7sJr*B&jYT&HFuEi9ClFjp{9nTSYrm;L7o@>9Mq zc&JpAdjI8oAPGC2KcR(GOwbHAQp53e$JQH`-sH0Heb9k!p81ebDSGnk%+)<t}}JXv6tRIA_yNbxC<+*h5TZojRNOlPQDSY`oA6`Y`2~6?G{M^_R7N#A$+h zYRxlyx@NXhghl#{z$wci4u_u)o$j@$X&&%q!-oqbt}Q?j-092x#Ku}vaCdh}* z`*OGLIenBehWToNJER^`WjXqZdA81WZ0;I;X3Tlk;D#8{Di@qfg8(oI>ER zO*)V7ikrJu7c%K2^+h%K9`Q!m%5@1N&&H{vxl=bP1sB4p?IR)+$x$x z1-w1>sI+AcNl|+5_-D9ErFy{yjh14+1JqQ>p+9^z}rvshhLR$ zkCkA|n5ot+Js^-xOWv@|+*-K)@yA>K%$th1;{YbnWi9V@t;)~E%036^J_n8xXO3;> z;ce$~(xI!9;Kw?(W=Cr9v8&-RWgi`>s_cuRY}S(IQaY4RU5{TC@KVzq_VT6A)U%Q@ z%8%FE(!L?GRXL9<6qwxE`2&sYKz`d9b%YkB7>^cAwVu|x;(0!dcNaJPgvWfoZcK1h zMHF4UrMK@+Vw#Oun`I(Ju@m($$M_Ml+s&%2?-kyBF1x0Q6AqqCT{Fvh?3)cgL(#4l3)L4|9|8t2Ulr|a0f#AL&BL)r?PHfYM3vOiq?!8-Y@&bXR2K9kQiZN)gOMEEjdRUcXiAkP2>G`wJ+&` zdo!L|2#he+0*R;c_R4WPfi(hDI@vpwD5_W#z8@F(ToiD6BGB^SJ;?!Q>tN9P`CWJ@ zT|`9nAWP@8>FcFlH6z7v_lD@n3WMm&K4d}2L6AgAnjt(jkLJM+?XqDGMg(o8vBaoi zLPP_#ccwHIh5QELXN+sirl8gS_lvYN0~0LjXkCZe(?jvBxx>#Bt_F193#P2whf1*g zb|p`1Q9}#1jPPRMamnZLu8*6M+fD);^1urziwC`UX|G>Y$y`g~8rW=;2W}ltDD_Pc z^sqKbVTjOj371lBwCsDIHTj&m_$0qwNCE)sbzfmo+^mhhzoh4QxCdGRU>M*BKL1X- z5>2@PG=yR^M1=qjTXHhuhbcVk(SL=LyfF|_vm+vCye?$#8 z_c=BHHe#7BcLgVJJ0zC}aTgSer(XHop84E%Gl?J8d2iR<^i_pAirpMWqxbOr%oebv zGR;2DWqKlIv=R~RF}K=ooA*n@f?Y}2q&a=yLn>HTGaC0~=L9Q_7K3UUEjQ1%F1>uXDO&#y_j7lK89==f?o`U;~ z9`?nRMW!HIn|`CbrPB4BriKQRz1+(Vk~Eu>@L4&({_F-b+dP30jXMNY&$B1#JcGTZ z=ccd;c|{Z0{@?|u(Ny*-pd_Sj{b0EZtVD~~`@#Exzpl@TmXCD75=|&&?7{ln4+59E zhuVx^&5k*D9!J$Qgj|<-<}uWA-x_grSc{dqZUYxzvsZCdWhoeIS5_;NBBG4XTLgFE zQ4;i}hn@N`FhrFqS?(^7uuqaV%PJb6pD#3yT}l5hANan-#Cnc{OR zhiF(C;U$?qsXcfjL3JG6?aTzf9}=4moo|dVaB^r1_>b;ltL~&;AD$8DB2TA|As;pG~A zilLhEx-bl*2r?|=D!2YJ;Yssle02TSC4GvMl|TofEk+I|Ib62^%C*;+29c&r>*677 z$mMZhj-PRqYdksr2epBG3GZG^eSK!l+}m3>)w1`_)_o#f|0piG())q=0wTt)78qa(&l#7&@Hm%UVM z_VtdrPF%41a7aD3>B0m3kakg6>R5O1vUG@dy$Ly;_x_ppK8unY28;of@!trTM=sQ5 zndYu@jfMYP`dS2T2CQlWbG%tgSxMkJCZFz8aHR+Gk_TF+AM7L2f#;o%`Pw%4D%>t6 zvZL6)DW|;US9w7SywfTtN=i*~*gZy8FrIFs6N|x2uNj(+z|BR)?M&NG_5#%K^jt4~iSWHw>}?`%@zN>@0}Co?HF2Xdu%(`cYLKKWE-C1Q+4GjjV^jRf0|mpW z<{lB$xGee)Uo#g-GJn)heerp4F~Dk@mwvXyY|&r-E{HdMv;1Ipz&1Q^g8fBQ145Y;>52oe`#DRLhNQhDrr{WYZm!{2e#nXwK>z z7ro~zLI@(41Iw9{Pz&Hd2K!1wFEJr5)7kVkY)@^Ae&`a6Ef7GaQ`qDqJ%a` ziKgLprBZ%X*Y4mq2iY_Gj5~E^A2OlCIvzzS2fRll2*n?zim_+=Ki-47{>bj0xaIh2 z8gOIzQr%TpII7R=FdQuV`S>ni?2fI^EpbMMH&`*T%fRYC9)+H~+XL0NnFp5Lg*rJd zjrwmipQstk_-aPry*KWbYhbk`#c!p@An&42eM^dDRBc(}sY}kj)^>AJ;S%oc)G{3> z$j+KZJ(OgW0V5p!}#XnCyXlgYQGlq#yUrRv_dF4^zr$OubJ6C3NtMEHP&TT%E^1D!phw zh%F_fOY4bZubP_F4CGCm*uepYH3qHHP?GeFYA(z^=NXoKU{^)j=?(O7&nm0E8k#hm z4OhHqtOL5F0NbXKTH&c*`Lu;yUgef^^G?Q{OJ z@u++WUfnW=S@v|!FX++DW%%2BmX^$hl;(ta4KTiq6`Y;~A6i$s$$8$`Dat^a((iH3 zJwq`eO>`qn2M3^I+w zmugm3kILg$eyi*ZyT=ha^G;P6{EC8@Xe8Qn=(G$dr?1-7BkIwGSG`EXZT0wQv zK2*}NM&f)7~Y7~5(rsva1eEIs^=q>-* zF}vnc$||}4FCVhOB){uA6U*n?S{~T{#HBa2!oAAN#&n?dLD1j9B5n1Bg)l`xGBUDD zac{>dL2@gVg>SvtfzIGr&7&2msPl%XtyRgUqrCy?1TZ|b zw2vWsnfC{G@0>R9lj>D-C7qdx6GBFelynevr}9wqXp^B+%Gn`=h*D)=A8*nSN&Z5! zHs{Wn2bVt6z}JG|iLM(|qJ-+dWKoA*jDRu!r*@Exl7DD{!T_ONA3wsyj4<2Yls;9% zxJU6&>7r6Pd6)2BwYLA}*Mxq9FDE{x$+U#I_1B8DM5?>;WFo_x0OO&hS&Dl4w5KxQ zU!X-bkVGlslF%|8IfO=j=vX;8?t!LE^(#F93xKA`E?+^Zk%*^N*KgmK-+Gz)o&9Sq z9<~GQ6;-8l_a%fo5xMdQRtP;#c-V%3dHD6wWOSmL6!PQ^lux&x_+tHf-$x?78fra! zW^m+*5>1?RO=GuQac}n7znd+*M%&8SHUFjdS6HK=nWmgnSW68OCTpWGrq}+eNVSIq z%+bGAmdbEV#g*!0qlCllCd=H<72G28@h^kurt9p2O24)kK^(vKseY-b?IWxx(Do>u+Zz?dZ#2OzjIi@DnY zr7!jU4QiZ_kkmg1`2I3F-*lcS^=mIx3%QEHUR(XC0T_?>&pE)q(ym_AoU&)3LBqd$ z@bkxF#G0HF+xC2xZdxu+_axdmd$$uckW9Z6$hYVK^oHay)1Tvx{v5Rw=kNIq93xPN z#p|*kG}gHDkoF{X8>xJ~ zdI_0>U3(1bU(p^8CbA)P$9p`$U`6AINRl97S>$KiWy}5sTE_SB+TqWYLdWx^d!<HKKKwBldSL5VLhhP0m)~OO z*p-84S4q7>j{=4IAg17Ko>i&^vg3~?=z`8jU&3$Mwg>^w-(Y+DC!0K1WBKG8>i^me zGVHwd#_UZy#f1&TMHA-7@>{WFtJfE(=YXf6;dzNn@LN_>LN0q{7S1Jba=B?f+VF>c zGY@k<>J*Ti^k$mtX;$UB-_{?RYQ0GaK{`&926^j>mT#P2pl*-?Q8W(m4CGo|_VuqG zE;{TRpgL!CA2KGXj%emc8^8qyUf2+=lG*rrkEux z44l0bBrN_#?7Q>VOE+EU)Sh-c*?!SD)Z(tL7j5V+`wafs(3XPJF7&gw-Hw54KLYGs z*&h=|a*FNc<3iy$``O)|avr!;-Ul5~OZj7a=u8R}$r&lk-scD21`Ano-?~3r&q5Ai zjK;>s;Qe*%tSIZZ4C!++LB-)>~Nn6Nm`lt1MVta?tK34=; z2LT4x-wpB{qPo9nnnmsQKG5A1ys5RCT5#LU^bK58L5?FPYg&yGK^o0hNEhtfcX&3M zVn(-#R?*#_EMW? z#&#B9X54(G26%!)Ts{Hfl#sQ1JFJv4)-!eH$LE-1dQTh8$J}e|zcy@h>WVg+FESR4 z4U~K>KsA3auNWNJ?{S63xZkjSmLb~sb}Z|=m{w7!ML~wc;E=(MgH7^XwndKaeLdxK ztuy96X?uHW3%eW;9GWS+?w1um%Gea$Oda#wpq6J^XukMf5mi(+OmV^SMQ3iJ=6Px= zY6nBU{FUMCh`{3TmLcZ;R2fkAzIfx!#dhik?ygXaSK?!l6GfHm;AOn|;_r9CG<`7+s$^{k<1^AHIXw+jo~(bvU?|>0W}#CCB^aq z6G5NVwehd3yMnir5{*s{t8j0#v)0m}FvzI3^RazXgeODOYuRw6n~k-BPoLuB7oEx$ zKfB<+l`q%%IV1%!U0OeA92ofI)lo1cLn3i?&=_1Wu^ddDHRqADiT{+_8d`1Y^E6ZZ zY8iL+al@8u%%;RG{B95W$*_XJJYj1&3S?=i=s*pjPj_3h2z}VQdrY1L0D=&v)#rSH zHuGF^Kh3HfK6ZPhL~D2uU>Bbm1)WOcvob_EFj6pvZHx$Rr6jGvXdavpCh65$67gx3 zow|*AP%V-g<)suhZ|m(>pE-4N-X3v^5a?gdOmz}Rg#$E*6h(a4fzxQ3N1$PQCA0AS zz^$uD52K-l7Acj9)+gjcYoyZ5!^AI1-7WXjn;AFdA)5gb{r%ClA9?lwDh6}q5zdi9dE?5uQ&!^0(&Cwj?d|2 zCn?>YQVMzofH&VoaW1$ly;(5uFkD>us&-~A8a><>P1WWD3#4c^oM<&g%y`xX8+}*7 z5O-tPyE~J+s1*Chs&nPVYv;sKR?$k^#aOyvJX|zcS*0H83LW9W!)EqRa#OmWQ=mhT zh~_EEIol&m4Hj_n?oqMzTWEakR1+v~v>a5`bi`}O_ z!}_WN6?*SHPTgBb{AVt`N{ibcKMrp|u#psP%8D)QmeoXTmF;x z6>(k9-7}Gp#tiqLMe)U_BlVp085chI0~vcjUxrwAu!eJ3&G9pAFfS@6Tr?Pml6D62ZhNx0fadi4dxiJ+ z*Ip|G**PTVqfbvI&mX>Qz23FGT_I_ENma#Qt*Krs9tZH-jYK#m41{CadOw10=ZB7? zn?7c@z-XI2oe%48$0NQW$#%(V7+2T?v~D1|38!ZY4}G6-3t|;Q2V-xHdBVP+Cmua^ zPK+vs7~UL`=sOM;mYg1RpyG-h9r&RJ%a@>{m+QD=<5R{9%6KzT9x2>vJn5O1ey1Sc zb=U?UvF&|V^=3Fs1w=c`%p~0r6 zgm}t#`%aLnDZXtA7HNPLy)!y0G1~*+%hcCMm;_kFZrW5uZ*JxEkK!u4cC9oqD%&>2 z_K`PI6E&i^BCoDCC6uVD@`_y)?$E*Lz@cf)AY_(G4=F&Q2cYd zs~;@Ey&~~lQJm&kT;AsiI3*=jpa%;6Pi#GAXSJog@0QOG*VETk0_?U8Tnx*ud7uR2 zUrm45RQ2R1_02Lhg6VA*j+>OxkAhX4lP6H}`x+5k;3isKV#iZYs%!w32EQOGL9!s_ zXJqy-SOS_Sgy3;Uuuc^SO=NreewLD9_EzL{96z(A_96kquBu78?q)1vO_xkUi-eH8u@*u;YBsWfi|&ml*;y^qUnM`W#Bpr%A3C2 z=Tlku%;VM3f7EHzY1-k(mme#b8J<&FJeGZU#A{T-PPba-_7xxxJs=k zQI!Pnv%^-iO5SwSilLPej>TW7`}NX0PuedOe}Cg$&OGVZX)1C20r#u-5FLabE9`MT z0!#{;<@6(jTI2d}NAX(5n0Ton=DN^+?=QmgYW4a@6$$)oDYBK)=yBN#RXOi5)FX7fXtw-NYE)9B-kCt7dJ8 zEIgHWjgtxZz32^)@s`a1{(AcTfbX?zALHpxEE!?jaUQ3s-y%jBfR6&)DNPH-cU_z6 z%}~`wRv)yQ#@Vt=?_J;`2EOd>aD5;52-{`6*{uUpAIaQq7@L!o_GLIR0EPV^41iKU zzA1jz0ABeSKrp2CLFia-YP1td@a#SPBP>rSS&BLm@!Kxh_JU&R?uSr}7#8WwQdvC9 z5(G;UN;j40Wb%0TE_ci&;ox#HId9r8g0eu?Wx;>*qEZB*@$%!;uqA zq9W2PGOyD6pNFp~1{&Qd#_LKfrGI7v;4S+?aZyg0`Q0Sr&%k0va%S;&HapdRd&w+Zv-)CadYXXh>y86JTM(CJTmJ9~SPnWCAj#>O+JBbKR z-toy!HT-i-Ors5?0nhU#e4F~`5Ln~%I1f6FW3FU2;iJDtrvewTzuw)@2_X7&;0zUP zB*8dFR`Wc_fTQAY`w=TGTCQaJe>zYj(!2k57@F?Pm)-z)&Qi}Br__DBJbaQEhoYLp zhY|8ymr%e)eQjO^0^roU8P|ObQN&Uw+LB(Nm$ShnQM1L5(H@$KI zGRXefn%Ojf4-dc>YTAHFh6(`V6h(_d!j0dA)4Xu>OQ$7O@(V$W?jKQT2fu;Q$Bn=Y{Rf>#KBhbS1=*SVpsP)^UFsV9?Rx zUJHtL{DcKc8Y4e)&Yuwdr{C6jkdFD*M-8>1P40KdysvpH{_veU12&o?sI?0{=s7wp zlBSz8b#9IIF){i2tyucTuF@Y?FW#5jv`TzY`T6ZvCEs3*vXCF(8YJN!3%3r zozH`|m0pDP63!ZBX&;x2iH(|kdOJ7P^*U&XU<$CN&@+AlW_5A8K&VCqNd{cg91(n0 zmh3#vxnExBrmM1m#tXyYUna&10I)GJ$;uFO{CWj}=8rQO;&Lag_#v6e*oG@U9wEqZ zVs%D58%g8c4b_HfB;tzsG97nQ!t~v$|DYm ze4!rJllQjX`uZXug1G7=ZER=NvPP_jV?n+EacxflimoJ2olml2kd(30c=$OIaOaa} zY=i-4mt5~i)67n@=`O;wQ!7!;Fumu|!sJiPa`_<3jM z$c7|i+fbclJHb_E2|9$(=4Y(Lr`x9%xkt_-%AZIYAswLxllTQfHPFs*>z8xZsv{{D z5O(seOcygIIE#W7L|aEdgDcs>XVN%aK^=T#oaka2o*k)L9^|WcL;qxTW1eDo6gZhh z3VFd#$p;M9{@=APiNN;5LSZa!25R#yWdjBa$f&5b* z76Wl`@90zDQQbzwC69RhfNxK?Cy7-SCqd5*0tuni7Av&h2r=2|fAVln%8ZewkJ0A}GGDKLP3d?rD- z{c{TNT+*$kzm2kR22*dgop9>A!8E=lO|*2^T)Gjgwy4(J7knt22)p3zC-zZXQS0|? zu7z+#x9J-1x@?P%YREP^`z%O32sev}1i+@8=Z>NlvqXVMyAgMM#D$_juk)JlF*X6Q zesr5}y~Gm|0hm$P?2Kkfy(#>LJ&hM9&9cMHi}sg&`k!})VIa+|}BBxQEE6B%sCds}`3z&M;M}P5M^3bl=Mkx~ zBNa7HYNh-#qXEe(lVeV)#2(Be=Gs?&c~l@A2YTVJv!=LdiL?JK3$Lft+Hd!}+d2%+ zJNuc|2q!f^Z?G@GCbL^KVAfz~a&^;r&W2w|HSmlE zs8jjbPRCq8%bf1;7{cLGH78ND57EmR9$_FZ7j4v)SU?UB$o)AC*bLEtamoe)Ac ze{>h615B|=>47`^b>M7mr7S0_BT47TYQED@4a#HQJZ%lW;*IF9AJ~8(R+TIxWkX-^ zz?Ua5=9eaRjJKY0CLPPe8)l5D1@1f%kF$EU=9xD3YZHjWK(pHq7res6` zQlW3sr$NbXH!Lut`m62Qj=-tG$rQ{si=3Yg_baqDG}T9_KS`R&X3xhYZBeLwI2uks zK{XmOy!t%KgM?-|3^e;WKIw*VH7U;!?gv?LjW|;ZoZ8V*tS0BDlZ$W_w0#mtYTZdX zPwT&{vvBz%d@HJ5KR`Hen#bQ?qaX>T=I*wMbd(QLeh8rEtzAixs^NWvf4#pH19S@e z^|pmuEd6i7wFuwJTmF|GXxiaylyb_TX5*+r|Kr`&ya84k2v+-(x*vqx;M7BMM!vhZ zCy;3&TxjenwJ!^3C<0dpQ8tY6A1;Zy-b5z+hiZ2c8FjTKVk$&;uQYI_yK~-m&s|<4 zS1}arB~|@;BZD9F7Xip{m`?g*mb=Orlxt;4@K$hfu^Pt9KX(gft~s~!{_n0bOsX_p zI6}De{PLf{_kXvcL31xbh!QBKk&bAC5SF|`D4-GJmylF*rZA2p0jqXa3rFj)2PTK7 zRiEDyiIUs*J#;=S$kPb#ztVP~#>4)^NJ3DPriWMEFe5`;#_GAxik%Tvtyz%CvFK0| za60z<^Wpkwfsf1$d#MjxkZ~;iO>I9Bi)gIDq=a<-&^(y}y1{38W8IFe3`D$Q%9*v* zD(LQMqO$3Avo2i8^_=mgMdmj9?nzJa1%j;b!uS1}yqy=RmR_*S?j(zj0*cXReN}JA^gH2LLHV+= zLRK7ZeCh}VL1yOChLAE0Q>ONrjxLuv-SEL;=X1!Fcm%dnp(?%rJ*7>Nf$E2nh70&= zK4vKK*{6amM?&+mEopVbKyk`PUQRAAupudrXF%M(M#X9`{d5Z2k)WWP@ez3*m!GW; z@aQ@5DmxnH_N4Z$qxgFgqr^hC55Mh8;JE#o|lI(4}Ga!dZd41c^7wIYvzoB2X-JB6?OIPT4uFRDi`px>dxZ> zuH0Wjw@`*?kRjdQsI_g86=HFN&8An_bS<*Ay<76^vbCqs$g1)djnz-&{Gf&Hh6tw_ z0k5ivu+3WFads+#E;4Cav;skgLuuBS6~6>)R}6& zj<%6vp3#`o8tdVGa2oD;-V3zsCTDI7 zJ&xx}-5u7nUUDkMBC77;8+e08fHGEBe=(G0`{DlW3&_YVvO@IvIM74JqFes{E zlC1Fr$b-IJmA5mHn%bE0P9I?$K`;DL&4yz7V=QE@sMbY~6c*=Rx!MM(fW*E_O+i8e?@B)u6yLn;@7iJzC zO63s*ZrgJ+hs!3G4cGIYCIPt3he@qqNmr`ZpA2*-2J}xeIc-WDjPADuy~bd>yG6aL znPUsKr~_9k{x(_^1SB_#{$r&ffEG>llV5N9LcsS&E6G2mU4}4iD`}1F-=>Y|a{vF* zF8@ziR~`;k*uF(6L}klbNt9viyFv=p5XNroLNP+N>`BO$ee8sWtYgWHWiqlaW5_l$ zb|Xv4zGSSwQQvo6-*x@|Jm<`L-sgSZ=iK-GoHOtH#sL~$IyvF81Ux=y>o3E$&D=+B zpCbKp47F{q=XFFHl?a2Rb(IPpm_BsetIGc5ugQ`(1WDlHTQ(MrL^g&S-DfrTTybyN zctYg$S%m!n4S=N6mcE!%xDFkfT4pCX^q57M{mY?byzgID$pH-LAnUqSZOS4;%U)_} zSK-{H$z=CMTrI?)r#xa0erUqpiPtW#kzq;g9QnDGw|=82t>zsm`lq@G zzmL1R*<@=I25XA~SUuJK^5~Sk>^zt8OS)evof$T?mM4&2ewd6!D3OeYwkWw6=&h{t z11&J|Ca1E!{@DZjJRd|GyJOQ|2pk3N&K+J8x^3V>+zR9>fJ~NJ%~RsNlu8jA zApB00+R5UfJ`vqc=0l~F%0lS5XP9IiK{l#lEZf4-R_&m~WQ_m5>f*G0W zb*iSWL{dL^0=D7@rAwQs*lqUE4CB7KFQa9Epkx#q8^;Am3sdd#mpl={QDLNKwtPDl zvMIX{Z&4oXJ3}H$>Tj_(q8nEEmdI%MIx}EG&&ZwX&gqH(fqK>#2;e&E6{Si_)Pm8< zYvc?B>fz>)PXtp*g^RuL-Fv348>Yse>y@H02@2>dqBW7im?>udMvSmXtCn%F399KL zqaonjCsmr$xu(ZG;ag6}u|Yb7w`-_&=rnJ`{K~>XTTjlcJ8nebXET#%Ck$%`2!j?k z=wJ~;j-cZ_R+OAr<%S6Mdax}Ef8ztqAW_Qbgr51BPZ{NH^^lNC__DIZbi{nNCm&=} z$MjvUYqv3E!Px?Ljxop8{o40zI9B5X*EH~10ik=)bI@0?DGxahBD)BigxVK=ImH4jwnb}wGdhq1otFq;-tL!FOLFP z=zGOV4-&pqR2v71PHW%iwmK?N{WrK;&~Ads-kq@ABIod+$b}IIk|!Y-CH+EcM#(C} zptSn$^QkN(ei`X$5q(Eml$Lj)#c|zvy)nqqOlQofu4k%9SZ(Al3SsOSDN zgG4H((f~JMJrdK1cBbUggE&d49^`^Vmkg8;MZ2@v`E7Xbd?jUwr1{(eddSfKg(n?>#O{{49z@b_~1FtIB8eTzOS`?ua-*^KuzB1CV% zLUGXjgZ+9r7xwLtgw@YjcK%iCNniqZwJevop9GNtY|8N%0QL($23)_y)233;jdzRK z@N!zGe6V z4$hfx^HPAAVwZEyAmTp41S?2(_u7)S%fs@?GQZ*}N0Y58_f)a2il&-fjnz)3i8WpQ z=rF63ykNbzLfR$@hMDiS2WB~EPBajJD1 za#DfG8?nY_&i;{HdEXdA*85hDJ5 z_>(z?IlmPqS|CvmsfQz%9XCS}|JH z8+nuZ-o|C1)Te0e7@zi)0xu*X1;NrtVC~r0!sHt_d z8Z5vG)LSFshA=njgtVTR>Kcr^kU##(ZBOyP;WaJ3-0z8sTIG+U9beCs1eZ8_sOEV4 zQ1h{ea8VT3**a15k|EMlM2VV#@AcShfJIt@?K7xxg$K7V_;_tD@Qe<}%~OZqQ!NXu0m9 z$RYe&`tU*Nm(vLMx81jsVR3U?*zDh_IsM9ED}e{UND@pJCM&zvndG9+hD#axNqLxF z5`Ydowr7U$3cng0T&r(Xl8v-{px*3`Pf!^K;!gK^nMk8?9(0jP0OBj?gOxBMWwwhT z4wlpV21dHA+#&A3QC%Y`8OwgbTA6?BNBKFj&26QWD&@#2zHYI)FqoIsdV7l=OPP%z z+pKMuPVcNXjBYXSfXhqZlTXLVn{!)0|Dw>&SQ>Ao-P)r@Jl$0PU!oxn0a4?=EI)ra z^JL%#P*ev03HlC#DU?fgjjO{hRS@s)&Ii(5Tc&+xiiX-N&`-o=j*D zXx^0ff)o&C;d(g@A7hAST0#M~ttqdEy@UwLY72x~1WKxJH$^}X=TJAauf|j9 zcqq*Y?@d;8%av zv`h*SOXB)#Q8SDzFo+g&SPYb=H%BM+YN0IlYAO>n4u_h53y8W}PKTB1B>_-a6CmmGQMXTd6J*C&tEKU^$E;t~Hbz6Xh{3wJ{us_b zR57VOq}?3h4#patS;ca{$3hbzsaWe=x(P{77ss~eqq|O97pj|UUS5!X@CHWv11!eA zK5qY<4iv|{mbU}SUIK8Yy!kV<*IV^8bh-bO+?>oupC?4Ex^MW!{Tv_W@m{|# zF1y8PqAG1qQ*sdVd(euM_7&L@*B1`H1IApa=b-g!9-VO}X-B{b5MVvgP^|f}P1Y~` zmoGECw6AE<3LFmXjniH7xMhXFLXojiIHw2nd(VC-9qHBO7jJ%uk%GS#Va|&&yJHo_ zkTOHqPP{HE8K`b|5+xT z0xAsB&YCQx|Ac&_8owy$nJRaBZO<9LHuyU>mR81ufvW8ZxE09}J7@R+{SJHue4I-- z)7+7Mp2HSFTpSM#f!9{ik=IVX=%_n6ku@Fg2{~^Yc>GDjvF)SLwUYTS?^D9R2)X6@ zI}UigfV->sv%H7mGWSl5N!l#TjoLCKOCEx|NTDGxr>#yR$Tzup;e%BY85KGw&^DzS z7so=`#lbiM20ZR%50<2SEFm|BH_a+Q`dGCCI2s0!Lp6Ms!M7jLT+8*c6OAxh&Wf=C zTpbf8j(G)?^&@ z7fa_!?OFk+x%y~Ju6D*&&li#mlIiMu%vw#jpv*f>&w8Q?Inmo^WS-@{wvI_E?oZ%y zzbP6t+&e)5<^*)pj3FHmrv9NnLsD|KzZZ}u)#UNta(#HhiQDLtOU;a2j9=u;{R=-> zW1XY~@f0T|fEnh4PiGdsAT0VI0zp}$E@DZf`zFQBO%m-+vgX`fIty~e-w;onv zZmYpOIWXS8`Wk(`zA_TyOYCc?q0^bO?OQuaNBM3ms5`O=APj>(?_#VU$Gb7|!Vy}Q z`feKT23Pg+tS4qe60snGd0K=_!&(cju=uvh>uEZ@IfnPK{P$zQ-zk#d-GkoX<+@tr zoa#fIHz2Kjv6o9U5KcKGa+W)!Ut(wfuh%CQP#;Bto%;@n6pk1iVNR4_bP}9*SV9V* z6A>RWWt^_G;69cSPR<(s!V>A~t>4^?K=G-fJchk1E|jz&OD_n~UX1#hCxii;6kr@H ze3%reKc}aM`z_r+!x7Y zS_m1(gOw5!7BwpHvX5y?v8W0gUy_zW4<02+RJ5Gnha@Ze0Q<6hAoT7}kga;2gYZ|Y zJo@TC%%9Ck&m6t~QX)P`HECd2^Ocnh*w6&|Vdp?~?HR4zwr_qVa>M$Peg%RFwo#f4EDVqz{} z*@jp9Bu~}io3mL-?F1vj7Y`;pV!wSPmu}G@2ldU4gq&wS>5Zl`Gg|+GG@IhPzWQ>~ z5Kv%^6!LiG6VuUvtAa_zy)BU>b9JVi1>q$&Ga|H;1{%l)W#|LntS}JrGq6Iz)E0-# zV|tZ(uri|o5t-#!uN_wKacUd+l+EEs?k(K1y>n-!-3g^+!x|pH)*=wSS!LE>>n+K# zElj69E5&{*_@W3CS|9MalLX3j3<>9WHA%B+UnZZGnc*X3n;9y)tK8MN!y3yNm}#1C zDDk3*3~1jk*d64newOC}EZ<5d!}U0DA8!>lY4#5=)l=tz$38cK{EDV^GvL(kuWmOs zske?*LDt=OfklcRY1ve4^7wB9_CqoqRM$t-5j-?$E$?h%J;XAAh?ccIN*y5A{zc7Z zIX5x5h#*uI^C=!(nK1`+HzUn~I&(Q_=4|1Wd0s0Z_Ak+wl-i_}JM&^&S$}z({B4@! zh%W&ue(wHyW$QBU+?*4U^aum5NJ7$9nw#*L0!xv~OKpHSkT_DQzMjNzmob6fwS~q# zdV!UBNFj9Moy|AUG8Ivw8Dph|hl?t;(s-$`ChN+9c-m`+rc5b}$0Ba(-=-+>=Q7~+ zYHzdr#>x07jvV@#ea|Qn2#AV>t(604YUX@j8C@=;XjYrkWmPE`I+w?|>DV@HSbh}K zhCu!^7c3iGxgjZ~*ghaJ9m+WQ$3thb-j$Oxy~+&KMAmhA;s>#oP2!k87lKBo52#Tw z6_kXeiG&!2*GO+gz!T~!K_K$A!ZepWxJZcapkBLbcD-Bpb4gZ|Sy-AaeHtEHDl>P4 zY~}PR+bSFT9deo^VE-BGZkgwS^c3TAzqS56{vkb{IjJFoZ8Mh%0cmhyZ&T7?0`=VC zHg$7qtI9*&SERfW;kM0P;(;=1n2Tb>IsG;QHX5|8gTi*|?TH17n3HSgJ;ZSjZ3EQn zFJxOI2lAWg(C#GtYMWAI3$*21jy?XMjMzhYcXVt4KQsF1-{1n>%`>{>qt}l%aQoC! z5UZDYlglvwkeC0`{lEr6xg*WG4|MotQ!Q68*U0>kuPF8n4V>&JL@Uklp4C=BUYP~K zkjJ*kKPMmijGS>#BV1;w9d7$J&Xa?c$s2Or-+6R&KgZzybMHUS+^O+wVr>daZ{ zlzuWXMo=hD=LGuQ>DYH2kJMwT{@s8)_`Sur5BT4p-1tEelUa2jpa|pt7sbHL%);@1 z6vKZu87mu$I5QI$>;F*ZN2pLhhNL~5M`+Z|6_CDfx5z+9zjMvMzj+kStr15Ib?x2v3@^fx-a%yON97v7 zctYUw>EMN_wm?4$G9ou$ue}}T3(*z7E#M0OPy?0=9Zn)0acrK&907>B{(s*DbB%d$ zY|vky;3UeXNnGCP&RrQO(zIvyWdK$;;4n;OTBouV^}%#%XIV!Z@9rW-vs&ULrfy`z z4!m0oloxX?C9!2rP25aoU#8X}z85EESRMS4)ImN=a!h8Khg$sz@UGVI3t~4N5`KtEw z#H&m*_7#gD3{x{8I0IHi=pZX}cgPi1dS@)IuM|pl`Vvz+{^&zWcNPuA=}`nG#XYBA z7vqqS9uo9I{u!|Bh&a+=f@WV=E*J0hg^(G8EwpnX8+aUNDf2S34W;*?0pXUzLqn_f z7CH0@>F&5UTR&W+Y!Fa)-1^sN{&XaX^soAOIIbUDh`>gXHA9Kq1B*`VY^+>A@fi(GCRaPzj>~ZLCz`TMz2mGX|h@N`2Y{&t9iSH zdQQmZ3sBUprES9<50RFxcEL5tv6c(tG%;A!Krx!@V?Y6y(xDoa*^T0MRHET>H*&&GtsMwo0-eJ23+2SRLqkM-f8r&2QR zbhsyLQexmdcakYh#g}?}P-HZHL#AoWO1>=qHahDW{8!lAI3LN9N%=nD_j0WPSej)- zckO!=G)y|X=@YT#bE!29Tu~2RlDO_wm^@lgPK}M9e|ONbYk`X9G3TOxVl+tmKxJX3 z4aNf3#%3k6X0|52CjCB8`Zd+r^I6cCy};L~#S6owh8|*o z0|SD%Mh&*vDKPtA}a;izQl2Dawz|A>_O=E* zE(5tTxBdcpWtA)jwlaqmnut$!Wsm%F)$`o8-ya+cyn|2Lz3v42iXa4nI>kKXP`o9J za(n`OaH94z0%^1nlaTC*)>s#TTtD0|^f|AYNs8id5Zav%7kByf7khp`-ka~yuf3e< znCilT7C>CC^z_rzFtM+_!thX}^&nC#MGHDng2_NzPp=rnNJ)HJYxUtofFc}vxQjpj zdWKa@?PzT6u2^=O<0phafpL!8`Q57R-BOf#AO5rbaS03bnV37xw^ST7=d`vBBo*9E z+r{IS&<`yD?hb4pyyCOGnhl-N2Q?!un6OLw& z+XN)&bTN?Ouj4-s3Sz>tNi$PZZCtS#h8GJc!sGtD$O~RZE`%_L{0D35_HlncTiu4s zfbUmdZ4a4AL6HN3{Pm;Gz5W!VLj=@CQGL-gKqB0=)kmRbsW{R@_mS?I7Zw0Ja@%;j zDIw2vwoSrW_M!xK^4q^PGL<@jCIQBQAYSw*LCcV-)sM@OJwdS|v%6dOWnH#RBSd_# z-+lTo#bL3o->ZTh=EQU3bb0+i!4xL`QD4DqV=}t73UgJW&dQV4d$NxQI5;W9-9ma}fmRY~n4Vy9tU^8&Jo!`h3_!)d7bxw;(% zMLIM)ly@P-rO%o>476|@(^GBR6c_aRRpg&2G;v~M;0q&?-fvJJ9EVGI0Ha+m87JY< zF5&f@e!lO`&pJuLq4ZI7li@_Iws4`<@^MS&xk+S z&%R6Ys*@!+5hM9i9@OU{&zgI5HTVsm3THPf79j(vc7;|?d~4sx>K%d{BhvT56cj`z z0+g#YD_&LCo4@^!o%c%iYC-p)E?wRx`AawQqE~v$)#V9G!Y{lC`+pEvUsB!ikGG;R zEg$D7QL41M_V*=w$=36Q8il#Tw?ARI&XcJpkisozs-9cF|5BchWE9Mwj!;PQ#3mvs zS_{F$zvQ)H^3(z~3vOFh3OHpr*i?7ojIik$B6?;iYR$ynIx;w7iB*tObY>}zjXr!_ zYoH8nwIws(_3d_?7mz08JLoa{W-UMfO%g=VR>a_%x^Re+ zbn3-i@d@v|P6b-FE=3sd9lAQca$#SN$sZziovhVesW6U;5%*QnM=*ietYDLZMuflH z$!(R2(M_>>5nJeWA&Ew$C!>*zwPPbYUQMCU1PS}!Sfwdaup#m^rsxRI{dCnDcdU>o zONqm5{`Hu+FIdDW#O3SUFoW)VpJCTAvlgNEHaTc=YcVc)X!u`Aq{9<$gREKXK`VW) zESZ}x=md1=$JTfeMh8<2$azhnO-y~wpz##p-DRZE8Fu;Y22`E%qhB}@b(pm|^zD5X zsC52^M<*PqbL6um>8EnWN7D$s+Ms#>p{FTZo$}4jT;Et$O+3fa2z5YPo&0gGt%l`K zlec8xVcNWA3$@g?;+@v;2mz_yQf9kp9DUKvts`2&i9k`%Agqb;DyW;-M~F_kF5Om+0-5Tvs+ig4_yj6}(YclD=5owb)CQ zL_`|rG?vHAxw$WY##1#nQzvfF(+7$9sQ0gPNtz}W6B255dsr+v0s|6>oR(OvbNC)> zbp<9!KzjF3jwB`3SWmD-{nkFAZhs$j<1irf9;{9EH3cjo)cG&%!i#FDUkp zl(~1m^gh+!!Cn|N7Uj-g_Xsi{dm*3^ku$L=Q%=O*V@^x%{NvyjSY zJj6};0}cub2M*(jRUh(l3HYoksP`$5p-wBzQ^PoTbbLuu z%dwxn^XBsk{?zZpBK(O3m7>cp+-B*-pmW+Llc2DPgWz4!yw_@H_Gz7 zBP**7G8oWsBRokL01NUK$0WQ1y4L8KfBqx%rimJ(_k{E~_ z1&H{fYxK}TN>(lLM@W}@zD&$oTPhKjGx`dmeedR#m68uBb;b#=xEkdvVGR)f!k=Eu z4Y*bgE&W8WMPftF3*!RizwdUo>6$_(X`0N5krA7wUNJ*)3)#)C85NHpoxpL1JiAxk z=Q60`JXe%LYqiJ@h!jH--*@8rz{15Nl$xFtS)}^z?`8`Gslmi4TuGCUsy~)?1u)G%RAJ3lF$uux+%5TwdjpH>&O5Hy_=4J}*`l z5j8?h%CX{GQ1*FEPxfL@c29h4Lov}yFT!@&@hYx810hm~Nij&DAayIvrA>}6aF#%i z5K3l<^f%?V_=PIK2f22A3G+tjI`$MRGm31qhuL<*tsJ8YLd6=#5RX$Js zw-FjRAXS|b1ul=BEhP;|SC;%%&BL|3g~hKHF_u>8-d z7XOmj3*ODgXmh{T=JXRm3 zE)zzBAm9f4g&`^MdLb{EuML`XczPBE!obrZa1}*_ zL%u*tqJ!v1Dz}4hW#2TO^^Mj!%WN5fN7a20TYb_fgfI2UD{GpU1K{*R_a&Ij7h}9% zaSYP`Rqb5%N3Rfv{aOJZ_|cpd7W_6xZi*hXFpg!ziMTJ$sH7R9`mvIPg?LGyo`W)$ zqkQ?n0o**nTfq?C{bx&)Q!MkZwo+7(TBDW;g`c*+Q4?0|jKLmuqJfGK5r^PJ=Qo5Y z??`5y#C_Zj6Xa!;?*~g^@G=E)EyHH*Wju}zuRX)$o+d>fz2*)fQagt~u9STf4WFA@zf>lv=_sPst^1#OWAe_a zAo)e<4%gOf88qjVlV?9d>rAh!s_1OE==O2r>x|Z)cjuFqqRtg9PmKHv<=JhU{RI>M zLwE|k{PeZ(oiWs5+OQEYR!}1g9rLxm)Nd%ImGEWpMNfaBKK0Z}ihbMgN&+_D5Sl6g zyd;P|jJW)D2|Ra{4Ctc^0Ka|dGmh(#fnEe5tVRl6{ex8<-S~2VNZ>Ff>_DOpp;pRj zvvq*;n;sYYv#^}|)6LbXC%}KBXyupvLS7!rXsjR3?+t9uGutw?@vq$(m?ES34l^-#uCo4uZvrOUb8Gxe z_catG_$_rc{w5xP^Vu}|)fE^(jo25!S*0IY4_d#rW!om=?$W$LW&VeR)33E)$=CHw zZLrCJpq~;KclVrou+`67?;p$B5aq$>8f+52wGjpAxpdR?_s!9br#WACIv+!NUxKS* z4O=11R3QUD;Slr6Bpua&9c96kT|RRXoyq+t{V3Ds>TCP9?s7_4b~=Wc0``6A=}>-% z4s(G(#ro1h6fDO{!{UFaY4C)4&MHg(B6YvNc$&@RnkF-UJ>Qz19SnH796}x;y@Kr} z7#yn1q28H&8nprXj=FWDr)C_+H`N}>iwf*?U-+TlpEONB1U`2Kn-o=~i0W@=#vUEp zwaQRgveu7i5dlNKf3|N0k*QY^DK%@&wI|-#Kdu$ zC0g%v4X2q;(y94vyQ4jQkStYnW2>S6)5l>f zb!A}<&iMXpah2%B43(G%O=f%P-1WCY zk(?RA8JCTkI4o{Hby;%z-SiOiY8?quD0||zL*NFUc*LLkuQ~xzx=_L7@N3&)eS>{1 z)g7BARJQu5?HToMk7#_lz3Xa*dp2UuEEy&Pj730>o)V`^;MB`L?!pgMN4Q)!p{ltX z?;5;&S*ECGj0oTzh7p{a1oahikj%kZN zE3pJIF`MUxT?ook&A0t{{eCz2`ns;IAX&fYZgv9uoQcwXW`Tp|qMxb$0Cfuh^0Q4X zyIM@A&LS8$ymU%}uhNTsTy3Seg0v#fzx#ttBiXo2+nA53K~8a0ahrOg{+a=IEmV8V zn~Jpba8OjFb)-cmIl1~`-^AovzK;R>C^gv4rzr5EAhms{fC^zY|KgkeZbmTm%S&#o zFE?PxBW%6@sui|prFa=Q!4U6(R}Y< zm6>ahTzDMh&}M^Zy^z~}DXFi7sY+)=-Tl4B$>RWp?>XXWO53)Igq{@7%&bCtG-8d_ z!rPbc6s>0I-864^l&?(LlGJ(y)0LP;?{UQxBc$)xxSD{6|GA@Txj@o1>0zFJBto&5+QWK{6fE%_exC>Yaxa zE1K^SaBYU#UrvW8@jbI_iLTk670WH0W-sC&19|KBM*YY;D@J z*cTcNe!s-q>!=>WvX-KTf1D1jQpXGpV|YRQ{AuK($^N7k?;qc!9%|siPtD|ZLo9No z$-;5vvA()E$UKNV$!&JXg!1EZeuctW712S7oAxkl+Ab)ELhwbg2K=a`{^Hqjkx`u~ zC5vd3!GXRtUk=CQRz&%gALh6p>RXfnkT>7&mOEsu{%6D~!cC?e=>4+B>9uT1+l#0u zk{A@f;3@mgfw~WXsTl&}kN&S^QWH!eFLRw2pk{7YXU3prVg$Z^*Jn$?CY>Os>)M=w zvXtu2*Hgq`<#D){4$vA>o|a#gQQJJN6^hSHl&`=wr?qmY>nWyv4nMuXsK+T#-$t^@>?uMJ;Y8w#<}?AW3x^|I30v8JT=D%Gy74Ygx3**L*XH?~j?N0f!HL?e$4 zxm44sfywJ9FMJd{Vi9(1BQjjssSEO5;72|6{tc2JLmhI9@O_Ygt`wP6@rc>eZ;U_O zM0^;5)YWw+#RNGH?ikFKC73?F@gcIMB?bJyaPjG+Z^NL*ogDvWtic?!DeSs?N1VTm zRhK3B20D!%%4TpulmR9QYIQw@04-W`V2Zd=F`a|M!s=!)8ngl>TZPQshHB(54k`A1hA`7UnlHM^9^&c-V=o-hriadr3Kpz`qc$g&avdEL zTg^xl(aYjBSVl`5y(cstVC##&!_W*Zg$+^H3S$c9H!4o85+TtD zvu}2y>{s>J8;0o(5M;hHhRuRayD^H>`DBF6kTa$zsn`XbMf%k5WsIo(W^@qI3bTAu zpAI$q&MResfDcmCSdOrv^%3dZGm1;6fjSs~tQ!SE!*Y{%U_`w6*l)gxdqo+J@Dp+x z$5Yue04o7Ef)q;1lgoCkzG%ps^6Lw@T?|YSEtRzw;ns+P8ra@(t>LUlVQB_q{`l^S+xqm=6xyh4x z{>`-{@&5Dq$%WK&nzLggc@v~4KB2WLz>`xn*58tIA;PFgotp?cN zEi-8ql(eEhArR39Q&E}h#)C|ar1Qc+Q3^N_=jyj{Gbw2G^v0m9?U9ozE*$z(Cl_ttmT@}0_QTB)Y- zK0s3f2;a^c|E+j0z%G8=>Q>M8wr>PqH|-mq-pM7TH z)93yu4NAOg`_4V&2WcviqU6p?{Wro18i@RdYK)T%;kd8@*-;bHINb;QunXc!)y=+F zfZ`6RBqbEs7v$4x0PxT+$p4NQ(|t3hpzwfzy#G7@5AB_uQ;hR}M~uuI?941|%;K#7 zft>$madx|@>dri{OGDkrLxDv=->`S~fUWJx6LErp5QD+a?imq*c?6^41w%l1tPyvD zVL##S0^V<4AM#z+x@~qo*YqOVIN*AGx@+?5>%FZtE~RTKt*7~f_JjomJs;NO;_qGy zD1Li8u91*vfuNwy?gB{m6Oi@;s*sC+pP_+?FB-tQb*&g{0XEfqxq)zV1H% zeD!-q2j2Zm4x`N>wVER3Q-0Na-wNFB0lolpe)_jT3psMGzL!RAr}1WHtTpDofdj)K?FEO2KIcYl7`UGei`ZTKr{`vBZaPUpw z{QzIzVq$EfmYyVzUC}Ilo;4G9s4fNOvyRHShZb zx37SPxIVPvSV%IJ>mBN!6zPMY((=9~CXS%}RisQBleLyF$JnW|yI}+img(tr@>%d+ zAc4E~4f~R0?WIsv5F~Yf5p5Ie$j-KV7(5P}{wf&`f6i=eW#xXyg4r4GyHB|LGvd-8 z7k^v;so?qhCc+Q@$b6HAY(nflRRlHc1^mRN4ecH6{i6^RdG{yOxmiDM$l~DhzQpx_ zk-+$p;3#V9?I-Ps^w_Llng4!o%ZuQ7ioEk? z^0vVMAl|5#Hb>WHM-7$TPrVzflGO-eQ;X`CgB`0BnEUZFa4sS%Sz8|2yZ>5ssa7;V z<}(qnptm9(b3h3Yr7Mx*Z(rM{N-*2*NEh$7(!O@U5W7EbuMk-cZFdWe;O#5FK?{!* z0}gl?yvYPcx+&!QXI>uY--PA?mQZozzmJ{!tlfQIq2W(y1*dxaF9U4iZ5a&g@Y{9> zwsP0oq5=B=FWM0dFGV)6v$tvi`er2hA1ejdyQJ3-byqjHO!!t86N4X_wA*({*1jP` z=b&TkYu7*T1AaTPICR5HGL@9ml}P-Z7ns0T1=Dwci9OAm)@*N$}V@9zSAk#l#bvem*;Q_xmY(aa^ z`fZh8Sw2Up#GNzV9N1Wz_$Rujv&4JN8_(ZQ%eRasO;bzhUhQI?{z$@FpHE+?IfU`g zR@b4+6`j*Z%)lk^>D(60uNFonjlt`ge*$_q82qp2;=Bh4`+}g?AUpF#w3GR!9p>cO z2(RCm!#hs-0TkiyAUM3BcZD?y0x=Oi0fm~j2gDKfQopvXa?upQ&#%v?-dqgbddQ#f z$KadSzc&_i^?z_9()c@?@?JjFOgQgE&Tro|ijk>y+++X70=cO$KD;hbQ3I*`kTWC* zY--cY*DA=%(6!%|vu1?a@b%3SSL_ZmF=dHz%7h#jGstRhBmO0uN1kf?n<>k-xjWm3 zU-wP>_uZQpex_8ix9_-eOLD@{E@x{KF>bs?Vsvck5YLY6bY*v^ z)S(i@wg6!};c6xg`GX3~yAM}Alt9><40cV%Q4iH}bTTwrzV8(yY&Y)jtQOphwqUKk ziY%eeZQy_h{BJ)tkLCSAL-3?yw$d-K$SMN{MKf{0u<^%F!xGq zyCKpq>@&}M{+-Gd+iHy+u)5^GD(|#CY6dWDK}|!h_8o<4g?*>jmiR->v>rfZCu)LiJhCdeDzdh@qtVu#)li$jhXo{2JfO=jsmFLdNN#cg01b0E;qBl~TFO z{dfj0kOe3s7g`dZ2v*$0q5Whi5|BNtJ2992CjvBD=}Dbi66Dh2ZPcUO8Zarr4Q>sPc1|rkF?1x_g$)rr|^%Oc}E37TM ziuQi&RV}d=fO}!6UwG?ni6@F|y_lnXfAC+y=|F8tK*Uhs%*?BWRCBUDcBgXojh(aB z6}NS?9&Gr%wF2JtQXYA+Wgz!_k!6>zwfD(tGM54#4tIc$95$FzRbMLE@_4~457@y! z^g0PvmfaZO!bEfYJS~k0tr@dtws5T7Oy+Q{4;Y9#_g;Z&G~jPIy>?pL!V$9b9{yvi z~-P&1~S%Vx&niN?rDm59O$O2cq!E!$r zwt#un;t`{lf(7QI*t5{rhktmP+`E`Oz;i!8j~I<;FSveLc$d0dGW7%IV5+rVgBL=D zam5|0MV0n<300r3O}%^F^1KPNOpXScFZcdCAG6}<&#HAEzvDN7W&9c znZ)i0uyOz+9h{EPoW;32^ybdPH?q#)8frv3ejExNY1|dW$Blg)!Ea$p^F7SY(0cj# zdO!~k-5i@J6GZHVUz|ylm|w9;P^3ZCxS-gqGU=-ff1ZEoosm||N%xtAKpBO&0Iv-8 z()%gdN_%t;^Ws>u-eC~KPA&A&BWJe&_SZyifybruh!(Iip&z)^@TG&YGllqL0(i{B zMWv(b=jk$AS8?3BsXEmRkkJzg4RpZcCzxr0(i3Mql7^0NS8CeP)047O&y|9#$Z@#O?7-^(6#5Nl~6&g^Rk=X;zD^9dD_ z6q=Y)d1?mEAdzE74*q?3yZ#UBL#hUj@SC$u#(K7lFDNbGc-j+<{}^@^9G8HQT|*yK z{ky6htxq%*&wY3rAO^|#boTgTXPLsLuApxd=%<3X@lV2kGm$K(Q1}gTVt6~TJ30m4< z3jz*%2tmPb(X|nw&Ih|BufYC~JWo-wQGn?O4B}FQ^v~DW;Q;{)BE9vM1>8}NimpfQ z1K9*q@k(qpDde51O1NTFYR8FB^pO{+Mjr1B+#P zg~xA+h2H~YL<-%HGn%d$GoZqPW80Fvy7Dmc#(V9}e6i46aC4B(nkbw?#U6!Q@tKT< zrK-~kh_|9`z0_RhUC!77~<1Z{SMIDga)U(C`3 z_7J_lKPFK1$>b&lkhBNN`6M8w>xrs}`EJYU5QaqqG@%JfKOXvYgaz(!jy$(_LVtIS zHZt6~ngr?^5-vNaUbgIVR0Q6O@}X44GZhWGoM;%HH8o|O3!yX07F|ATKBVgdo>Z=Y zd}Q^Qc=4rJbk63mzmC~0nS}r3NsP6we*SkEc}=xLWRb@{1!;yws-a6V z#kfB703Q1#GE28oKB6(pDM15x^pfWZFil<^kvbr_NOeL&ZP2-6A-_~Fr@t}5>?M4~ zw(ow1?x2uietAhp=@4%g-0%1)fPbFO<{gsH|YW?Vs%jG2g&8uu(i z9-jSL`YqGN0~{&r5h{fd*}PBRGm_?5CZDyfcKL%PjE zHbGA+kSEubP(T;tH)ir0)mNH7AkyjMRX1Uve;swbcmyAb+FHqtO0)Cj)>xCw8effG z;)l{jh=6v=R9>x&)-{`gLW zvm2u@SfWm>CtywEQQnyaGKeQ{2J(|$L{J~*6}`YPXWe=7qvi3Ghb~qmxwZj zmrRpGi(kWJX?pU;YZ9Rsk*rEwtMLsr%iSy55j0O*yx3Vx=-q25d$!=Pij-`!@mH6_ zgU<{kycE6@z-wNF&BeOHMkO=PjE>H@a@NYmsTls!B`Y&h9^UFsV{~OHjK`vnP4|LU zP&md?30Sm_n=2RZf4DuX*cvOj75i5_sy!zx3&2X9&O%c+hpE)RtA*+1uL(oV#6#;@ z!Y8-iM9+uvE1ICd+)UFi+m5_3nKnHRuQQd9os*ru|;7E>a2J%AUtkJ%$QK2E$hycrS6+U`tiKCb z@7=c5qPD^Z)Z4oVwM!`+nM{?SRzXZ5<)Gm*_85hON28mhYxG@Qn6kt{kJ$mxDFVmEs=aRO>%@eSyX@O*>4L)$FDI zh{I;nu(MP^+jqCOjd9xgq*_`@rYW=hco&E3l&h4`!a?o#Y~Nf#k0uxg@+M%JE@VNokavVN*wf8YQ^Jgnn$G+e()R^Dr`{O6Q#}ikW5Onc%6g0Ac zD7sAP^4aNRBT*n=DDLmHSznIZ=e4kj8!dqY(6#&@q!%w)#d|bh2srfI=P$&upQd)F z`>7)f_%gh%{1tf+gPR~sexjf>MyYr?{IE^u2m+zyT35pyo3q+4=J(mLY6r42$fm$Z zia?M>fG{mmVc$so+ks*d{#+f7@xu*jQ>n`bUDfFz4Vhf05c_xkeyRBJQby<|O7W@Y zF!K58c@C%8f7zdX@OwMnQ;Bv&bq-Mgj7y6IMv=CIR zsYPR|+Z*q;*1B<1=al0Q(QoRk=?~SZCcR`EVkv%d?E*!=Ukg#-P$%pYh7pSVve&y3 zzaYWcqfr96$=TYiQT%%`3bSXd<9e6Zj87NGZ1pBMl-0R99MQ=6t0f6WXQ!`$>|Hp6 zKG~evy9HaRL=x>VfZm;iuz^FH~Z0Q9>^NP5B3+g=ttqB=qXlE=u?K!q}qz4?E zIh-Ucpe^chL4F*BwisdOH_U?j+z+V^ke*uX+xEA7`8-ryl%K?srO8KL%stOqZK+l- z7%~~}Mq_yMw%&6rcR}gT_MkC&mFi1RBo8F^(JAowprLoZ%Q)15$hV)y&&t?m=tV|ry?(udPL3G_s^9IWdk=cUDF zHTcoWcNu4YV$QdUrGA1ly8yb0+=4)%t;7OoKFVx&x(l{eualClD~BdlzgcBW&;hGC zh8-ftKxC(BaG1&=0={@CEtfePYvXp$g0v#6kQ-s)ZVZlf5m%mK)A_W33pBTjSuNz@ z^yk018wuEpp6<_;O0!y6(KjvRH1}T?k#RB+f%1X7Krxg2M5}YN#@{!5BCdtiwr+za zRFD>WLfpHa2J`qa9grN;B&nh0InpbEf^vXqECe??*C=+|ONB+PRC~UBsy5oZ=$yhu zFEdxE776!$p>BuOuqd0Aw^38JF9!X6N$CPf=5zX84+nKm+ej)Z|D9cb#-GmaY1KL& z?ZI54i@3dm!)hEa$AyzRr^Lku#MT~e zlgiKnkAT{_V-d(V!-3-xC8nc=TsO}EW}92%cdyRZQ@6e%Fo}qRnpTQ&r$8>Z##bOI z@g}dsxkey-|Qf|5!> zX@^R&t-rjR)zrTU7|2|zExDUe;Om5xh{$dmSradX?XqfT z<@i3=Uw$^l>UVNhOP};^A@5#yVIt@zUH3O!dK$R&avoxQzn&;)*Xg((98YWS3*>2P zqE7r`WC5F&>5(jvYOu}rR4DQPa*ps@OXMphwLdRJB_=6znr2twB*^yOFUIB5ELh2O z6n&U9FN#U{=-t44q~Kq=d19o#8&N%<)T3w)y#J<;vq-sT(93MXg2+Y>&ow)h;uRm~ znjpBrs($!k{5aQCfajVaNwlEHDKjHn_H+c##>cs49DD>!7FoteFYqK(;fV4*fv?x2 zT=PMD65Y=#j|#y->2Qzgh&ZwNIM|VD(SQW|;jmv<+w2`3rnwzhc^J8Qd39A8N72txe z`sOrMvFNixj|x}R4X-Q-W-rKk@I<|v%(TJG|MPQoJ?HwX;$%OJ00dd~{<+@NSp%%S zPYY3Q_5x!}iQ#DB?aj2*VDXA#qY&aCU)itTK=GnkO$VN)uYEhv%GY+x;00FAPzFBR zLwFcOR5v8Jl&N`V+*9z$wK%oTNwIud6JIm3!6~*d%};YDjKOLwvvTjV6+L`JIc8#A zq<8Z0Rr7XAs)A2+%<$IOBVY`g#T+n|MKub`8~Yx$Rupd*chxcun|%}Gy!+Ld$@#h9 ziIzE;DztYRv41GtiLfloj{vd!x@fj&<3M^wA_6{kpnn+7COe|Ev;;8Fu2>Tp{|UYV z{&o>W{Y7ZM=+XKpEIL+W}go0t@$=p@X*fD)(B>dd_y==_5n-^YWX4mWlKL-70EXwF zFlo2beK17bAfW}dE=GL0sAj(C^q1I~oxWe*00Z2X)#0{$n_JclH`Xh~uOA`9E%XPt z@&h&|wT<0-CP1s{U3cL|)I+*7FTXX_7vMvYVbBk3evyuOjo?0-8)rX> z+dYl}Ww>sa@XQp~6kIF=-x6}|MW-O#Z;E0C3_jiKS0cYf+4?#dYvol*6K! zm&3??t0e@u8(l~g0)96(3RV@2>=#&(xl^gSV3s@Mey=Dx1veVydC$K)5?|DA(SO)g zJMiSBVp!v$=2QdvU?kX}PKst=&|IlAV+#s;?( z+1XT?ND<4nQ<9R9-q+Si*UwA$gqssoI-|=&Wcyn5fEKA`#u<$T&YG!feCFalB`K5I z=5qUc8dXYgwN@U~GEV9@gF6PmlLE-_WU^vx&8cWzzOwS~n~8jB&DpJd!f9A8iLbN2 zfci-S!$q@*K#5ItF?mP^k|V!&SJK!{e%J2yjRKk0&$ZZ*iu_a2MyPWseNy0g#MNwG za&-tx`h$o12{(?Ckcavq%ab-pZ+E(;#j1wD+aIF1JbD#!IEK^e1sYJxH~ea=FTQ3| zH@@CoSZD9ADi}LtTz{ID4ivACYWyKOi=dAjRY8_z6y_;q4W=3v)v2+9Z+z2_#F&Q$ zuN9%VyLh>75$&!3YH;8}i3AFKx+ug=U2S^Ca#8#5>y$AtKpthM9cXV-Ve2A z&8iN*gOVj;JpvBs7+8*6;LgOt1{bPbS(%lh0PlTK-NM9ypPB{l4Yh44nV{uNMB0jg z6dY6ygUAHI%l9PPBK6~eU5Pnpe~Ag-ma*;325@^%COpcTw;#Y=)&`>RpN){ix5_!3 zI)*FYKL{7~!Q(DYr|>h~BR7o~2hrns{Az!d4(|K>J&Oq**D5_)=N{Mpu&CfcVzopo zN#RjUf`ftbC>%Z71An`~75tCu1phA&(828l`%yuo{Rlq}Le&b?iFjQ91e(5iTyzMH zg=2FxS)}whgpI)*o<0(p(;u!~ScRGn?IU^M5R(5F!v8|}e+!{q8KjriL#{s}_ga;I`{)s}3F4VOC0Qhew5#V^6Mt>=P%=q{p%6#toef*D! ztK37y{mOHC_uoz;{&jGnyzTWr4^bw;fpO%c`G0`)!?6s{-D%i8|C`ww$BS|!=a$W> z!=++z{6cB7VKzTI<(ij#ZNO)qZ$7nG)_pf;(-S9mM-GkBPJeQ3AP*0^4g`f$L$~Sl z#O`PwcXj*oxkrw5K$A>biO4zr#-Z`Dxv860w|+gtvx5A|==PPm?>=B0$HuGKgj+1K zoH>4^Gs46Zf}jotjp8qU6AJZ$!R4pNmhBGXTdJm)oup!S$FYH@UzTseKcZ1<58n4ey!B!?91aMes>OOpR8`|_8F76zeP{nJ=8!$8f~a5gUy z;`~~E!~Kn;=Nt?z~R9lCn3kL6}Mx4d_X3hw6HZs!Bx z7<{WA2JV)+LxfQ6@0agym!VmKVhlU4s9me5>8j|os(KIx+fx~tt=rrqI1RDR2NFjr@FMO{rv6Ksehcmxc z$A1Bve1V@tUf@CXU{`J{4~JE}33Uy)#h|2oX#0X&0x@kfZ-E|;XWjjY7Fa@KSA1{l zNLnJL5gLx|YN*$YUsnlhxn4Z%Nx3t~-zxe^Y7kdQ4b=8ikh5hxGx?O;S#{DC88@)@E!qyCgr-lK=LApNB7`<^XN!`H zB4XSy@ZqqoXrSr!+_ZD!CdnC*EzeV;hN#rj1m9;v>4b@PCVxTRYoCT2a1?Bt>C4!= zC4QPVTxwX0f$WTNKc>ua>wt^cpCD)uhd&$7WMGM4V>T$_B%Vo&>p{*k0ed>W002L?UqUIkOM=E5jB2Xu0^_J zVJ_bucq6loseO=c`sUevt%vz#`FBAUB#q2D;&uZd9^nlR2EIH}W^Y6a3WRN@RJ?9^ zrvwu%~#J zmWRT0pzfHt&|x_t&=rO&qDJT84;OaoGi0`pzn&A9vHZ0Mmf+S;Q|XI1Ss->+H2nU+ zopmEkDS?&>)hswjRyyv=O2*4dY3kVrvS&H3XaCygovt<#*J^%q#no>(AC|!ZwB?Dusb~mntF&C=>BBW7C!cE7(zkvex#C2w63<5Q@k-8qgohhk zLFPNM`@QP+&iMepD_&6g>#5L3DNc)HPEpa@w)^Wg@8$OwCfkXO}UWXXKkC4eV4Fnw(qGeb-iOQ#nHzG>^3U^PhqD)0~yVIlW*F%%hK;vrHkMEyw9P4%VyJR zDEaf6UWc%#XE8nuz^>;X(^k8u9IZY*Q3%&-yP7P#B5htl=E%V0csCk(ckXh3-U#1F zV|mJcWv4?@P5tFYW(Pdrd%eIjJ*w-OUVXw@wr_(`+AOC0<)`L4L)JgF$IQ;KjWzF_ zUu*5u>q1=?YDQ1PMylX>YbUn&?QYxMt~Axv2&&joP}?8nwm*Lg#9u7y?G!tY{{S2h zxZ>qu;UK-U;KtvDL~$-6wgE9I8DAtm%h7$-z&!6nYH>QLXZrs3YKhRr;sE9?V;K3d7Co|jlPdVJQ+yA{3w>vr-cpmw72;PvU1lWkiiy+U z$bnLmGce%9zZEW7Ckl2s68Ew`qEJ+}IvA zp^p1*B={ik{+f!k7zHorYR^{uIzrult&8gJNM8JEw8DRr#dk(8_&g31L?_L@ z(hTbay4GEzIr85#1RI+5%er=ihJ7L8H(lay%M%2eW22+ZMNGZU@dTX0dBp?qSsCei zKv_2%%dCXq_ffVYbb(cuC8q)|3)`1D;F;p7b>A+)@d~QA&*(SV z2S)PNr)vC-UYZtoHcc#n{4xTquF!?^=(%Z(dgVdDzVS-@I=O(e)z?baBLvcOJFm5y zbBTyoqsIAOEamre+A2*X1y69*>QS4zMX@|jc5HGNTdgK-y(v~2%wGEK8Z8e5umiI! zIsu#FQ1VtlK=Yn%MhqmDUn=l4r=?|$xZ>;nDrVJ=*!P#5zwls(_jiZO$1&cV1%fQU zAp4xfVbJ}zeynFPZHt-p!O!JCgSH;xd3D(J4OBeq{vG1+{RzkYiSMxA(l66HH-h@! z^BL6!dNmR&B6$BN=glt)W}9D;ni7irfZM?SOizLcLAV4pqjQTu8*B*fx%~|41bN)# zq+?gJJKv-FV)7O%R0{sI-HeROff3tGIFU;O)16l2(2H}Nz7mvCvJpL}iWqTf+|hSy zE|-;Dt;xPULSi<|=R-+Ew-h$A|3j3HaTVwC!(iL0Z(Cas>9&*OrZejvmNg#@>u-NW zsFumum)mOVCR0Jvbs2Ys?s{DrCR#eIE!iR17I6D+tG7Fnbp2~r^YUf%vd=^g<=I$D zYvR;WqUcNiE#wR;m4PTrJ3aq1)(qcXfkrcg$$<~&4~(wRT7%O7#FzBTsO`aOk1hi5 zFH%?y2=ZNGb!t9U@o;ag7JiTCCy#UYc-=#loYq`>bXE~~%aa8g6o-MtxuTy4Scx-- zzxvoXZ<);l*?oNhOa^UOlT&0KKFBo58eh4Y^bAzZhSd9xy9pzv5<~;^?P1 z(m4byY;bD0o_#-N1PeW^4x;Q(m!USSj>eAu`R$tHZjIw^*|=Re2q>kj&wfl9-JUPM z-Vvih!sO_<<3Ddqt$N)aIP1|BsLV71W2{53GsXM(e)f_eV&T;ul31J=Cf8jg2-eLJ zz*RdaF(eZCW!kw{0i}sA`0_X}tokX5T2(fN8t^xLv#t2KrFf4|xO&u4U}UHI-G(|h zzWW`hE=bV3PE>|NzSMqWrbpvGgu|akL~lG-OsA)jPevF=l;S3kn(c`N%6+i-<5PxDy3rt?QIuZJp5|_elSt?83h& z9=X=PI>tUlqs>B3@m4ts3b6|G5EJv|rObqCcesl2biNgk-|=IlHg5GP=u#n~J<8ne z71`p7ep-W$%;f???(i4Pwyp~66FP0XZfeT`a6cR4Lihh_oEf8QS4sAPpOH?EGp2*?5oZ^W9@nA+#<;{^IDUJBoIl?g+EGP`3m>r+Bb7%*B$@n z&+_@g&ck^5u@sH_=M=V!9q;QIau(|<+&B2h&X?7Y$`3xxU#QQEU%U{paJ>{*wyjtz zphFcFW+IWgu^K2Ubziq)Nb3dbYi+pu!qct%p)VqVFEPlmF>d>1+Ku`mz{^)<%bfsw z`RP4o$mJ+s+^qjFQU&T)@U6q4=fADmzr@U?G z6^$94c~`?D|B_2TO@x1czd6oMMX?TX?Wrz)l<{h&U!%-GE=Hnz5HB7TkD4aEr3^o9}lj?i{M0l`)Os?6YF1J^Kh2 z|6ZogYFlG&Cci;fX`m#&imu*HJ{a#4WouL966^bUM$<|-^>=1esu6yVzuEc+-!yV3 zvLJ&}uJ@JVRc0NC{8R=&b53x$>G2U^G@Al2ewotG-n@t`P1NzA*<7;YLw_csjTu1@ zt`{asShxnxV4sGyrVUCi|L8ptlKdx8aK9XS8#siED>RzYD^N;hj(?Xr-^R#wBw3R$ z#5}5Gb}MDb@v42v8I|pvDqXQBOQ=Si{Is3dHHP@S{dMNVs8Av?BKe&^;n??P=jG*N zs?hdso^e!7CIE=R#(4^>qk(1@H;IygB6j>WxXpT;vDb9ONciQm?b*mq zazlpoXP7$Yc4LI6rQd2mPC4)0P!f(&(W7!0OR z`@S|~b&#`m*^Z4fxH4tHEU>p15|unyIe2Z3X7Mq zSeR=_oWlTU5fK$#0ll8*Fi5W%(4;hI1?D!tn^kZVGLvI(^PWm!+yALpCZieRIe-;Q z5YtPB2+mqq-{r@jx!~my8S`*J5>JTjv0whefw?*jPanl+X|jB-tOKnD@XUv2te^CX z2|IdVEBE%a_pKXTCh_^rEVB-RQ={^>L|=N+FpZ0n@$RWG1z=@B@t%_Ihe^-*qw8#O zOdZmUH0_JZl%GAx!`CdeK}y&}f=%X8$S$OKA)9FEwWX zt_zQ{n@h-xTP1Lv61cgFzX$zjugFCi^mCuV;Qx9B0~xSxNp=#MaB{XCyiGt+#LplT z%6Ucc!?yMVv&0IVj`@&RQ)CD6ej}xR^)`Szcg42)H(%m4% zCQd1i0qZ7QuQme665b^MqZdWdW^zJ(i?D7!9%G1|xMLtyG~aH$*xGg+BbcD&>5%l- zSEGx2cJd;^0BLx(OoIlFRqG*$B#}CT7PJe_)vFZxkYdI06v~TUDN8*op?#yUm*3q2*PL%FhD`w2vN}Mf{ zCBONNx$v_T>T-S?LPoLV_QVkL&u7myvvNWd&_onseSXqyOa9>=hha?zi1BCWeu+;z zduDdrvQoa$_H5W;k&&-S^b<1Lf#k@mFBw+tdj01}2Xty=qZetS zz)h)wgg2}DV9IRu^FF6o-SUW(C(@!ZVQw8R9 z->C-RZ{6b@*DQ!;hHSl8GmBpg7UK{*xY6@Wv=FkTk#7JI)#?rG@iSQt4Z3(h0F z2vgk+BwU?pKSC;WF}!RAe<-$Dwjf~tc*B1rs`McuRet|_Txs&F`jXTs{6Ph7Bu)Ld z-QsxTnPBUsIjM(0olKX!&YMp|BOb6n9T5FOnmI;PP=#Ao@~iPz%V$5kd(qo_#m>KH z&}@WK|9G1{8-kzCmSS%&Ocs9CX&>kRk!o>)p9H-j5YEb98B5<8fI{|3G*XpUq_-KJf?HB)RRJ2n@{^w#AFQst<%30= zRrlFFm4C0lk1*`6^CRL=zZm=mav&ykpvJp=F{XK8`24k9#wU`uTb4ATtNE64a%O&R zHG+Q`ti1vSARoF`*qZ|R9PD??xs>@{{)_DTQ3OWyBZA zvUh(~oSp*NXse4UbhF!7sA_vpt)?PlKzvrlAOJ?gGuHaO68=b&sah-K?0@nc`!exm zgYwQ-?C2z$AA%#zKUwy)T}HNr_tcrD;R_yijQ@Cc(ZI(UzC^*4^L*mC!4j!uP75;?LIn;-ON}J`*82-e~c0d8S z)e5D~;$>4ee>-(TO zJ+>TYJ#%sL3kppO$)UAT!tnmnL=DDE6jyYTx$y_5JQ_E6;)7s!q(J9~g|;rz!sj%; zl5CZ^dGz#D?2iW1gkg3E1Z^n!SEf6fdfnZz(KqofY*iocA@%SB+7U4j?z!~pijbt? zh}aX0*SA+4O1A2B@~m7IVUn>2ABw+MUs!!IMXQD-ly{gZc&}5c^NO3!*~7xQ)Iur2 z>b=iw=+NW?}wfxdCg1SeCMMSVg*t%pc=`Qj_iH+L{IG*6A*NYI=pN`*Sj#j*r+>&w@;$oO%*7Mj9` zt@qolgE!k}gd*k7_YW6%MXUA_gvi=>f0B_O79NK~hE->E@$y#<(4tt|qGS&At3|FU zwtfpAq(&xC-7GE?g*C}KRzQ}2_*SpS_Bes`s&+lERX~*R{M0LU*R z=pscxVMWnJ1#xoDNSPm%u$<3;=?^yloE zCAUQ|rA$bW4tgvFw1+BV;{$U|!7)FHTW*Oa(?X;b?ubpTR6%6{C)d@nshm*0*+QM* z#S!O9%;_^@ecH$or^Yy>KgeF-5kQSjE~fKRWp{t^=Sd9Y?-wKt^F;!KhUz0Bb6;t>{Vn`ArGij<% zn!*4my!$)9mX}(o*?E{UmdZh;Ax4A-wt3Su~( z&$b0hhx5Pxa6#k^IV@{jkBN`pY?!?`Y}*)98?;8dy}cG-B;25)vt&u}T*I@z@2gTa zz}#DI;QndQ7?0V@ZX)+d?b#Ri%fmJggYXfyO}vgO{TRrhej?7eyicB+UiRkUzlwA4 zERMy6pY6^vu^P2g9_N{DU=^SwrKMP#ge^+NH!Y#FaE+;Tk=hJ5#;gJD(7Q^j!e2V9 zJI5L@QsteT#tNunW7$D15&XFC=~feQO0PhwoR*ddKw0OK7^cJhu{gKFDmeO3;De`N zDzERzmD9G~{^BGKB~GJyfyzHKy@gJ^ms~XrX^$k0cXnoff4Zafh1$Zw(z9O!i?^wx z&d4m(njjl(n-CF`KD$E2KOpxSF}ctkAFkt-hYR+V#+Ae`F@1zGY^9KoDgxIMRTB4rDKS-n(8I z=y0gZDK59u1N7t1Y1sq`{y|g2J&ArpcfxR=Tfk|v2HO*S+Jpp{BB=p8Z^$Tm6a9LYrZpfi*?{$@g*@@oTmk`Q)VZcO-X$ z?ZPkN2Udxme>yYK&+BoQTzUacQ(Jo91?`5aCXkjO)P=H(ws%}xgLzI->*+yrZbu06 zyQAl*{N*dx@tdZbBnwZ;^+E+%1iaMt0zHKyJU+hI6Y`lo!J`q_O#2=D?Cslkp?1x_ z9#&RG;Q4-(fPXpThga`g1&{(qEmakaOnwnwSLSX1W<74aoFYg zXf%z~&Qn4QI!jFc6)@%n>s!tQkkB5=8ikpI*`938N|*dbWmw-6+5FgvMQjD#)(tg9 z@{bOG6}p62uU%NX`EO)JcCw)NDR1&ZfK=aQl3tl^C3Ff{J1+TDHc{^r*kEMHM(_G# zebv*nLNrqF3Caix)pK}v_Q$UIb>nd3iGRPOL9;_hqadnpAi45Z`0H=Ov?8hcqcESb zJt3L~hqUnYW}JmZ9$qP+^>*Mz?yB>n#|Iv;3Hm$=@afy?RM| zRwQpcZe9@ViIM4l18dg&iDPudR+@8a;QW>V;doFJ%>XcI-J zzw~qOhxHgII_^#lZ=yK97nbRVT=pBdeP|%k_TOkQ8rlF zHimF zZ`n}S(rk?;cyMI36y0|Mut?MZ&PphsM_hY4S~L%naNBDz|3ibb@#A+W@}l z1DohInA-3Xu65AcA+$RMn7Hua_Za_L(+#>y8vC%(87ve1o|N5?DG9{*)XvXnZ&~#R z>%{~cwI#a>fsc~u9IYaWBb=LX;4@)>X#^cafXEszD5aQ>CGJ1>3|b%zUxrv(>t}j& zSP-D1zvGd~dTJ?BFV9Jb>G8m%2`Sy0?uSdAQN9j2rP~1Pnug~~ct@vn)~)cQQ{d7{ z70ThsV`X+JI8*wMKI011)4f7+5XZ1_!z>t?LbmJYw&OFzC#Yf;$L%Zc9xf;uvo&WC+s zJC}A+U8^4XP?|!^BC8j=IdkJ0AYUms1G=I`Bof{S$Pn^zGrQ=hN)vTBm1%cfZTH64 zVmzM2%H^bLquYh}(!(O{w?=V7b7Z42^O?>GsUoCat>?7XJZ8!6GrLcvkvq5@9t{PC z)={mg_6=bex-5*$O4n;t_a4U2(QA9q9@q>zx%}HLRSRs9T=Nxb(d*1p1;Q5$u0(mF zNB@qPFKS+O!cg{0STI(_F65?iZ9$ok=;>#GP{8?S%l zhv4R9`r_5YwU@pM%asWCoKQ(?6=Wo1lJuTP4&xaFc8>aEhrKL7bv#!5`cbA0y|JPi zE$fI(L-jXKACPF&`$gR7%PRO^q;UjQq8<10Q6w)wH7EBp`+9PSR(@2ldIAcz!;cGE z0EN*xMi$Nm|o$j7bXyguPU( zYa9?q-55xeuD7O5CgVfIkTA}_v=844Dx&og$$z9I2(@2Ms7WUMTEQ0{1m2;&L5NUSUW=IZZq1pO2fq?N?4oR5}3Q{#+@$$3NV6 zWLLhYsrspM0J5Kvkfs4>^b4Q3xs$U^-Et3eM1T5nKRr0O+UvR!6(bZg>a`#?d&sG_ zTNLHI9#BtQCr_@H{nTkW(zxpP_^PS|FcC`@ZWu;84bcYA1;z@udjnH#F^&5Q=T+T! z+cUpxuIbomo;HxBd1CrhLxf4yu?6M;P$uV@4Sf!oRu2^mW5^aCHgAI*1w(Ab0WCTl(PDJ*XmsQO?0Q zJ)9cpkPk5_fS1PV;Z8Kg^&gkUwzz8-ZbGM-mz>H3bp;7)a`74(_&mApuxl>?mmXb; zt?1$=#exA27g3!BFwoVLU@rNcB?+nEKHbtVq4cmUu!Eup8Jf)anX$T-H|T+M+_08P z@gOKl3^_UqT6Rq?%Xru*AGx)1F~fl#TfnKgEu}uu+|*f(QlLtUJC4eP7`Uc*W?mQX z%FOToDj*xz55{CO1fJ^!#trFxx;(elc99dG1>MIG%7+ZC!}`BSL9m-1b6rHZ_wv0L zlVGqZ#|iHKw`cTf^28KZRA9E=2aMF4*h-Hn6ycdI%+1*U<(wAK45TbTXP7Lb5rk`{_$o8KVz|5xMpx@2HFS4>U*D3t-j@U;#;5wE5Tz}FFTp}tls+n-D+4WUVU8m=_Orlq&vcHFWS zpKh|n43pq4q>c}7r+nnGOt^~!m*rV`J+;_@ly8BiF`R|F9vdV9wiVi=r>AJ6QcJRFL&-JQDXK};eTn<^F; zqH<8h>`C>*tH>n^z(U3Co-0aEHoU&@rr`!cq|1z4|uTw!ZF2!mP&5I zf!e56hOt8*{s!ISwvB{zlYeED+qiayN4oXU^#F;I!!1ug*;H#4L+gg(-~@Z9HH5>i zaa8ZsA5L&TZ4Q2FbzhLku1-(5B|5C%I6e}kn>v`(x!HEPj!5}b3KQb7J_th+QscVB{f4VzQKg*@G1PY_oF-6mNRPd zl*A9V68N?6?`>Z4c$%VEEZpv%f?M=sW@Y9_Jf(nBJy+SyD~kg&+kNt~k&)CmD)v%z zqa$XkOk{Lm#Mco_lC@qKjL1L={mekFfX1&~oN~u35Vg>uDymC)dy*v3mz+B|&5l=G z*(JNSe+LW*wGyM;fdtu^gXb+bQ^&`iRO!a41fH8+W#`A^Ddg3-8ZJ28z8>Ramj`2X z14QjsD`DO&O%8B2pz&gNIf}nqEATM!t?b`GbTq?tCYp*Qa@2n$;TV!|rI6 zJGcZQKT;kkT@&jc4wo}Y5q(;dy_&LyeC#A*@-E@oW*Twt$>g8yrMAWEszbAz6ZN} z@Nh71iZ*s+PXe*4<9QQ-IGY)}031j<@u6BY86J(WEwDdXPuIU$RtHh! zo%BC=)jYVYToHOkIIN59>5rgma6;sl=1W+tFXh6YlCjip7sz`9`~vY(%0iLKa*yr= ze{ZQ{r(XflmemaMjdCv6jb;|$SCwf%b?b%qe}FmPKdZ5D=iV7kgQB?B^YPdH2AZ*$ z>YHQ8BE`c{w^{supir`B8Z@w`h#6Z~RNt6OM>XHVIPnVy{GBB`Jy0@^EuCv2?v9S9giORS>l zD0}>IoZoa2V*9z)XlXa3px@z|?g549mUfW>KEcdNUI#Oj&%<#hjgcNhMom+oQ4q_d zEG8~bsU)Ee#wD_Lqg0)`x^Kiu$}_E`^){VqyJsJcrh%LcUX#U4pt$@L3PE56(T5ky zs@QoDFTWe~BeOU<{WTF#+bp4U&DYI*hlTlGnh%!f6W41jEmzc~HBA#1*)~^G{9@kC z>Jm)c>%J$!YgxyH{JL}P>g-C~6xm5XYk>P?r}19An?ae-_ODD$(^y%>DG`f$tw-~;bU6Mv zp+7WC#M9!-ym=>1JCK)0zfaAJ8hYtXimhCM*Xw*^Q+ANIN~oBsN=UUE081;~Riq=~U@kVAFWD02I#@oKgY zRFsaqOf)m`amMVxq1**23x48cmD#gL9`nH4TM;YHz&ptdu<~Lv&m=WQL;RT-S=>|? zW}e-pWGzEdIq%Suv+|mXPNILjf%`%XwJkN=yVgU&BTMfy%B6{vnfT(Vt7&6N14lN_ zLrRqUywg9dBdCz(%tOZcFR5XIBiq(e%1G+H9k5b&v!Sdov24PB`2^n=r6;2g;R&Zd z4a!+C)&QrDrIv}ONIQ!{vvf?tAiBKDn37;5Homek2H&bLV3=R{HP&ZkS#2s@>&W>z z7m5W8jfQ7F%3*(mcU&^Skh+lv+!O+dI>|e(MJfkTopUrqxVG5vPkKKpc27=A)hUeE zAzlcr4;}t3Z`ccWu8!a9c3*`F-Sj3$5`0s?Sp7hHNMOZZZX&UPM8&khG#z`D6|}d> zvMB)&Y6y&)r`pfJ&l-}+J2(5RoY2~rJQz>~Bp3=3-$;Q)TUL1Ebo@V47ZK^%$=y#0 zC3F?MAv~ZXncL(8r-c;}QX+*y*n4n3A)3#%b6Lb(jXoI71UhUbidAeMy6)Cz>HGH} zqc1JUA%0WLWBOFr)<6lrrvej57)WAR$;W{5IRzg+JWBN|vyS%*Qd8?Rbhhm|nW_ly z=TG|b+Yp6(?(p803|NPF&*5`e_%40jvfJQ);ZqsG7&Vy!xP-(CK0{+na>@XIQO7?; z0oQ{~c&c2g@qfmcYS$GGqsC@(YoJ_yp41h1(8>mA!#6Okb?f2u$w^FuCY&lomoW-{ z34LOQPlGt}55t4T#xc{D{8QJYvIsg9VVRux%{`9L=9dkd7jQ~tx-+5TMy#%J^Kzx} zX*OaT(-xpE+&D|cIb^uU#s9lcYiMdEgYU^^3%{%5H&GemgO0={d@`FDe`>QDP+m@k z^9`AL1-L54Yg@`QO`MrCBnESXf5mHJT!n&0w5hn3nESA3M*e5&_2c^teOtgdD1<&@;xZ z{G0R(q#Cp{Ok7=iY_wEH1>@h?#NsLju~?|r=Ni5FC&4fodJillf$ zMT~&JKdCGhxjR0goo4-BO z3mMLN$10ncTOMwT!5w4y^L5CTKzDNg?x zB{DL3NL=qTb{7zw*>4!O7HRyOJ~T`wHH8$@t-V|zNk(Ags8H-EWO)nQ5_pR-PHQTblxB{ za6>9`v;%-XBv*^TQyESS1zp6}8P2szXsn^0uQ6_pv|wUH;eE(}DRFP}y$wpmT*9|Z zA#aA0DRVSF#3FNJa;m$mj@VEgY8HjGQDo8}gwG9vY^6}YI4{$U`u3Vk!tKsl@l3bN zYrs+edG9|^)u8&J>wO3^Osaq7H|>cJsL>ZUd7W~})E-Uqj0HBZ*1D@U=t z5ljbS&fj*IhPqz|p^gOK`-LrH*ap2F4x8^J1x>x7b*t+4!jZ+HjH@8V?;0Dt41*6X zLa}`OxC72Y+fP-q3gBX7a7i8&rI_fj_)jJprOnqh2We*9hd?ru3Nbep&VLZ5poYn| zr3#x(JdLmMip`s5EKQQyvdF5PUM{_g9?25i+)z(P$xc08ZMZ8?Rk zLvPD5iq=%Vnl&5M1xO-#xCtPuv9qqU_98!q+n(-#qJ9S7yJ7!x2|@;KJ;VPmPH&W9 z7Q5cLJ=pFF|MJ5QWmj{quvdGKsAT!{bsvmdrqJ-qI5%#(Y@pE|1}L-%I+d>gC-yU4 ziq}jKZLWFqJjM8I-@v%IUVTC%FAtU*yp?jVEr1neR)}$}e848jFc3T#Fh3FDr!BB{ zz>rxs*nId?UpxdgARSyU45AGj8eE-zrtFLj2Y&vP+94F?aAtCaO%Eb(M}=k95yR4& zJwzSBInv6NLok6YJKQU0#^R#>vPfXSKI=c{2ANZ)d3m}u$|dO}rklx6&STB89ALDmZ#8Hh8XCijIxSo>W%N&^PtIu zvJ_nAPXh3B(9e5!p=|Qdv{^(@Lpf_Tp9x?tC_O_oboI~(&9X(J=jYUgp3$?&x}=#f3gy*F<;dpnQN{Jc7TD%zjEV=87tf)baEw?|(0 zHmBNOUa+{Vd%NKC*B;8GCx}#XsU0!r@bU1EM7;J|W)xN{$vCO|pKvAc@i>f(Z0(9? zb~}4R{l1@yMIr#!guGTu`%H`-o_b<~EMa2tX;9k3W07E>QnFk;rHzS`o%t<3$HKP% zwc@ME@A2!OHZo-Z`5ESlc*q2|bSz7lV4E7b#7HiT_38h>kENwakT^=rLic7-iu18$VEWWa_#pn zQ0cs>>elE@t$qFT+)$c{Jv1{D5)F2Z z2}ZeyO)gV>LXZ15JJ}7RVq1N-zTpG1Q&OLtQ7tFz1@gW+dd1ge(klB9Rs%;HQhd0t zy7!2rB`Z5aJKtz`YQ7QnZQ`)lQF*p~oKT#tHF3QOCV5TP@(+JuEMKNxEApB2OVdXR z*vZIIVJQ=*AGRGe;Tx{F?Ac~6&owCl7su0w%Ov8*=jB~z3z1mWK_0R}-((ze=joht z`@dPRx^Vs3!oI86)WP-0w4+?oQKkT!(hI8Px1@>^G0yXFEarcH#`_c$(5hKTO^G_7@3)+&3D`5iiVVmCD~a{V{qXaE;t;EImX zU~ie9cob8%uDhz%ct2);Hh;b|Dh!U&SY$IZ(lHC9Kh9%`Pf=kOJ|i5SF1fKefM&hQ8TPgv5!@=2J%dAYiU)bz9e1Bd?`}uGOTB zE8Q3GqW`;EH?<%2`DL^5h`Trpd{d-OF!FeNQ{KGb>r6qBpL9R}2G3%rmE&pfUE}LwI$@y=VV?BeyG{*+a z_T*j>ey`RCr8Afy4#wJWgm#nwb|NiHcej#?p5W%bW^dx2qgQ8lPPv9v>VNTft-V%F z0K`p9Nd5YBsU@efgH%Rl+}&lTho;=?oPa-77mm5l+o?w^pFN{jktaq@ktlS(q&}y& z1D6r>HI__A&Hz($lcB1>i?l4K7xN^Vg{Wh{o%1wBtSP`qHX^ol5S^8eRlWmiLj6@% z*3JMG-qt!c9=i+5el+wNEyaiXc!HPl}4=ELG{mu}XUy7WW-&x9mupI}N6ooj=ZfTl#ClKiME2(tlXdrldq4K6of^S*AKGWM!C> zfN0suYivs`MY^=>TIbP0am3*tK2PwU8)&!1CLxpy@ADBp{l6@x z#!bpd1mo8BPu&IIHU*r~hPx7RbkxK$5qrXp~yaJh!46kazFyA z{|?3W>EVqQ@TS~2=h!JV0ESi8&o%yXwb$*h#rqx}Fn7f451`5KlV69OadaNb+PaTx zo?2h?zJ~PFf}jF_N&PQ^xvbi_!Y__I>&hC$cXI_p+A;=&{_7D?B;Tk|ux-GmZ1^j= zeS!0GfUV-mO!|&X;YCqbnlM2}2)8?uvj~ode;ja2TK7qDo{b@LI5lS3=k<^7-w=)t zf5+<)+de!`WLo3@$>2XcF}K7pFYbuTSwd9TwEX3}9Vmerk$b1-X*FFKEXSY3~U4D5}6%hft9tgPU> zx%-~ks@)N6zn=cLfPm8D`-+D<<-HDJRRmz6Le24}E&xWE%no#rIu~(-&QaOjyHz#+Qa+QDtA=2S_b)?V z)vy$&CfB*BLo|=Ve{5sDT1t^=?cL$e*314sU&SbKkv;zZ`5c#@lTW6lMAQG4Ut{}t z(4*buV)p-j>4Oby7PQcEO#Q!g*;w9(W?zc2`d=?@_*?w*=*U*f+F#e3oXm&w4bSau z|G-eh6WbaX1@sZi`b6iAH`en<6WG?;VK$< z=fjHwvPwBgktrFExQU=~aebff&#<(eW`+gcu55j7GKqd*a8K{b{0AbZjp}`_+>&_$?%uP6-7nNpPhrkA%FrfJQIL3&UUhL#kx!2=0A6k+o{| z+Fi}9r^WgC`AOJ7aXsKv_6I6FK0dBCT5|QERlBG(mv~5%K(>?~D$)i2fajxAvVR}3 z?0v*vnsljyM`%J3 z$-hrr7Hf#8dc+#>R0PDCoSJ0B@D#w_KE6(I@E4=U*SOs`5xuQ>43ot5_;!L;AGK2UEU{fDM=ydx;1wYB6i1vu+ zO*_Ap2)vrR&>nFnJb`n&rj1aZZg#dSWzNXrt2EcAyh?tiFW)GAVv5MGH*R9jpokZC zKEeORRy6Pm}#>9e@Es2tE`-&3qv^%O9zXfO6SIa@VAb{H1?dk^*dLe$#I z*L1tzN2nHAa4;7klKDBCry>_+jFWI`-MldbM<%1QD|P7Tg1?8CMA;o;=F&8<1wS_Q z^%eZwPoIx%D2ftpbI;}WXr}$V&5|8AOpui{wT`;%#?dmLwqHN`;uP*zND`Su%)lSk zho$z5uFRk3kftSk4GsOFNSYEm;8ih%CsxiMCM^0ep&)lRmSONLt#l99ZL*4z@g#Qf zqg>H1iUZnQC=6$U$I>~GP()cEr_*AL0k@GV8^%nQj`C)qeKuyaGeQuf;H=+a%LJ zvoAW-B9D`CvZg09OD>=T{8UIAajIS4orC?|IduG~S#S&BBrwmbt+qXjQomSbK6_xv z;AQd^Ka6Yyys{j<4r5J=wju?tE+XjdOwOm$=-%;Y=9kSgzR0NCDk?DGsN97Vh4Uw|TiI@V56rgG2b(1MTzJPjs(V zD{#oOc@-1NcdFlwits_3@wwsfbsS9~f6rh~i_Klmhv}xXmt9W_)y%7IAv^-&C9sOD zC}C(HF80MVMxa>DQ!e0+z?ZY-g8eYw8#>mFzIKFUz3D>lx||I9L6(TiVeRa>KlRy` z^393)>iD&J?O+O@PZdE4zhWR}Dpu9w;DlYZA%Se}IZ-9OoO4%Qd#lTr8;{FfzjRo6 z%}oB4J07e9OvQ=90&VMJejfdAV-E)ju|j;EOf^gi?8e+y(`W#R&E3hu-xt8&39ELu ztKFrJL$+$~GfU7#h3>0Gm;0Z06pfGd+F!M-zAH(OIv!AuAh|^bJ%TfI-p(=rAhpKS zwCo|zh0sbV*r>3!F8O9o(;3aaBtBu5VC|e#R2S1O_s^1{cD>zIlR0!<1~Vwc4Nc~4 z<8jyw)Q@q8bwc7U;B7q)QS$D5k@uKQeA8v+eFu`Ss{*fc0`}os)R(C03PH(be^=Mj z8gO_bF{DB{oe(rt=aCk_?-5KoRLR!%J6LSyK$UQ)TC_u_M+UwbQW=K9u-mOG?X*^*TT-*BOr^F93YsZgejLusYs% z!>HKjDpL2QF17PCx!Q{yEVB$b6i+xl9BIo+>t-IJFJMB!t}5Y@L{Art!;4B z-K$t%-a{rxwei95TIF%k32vXRuoSjlcWr-O{k3!6(ZKog**RFh+gn`wuAzb9v9z_RTwbQJyo{ zc=d!ZZxOZ{oz*tMx(96q_=Nw$sSUX#f6hkEHDC?khhgszA-d{UFe$cAUY-R47L7 zIg~czAMAM;Tktmfd#1cHFflQ*+&WsW#mdagQp>E7xyZN}8(URqf|Z>dmGvUS_cLSs zVuPJtle;hV8EF##0oH*O(hag)l5C%^OND~7sg>wyI`nN_%WXQ4aDXG$W4_SNF8^ig zCg)-MZlgvYT(QbkFioAI?Wh3A|IixixxTk->w9WQ6xlS~IPOdIdL(hP1>^;CiI$r9 zp%vzmERq_d+%tCUgy3;5MxJ(`xBWrBfq-bDVmb+S?3VP1Ny@tquXhB>>~;A$41) zD%1RUp}rOdI);5CL?Ek837p7UGhc)s@j4PA;=UR{)5xaNYPsAa`pX%703MBiPQq{> z`~D#SZM$AbFBsjrt*d=Xf%K742Dr&RYT;>H3=_2RzVmYN&H6Dv64{vV6O-9yFF_PV z!c}dSP`Kb2LS*3+A(br}f-{?a-dn~j&iBEJBCu^4Gl7MwK8AKLg*O6^y+}_CSHm(Z zBJn>Str%;^-eUhgA~i(}4Gq~DWO0U*s@!plm8^^itlM#hC=i)XiJzZ@N zA1Mn(P=MKgyhg{1vULT_)lt$06y9j?PRI~pYjknb+)ruqI_P->Zv zL`H=8gC3vxM06WwD^!{n_I4d9+rsY`#>-@r+)LPBxqT0(-`1P1?@@y z6+JW{%ZqP(fv!G4DtUL<1VT#c7$+XXXC;9R>Gg!2$13p9{_9k3k;CTr2udbHmS z5;S~(`3z<+C@i^b-L8gsGXKQ~u8|+GHX(w-nu$wwgBWyv+R``rgimnh z5J?nw9VUCZeeDn1bMwIh5b4>7|9sw<^t_>p?HbyxUyKT|H}{5ojD2%?ahIKVcK{BX zbD0d0K+X0Rj3uwD=2&)tY|ht`tIA1BOLt-y8DU(cgRasDUyl>_P4D-xg5{=bAg9s6 zz8}|ptIOqmhR}mt5O|u2eUh>P`N?GrBiLVair4a5)OyG2$s2KrwWN?t*@J;9I)|nu zrkRh)>LL&du2AMNnup0DZpa8FKmT?AJnI%F<%<3DsiK6_MkzMZ2eQSGO#1k1k`+yg1eZ*;J7Os+okO99ICadb z0t&OOtb+9P&+!(&#I9h}?Np1k6AQ5wIS+epZipcO(AsZF9s5cA9p-$(m2ZYb&uO_I zwGcBt8r-S${ER}h&wJ0+{B_=+mG^e4?V8c$x*7Ew1Tzdic+S=-Ex`t*h8$lb*CD7x zobEc6gF~Xi)c$c&+LU5&O3UGVtaV}L@Qx-XRxaB8?eN!~xXJ5pLC34IYAFOF>RLvF z5Firc135dleMT$C--8(qWq@`oKW^3UYO^m89EJMZAQJc8TXJ35tzt}si{ z$3jJe#U0eR>RmOWkwQmFPHy|O%m_ynrdA~%b!fGQ9tDiErIJswy!?!7{g%w`kZ^=& zrhQ9hhz=I4>{TOY9MB-qQY?|@X?*w`d3Bx%OAOxbmFzM#8gl%#yLtk=Y#!Gs-qa4Z zagj=$8QgyFFz?(J6Zo#=2hSwp1EwGA_NHeIFzm#O}=T3qJw3_(9#0r&)wJlTyd{Jv+(|<(z0Nc zfs)B*@LbweQsY)U@c5x_2-8hq%L{8C%hiy)C|%lTsP5mX0YoU<{bVaase!vgCw#{yC5Z-;!lu0l*3-ndzZ)R}aQd2u=mp}PikOeQo`X|~%3m;6rTBDe8<9db-u z@;V>7n>pcPdij$&gl^z;(syF!wAbnwJ<&S8hkO;RRLJSz^5Xmpl=0(2Kk*A$ok{x) zbSBT`ZO>XK-QrsYs{6C49OEJ<95?RJK|M|MmveS-pB_#pUrV*M4ml+Wgs%78PO~nc@X8ra zV>0UFL{c$6tH$>o+u8GHxOL&j-bXsJ%80mmU8*9M4b2~0g#zdDxqh#hS;6q;Y~k-; zdmXamqA1+ubHRMOkqG*nxiqHny~B}YMY#`)3=rm}^ZVC9dfn1Iz3J)eg|C3Mta-Y$ zVgtg3^V6}s?^EZ6H=rqcK!*Dg=29h#_u3Ru!@!lItEmAWLFzk3b)0OxFVq1nQ)%^; zIAf0COY8(wcK{9hU-Ju!e~hee6RA$#zmLMG{}95_(YyH_q;#F&_FTjt0Ajzc`zcDv zR>`*XnbRtoP8jyI6eUCW`(ncXN{P!4ZVmy=H|}T0c!oKDmq+j_O2#JFJnbQ?<#3|q zY${`1?tgDAuf_zfX>$BNJBw1~uxo86#XRAU23}~b!QhlzX>APMBSIP1K= zTN--=8!vf3ItYb@*Eg-TthT*NL2z!uz26rD?XAG;!$Af8^JaUSh?A`uJ6WD#V}+J(AH zX&Z_-Y0O3$JxQ49X6~q9r?Rd?-GwwM^s@M5*+-kR^xaSuHz(ICBSv`5PdmqoOtlmgwTi>lU}rbH%3Wj`E* zTUDX|Y%n7i%SLJz$LZDTbgQ>}#$7!Ve^l#wI7{!j z2~`1%ogEkNmh*4xN_OU0zDSW6EYK51C;WFD{=vojDZgIRV>uxS@U^cCwjo_E?MUn# z7gn~mz}3x7Gh@TWBZSf1T~MCY5c_m|7{aenF-C(6=L)>3CzwEQ*%a*q6zg-ZqvC@D;3gJ3}(u*mV7PGsgQ;1zW#DnW^whUej? z2~~aNMc?QT$Fk(RafqTLR^`9+=B|29?%w1B27HI=hbLS`b}|%d!$!=%>mC0beg$;9 zTb88ejDNH8@IX~LWp%_l9mzNoC$h3pRo`e~H@2i+T6V8!)f^=k>zOjr*CwE?jZrk&jRY7Y{`V&KWt=ln8y^5l8|T} zPx-KHLKY9$`(hR-3lEeKc=};g#LC}TN`Ju!xEG)2>;d#B*c8wSxn zy8g3|q5+jZ)F=YeUeALQLp&YJa38%^pX5VCDwyae0a(K_Wj)`z7W+Pv&ySEl!FnTTxO{dP@P9^2dY-&G;F1mq^9X3a_r^dLV>+WIIRCVv78VnZc?P(c^lEb$^CowDvv8bjjDQ=r|ke;jc4`pve&GW5y#gV-A|WkldS0!~t|T z#N4m}savQt+~y-xaVK-ln=bC6|j9zD7@x+N@7k+^2*GCB9Eo+U2Sr? z{LuhUnk!OY#;+uf(d*--)jS#lfC zOlfATGb9;sB5jwDTKc*MlVnO6MlxT0CPf;cqm%nJD*L4h0@fcM3~u~}N0*QQjIbKT z|5$U8K88cNyM=u$%kBEuv%MPnpdEBOI$AGInLBh+t)-EB3xk`Ue0PQTBHLQml~86c zWqkju(Eh^5qMORaXz~O19>!K`G2UKt)h0`1%I!^oDM{Dw#WQVr=y3(w~(Sq*vcW-R-1CYL8h79z5*7@X63VA{iR`6CpKpJ#!B3g2Da+feK zw;ZOO7VbZ-tkZ-`781J;-Rb(Z?v&J7f+aDSl=N)9KlURv<$nqc5q;RVuA6%3{`=b8 zbywwZm{@X)nmG$i@smd+vy64_t4LJlVQ@zZhPtVB#pg*sSy`J5v{AJr9K{6m(t(dy ziTMnOjc>KpXg4c6J$i_ZHn`eWUg>l+_4MQo3P)*!?hf&r$-Wj&~i`+F0)jZ#O0QPg_m;CB7gKunppjN*(k9@@!pwi+V66 z5%5VE-P^6LzkMB0D$3wz4R0Vlh5L2v85`aAfl$~>NLAnPS>bo0iXulcV#r`xztLba z>B3uY2LcTP6H^BttWd+q&oxuknYIv`?J>8Ex}F9WAe4=3$b2RTjrr>-z-*~1f?iUD z{jl{x815Ss?mk85PMA%4C_H3eGBX*Om+~a1dS4az@!rf{-k!(S22m$1m@H3Ei0Cy< zF+#EY@G>k8g1@5WFm&O<=knl82qd^SFip8l;5e&h9KUy3=y3Rz-xv3}D`KYl1ci@2 z{%u~qOi+0no80L$oF^QEqkzxAt2oL;QQsqjldX58tA+K)Jb~I0{<~|Yr3d)#*!oJp zAoz4_%IEmrbMgBAa`Sm+bhACOWP8$c4E=Hm;_24SEP5(zWExF1?C$iw5aSw-1G?T7 zelFdGLfs}mgVByqS*4p!#MMpsv|UDN6TTm2XTZ;1*kf0O03-?sO&zd4UA{Qz5H728 zJ(7Zk*T-HEXiGUB3s`7KR+>ahk7_9}61pakV5wvv=92jvcsXzrJo(-VeKp$8E%Zm2 zN(lo`3~xy6*R;5YtrwM6MB}SP4wOif|FDU}VDbdk_k-6K|H$ zz1*HcqS{nHt6J%PTBzo>RBQZ#WzMn-x?eySyWlnU>#5{lCqhoY7fvbqbIGuty(8z4 z2NS}VA@*q4DcIHaH3|n-nK@XH@&j=Y^3w~32lv`-xty;SyULdAk+0gF|7^yLc~|q& z_@28vS84GcWT+sD`VnZJ-8=@sQj#V0H($pDxW{{5?%VG#gw4n(W$UL-9 zB!kJ}CX0ivmONDcbMohMeU`6}rJXt>B7SyxAIs9)b@A zPZIOYgI}Tn0VnafXuL$DSiA$KMe1M|;-)U?$R7udB_uwa<3X5+ zMu_kldRpSg;_}NB_;xbt$}ybQM|Rl58yDM=*T#qFR{R z>Z!p6{?P?f&!5gv2ney)4QCD0w_(%ZKn6uqCt${Tp~yv&lArBWbg~lBMm58P7kasL z)|<(Fx3+>c^6CA}W3v2%Aa+k@3DCp&NyG~0SEy#3mlvV6pweJy8Bk4fY&l$)d;+Fp z*yUSik}ZlVmIbwAp%{f##O5&J+f8}f0XG7`)<`%s@OxN(<)>z-w`Q9;h8q3Gir z{a`kYX}P!J+EeZWao&JX?UQd)bxmL#i#()ip{DcAWDr~D_`f_6sJ7njn>!6;y0(Ox zE5%*(bv>a`4#jaaTh1u@V!+5%+=hiB`KcEqokY%CsqoM^bpJjrStAWvPW?#?`k#$! znpIWZDNKza5G_bBoyYbFzUWHfJhEJt*Qh(v7{p+3A%OXsnENtdY1{$1*)*&5slpzT zJ^0m_s<6_%5s8dyy|cDfzw^@tczt$5glcl|y-)Bzuxdu^cUh%2 zgcR(}p#xdy5>$0}<-lg>44AkK0>tstQkkmDHGlV$)iWvy zvaJ@a>TAQECY8At~b(nB_j;{Mc7#vx0c%-+dYBR@yd3`E3 z1FCghV}KYJcOugFW@imMphl)Z*NJ;~d2U^k{e#0bO7m^0hk?QN*l0(yl$^LOY(>d` zoBp4&t~?ydt`FPFSYm85B+F>Cj7+0aX3D-K2_?KOBUF}9AtOsoVr19LAm0qiFrgT- zz26Lzj40b{k20+$%NW@w%X~9^-zy*IpYvR2`91f!&wbAMo%5XQdXDC2yOlOW2zPrz zZJEW*eD%ZwJVyaNqKV)EY}c-HQ&|bHW2JGDl|TF-pD82QuN?n>3CTYZ*hZXeEgr*- zH{Yr%eo*=1{2_O=cg5`k#|}h`nj75kw#+!)_~b>N4suERh#o<0?s0g~A%_M}>id>D zpM`YrJ2H=^@!^PWnvEF)5; z+yPfJwbbye07o|5nUHq8Av4c-_h~?o#&sk*620PtQ^D-&K+O+Pa(;%G4kFXSyrWOH zw4^rs?DSP`<8Vg|>fgQf4WEC67OS4e&j8bqQ5u$pA*JKepr%BYsg|vuggm0!+(de! z&kJV~nHqt%?;FtEi88z-NnjM`7G!Dv&@MZ9lTqs% zY^M`@6NF)nz||?Nku@=v`aSCFDerFpCy#SRQ0rv|Y52qp=+l6t8iui;qGA8A`Q*_# z8#UQOY>7eG(Syp9ia!_PQOgb2?m44cs^DM`M@tQy1tZRTd$(l`$p4fr-;D; z6S`!9`qn}-=`KHPB~Ehvx=l}lU#5Ktb}22Xm=qQ&dFTI&gP>m=+#b}3boV98#k)T( zC?ywPqKGxi+1u8XHpFW&#CX#KMDK~%$;6E6s`oW0kL(E7Hy`m}bDVIdO{_}f6$v_Y z2W=*zCa3+;P?`ip3=4kh!=|M-MfJvyg|X6l8RCUq_hsNC`k~#H)8&-v=JIcXMW7CL z?_EAL3nlFFN%E>z@p2_N(2PwTyko3Ra)C^@;qpUfufUW zh76`XFPR1(?icQ}=OA5cwSJmYSdfS?iFvn6_X)J@T8mRY|=^zz#CiS|J{vCe>{R zU+;<5*VSe%Do>%0+A>N4ljYYWxQu{oLFWxV@Y$R2HWnh4ta{=uquTmI##woj9=q_Q zGql;1N(DChHDY+Sz~Jc3YW^*o)H1)94d=(U5!6Bv^ce(%H6d{@Kgiu$UDzW=DBTv) z`GD3iy$rY*48jwYa>iek@1#9qf%F0w4&K^zm}<7bY#H^TfgMq&y_w+`4}4 zH<)<;_sUfdCT_vE=hWM10pBWRYU_voTzrZU#hzteDc96cCihDAuqvPM?T+x6cG^F4 zTv-{i-dAju%3zVN3CG!1YiDh-qRnsNX?p=4qPO#kI-lGmpRGI#&TpZgc3Y@-^DvJd z@RwaX{J+fPRG}&oS&U++kaAA2j6I?4Y% zhTJLSr@2@h+1V8&;)y8RJ`^f^rLGuPdu{?D*)?Wf()tqG|TL8qyZe+jaiWkfsO-jQPxo_s#Aq+3*g< zIGWIOIGaQ4oqxvqxv`o!<`TfI2VDu?&t|cx%hPXv9DBzd*XGVA!*?(K)lc;ge4H}& zSJz_5!6Ii?$mILlh^4A$tKJqw?G3<;Auvh7gzcqG&u>hKzMVmZep4`mv(a6j>HF(63pazN1*+Obug8i*t*gTCHciPx^(_9I`R;4>l zk8gPMuqU}i!o8WA=t#LP>7oucjBacoAsX`xL8{nT4+|7rR*G*T?jNh$#r=+syhe!{ z%RUdND!p!2w5iW{qdB*;=78k~^XWfZI981_JM-1f7!5=MS2u%Cu~Lr>N*Plh;LK41 zQCNg)ux2-KwX@7-LpgiEE*USyV8SP?r$k3Uq~S95&a=(BTah`8RLHprjG;lU`aHCkj4{?w%a!M-1X_J0g|2d!zt#Iwruu7(FM!uW zb<+YG-(OuadcH5Zi1>BC*~ep3%N{W zb?T<@s6bsD(ybh!&twdS6T^SkgC66705dFKJH7%DxZFK|oR|^#U-<4NAds`flElhe>#Mye?B1~ME)A~|9;OM`1C{@0pXF_Y6sS@D}unA6?n4%1Bwvu zmLNyamPJ4;|L6X{|B!*1f3AC)?xf#~1u1y#4%`nAdk}ySpd6>H7_kr>+@_xd$ZiIz0NOxm(>OZ&%R3{`ZqZn=9MVs%klUyvZFXswO`i zn>OoKeqJlBX8#^vkNfJ@MsmZou`xg2reDOhKkXa>>Zx*tw%%L_@y+{P@VZ*tY;B;s z+D3$<7)l}JkIx$DE{%f4OjA{wYo@o)T*8eWO(&)?C5r-z2hZ-VZ3q-1&)3H8Z3ER0W}$MI;3-mrY!`j|fPg2h&F@xDU0kV&ao!Y%r4G*wMyrFQjh4 zQM5SpEhIB#iF)MYdM?M;jVZA<<@NUJO7=VCNbSY*a(bqcwtQ3{1`$>2noWoD)wB7N z-rpb1na%e2l<{({IpSqCf;s*Udzwgh3NqL3GGIsQU??_ zT#1z+#qQQ6w$tp&HCLbhPFv;!gj|g=W6mq3E^OQ+(_^Y>qSCt7TfP)o>9oVTOJVdu zLZOt9ayGR3@demAR{#QajHGQ+y5q!f#NU=Ckx5Pv+{64yx0>BH1+0dAZPS;DzhfQM?8@W>o^hLylmu5z5o|S zCyz7e8LzDGF33+)%N*(&N;PU}Fr8(Ir!PJ}a`WzMB;JS*c4w(+O_<&~%6OLS#^N%R z{Mu}bhI`Ouf^H4MiiL{b{TW=}6W?eI8s{04Mg0PnCCVI$WLY&XH#I0c1be4GfMh&u zDw9anYksdCGS!UBv=KdH$Bw(jA5|;YRGF8}QE}4Gkt@3DXxMTSEzrvN*l;Jc>wb7X zB<*wf&ciojuYN2pY;M@8do1{bQQN4b&+`t@Iy!G+GE?MAvOnn-Y$ANj1A8kL(3eB) zRR4-Z8-f)EEn%pGFZ`gS{#@oe6vxlkDQGXA`aF14>*=tEuUHo}C*fm=S#M$5Q?pMw zT+jznvmN)j^4!!CC0TT%j?G^izmD#7r*lDej@~Y`GQnLG63|Pm9lAU!Cgq>lHW;7X zoXz_=0w&kP`j06>SK`gJ zfpa1UYL#vmt^V}Jmmyn&X^;!HRg~J!N5`d|GcH>X^5B}pSagG7aGev(J|@_U9B&_W z*GTa!+(m*a)iHtf&lJ6U-;;%0Rc1&$G+J?Dsy^YKLp>O_9Q6curyl)65Ufr0=wb

    _``&q@j)?f-i6^G)3B=HQaYPt1Rw@)wt#+>Lq@ykM5eKu|5Y!(UXNMeEyW0E(9T+TP9U zt{57-p8J|EpPsK0z1rNBvS0}KL5Q&x-Cxzc{(+q#TUoRx$Kr)(|A!}#>U+zExJM8= znN=nobhNpMM&casSOZ!icuZv6p)gS@9SGI59vMq0hp>2on?VR3a!TA$eKEIEal7gr{j$Mx% z^}_rLJ-dl6Wml~HkaNAF@vm-d>V=pSu$^z_XZFw{VY8;|~tA z4vvI%3h$@h@-K_i+n3d0bEUp76Gpegh(-EeqZAK)K`B}U#IGDk|7-y{O(-v zc;o5ulL5lRu*`Rx1-rt1(F3&Tp9BV+lXoh@SAZ`wHMOgLw#?ITjiX zCCVm!%?b`sg<4#vM4mG!*n6P;2*{+4HH~BqJUzbg#>~+`fhlv6xU}u;7QFCst-RTj zrgPGSK*0r-?u94?U@N?hPkWLH@TAs)pDk##(`Gjk(EFW?xzMU!HkxL9w`sY~pL>^?50A@Ur@0iCKpCCS z@bLDN$=EKzQNbJ^c94)p)3v_tRDzS0AYVF+>(_hF$?PlTxs*)E{iE6`Ne!282NV~z z&O4_{1n{^b*ZF~2({eY54ZkDSt!N5Jgky~_A9YXuGmJ2AM^0(=miEp$az3g%SP2WuJq0kXn zz`M^qf2Ax0kEW}>2v2TI1tt=|XxvusT*viWgEq?G7%3nr{~4z3ZZkh8zNJ@oal*+C zy$Q0;uE3UN(zN=k;Ue&p7PKi3!UD=aw#tX=aF&-hGvU+yVRRHEPfth}kb4gLiq1?( zhj{mT4nhRIjZy7rXXK8m6B@Mf1Hm$#KA&Fe3Fk}@JaFFr8gx-fl|hF8^+Do zxrz#UVp^&FLW1)j9PF?5wY7583Yy@9Ob%Z5WcCgqTR-e1^^p2``b%@eAzwzF)*eh@!j3_dGD7v&Ee z79S4Ks@a6|^o$#z0Q6qZoA|8{e*FIZ`*K%|%<~Mf%nZ*Z%uRJKWL$9;M0^+buFa|> zWqOm3o-k=4jCj6>Z?upfs8fpC;S``O+d$FrmM+>#jAoDGl zfE~y%-=+AUii>EXr!Vo=$ptY0$m*9$6S_#JH-uv;8X<-aRAu5CSEyaWPlPn37ZCW2O8%%HwGTT5?%D%2! z_~RoOGQa;heFn(a4Hmaw=Yr7jXvDpVLA1G?sX~t-eq%+7q>;>~3N7~7ah(+)`q%4ip8DG`}K>=El_nKj2!InK0#tIaWK zg+e(5dYtJPBVkPIF(Yu({A%JcL>c6|E`|w|c(_>`9Upn)VxdGbg@IlN8@M6Uy#pq7 zey+zqW+q@&5zvk{Iiyd_ZS${-v#^NgSE!*xz7~j?RGjXU9}h`b0C$(b&@1mOfp(l$ zJrU!oIESeL0V_?y+VVZwEx)l$xHcMyC#bd$e(AHQQBVja5Ha_qV1;+YEdPer*`(1= z%D*A=pjc|(F(1ye8jAqHMnp{WlhU}~(G{Bu4#QJr8stL4dl-j+spF3@L88+@rKLa9 zah*Dw}~c5!aM(6veC=fN~KB z`kNYYC5WtBmhc(L77>fOs)ok0-sfaRe-!8)7?lHTMZ~+ITiCB}NV&=1U4I}02xBF} zTC#%(leR$@2N}EIi67ug0*pVoLm7?}-3Ep-csCu@svA!e8qCXcx#J3uLni>B_v59e z{tPlSh(ZV3N(MsXbwuC`kSvk{Na}BYeksQbt$Hyc|M%LjWq6^7>#GXq0PYkZ{gLV0 zdVgMD>e-)b?|){M*LJP+PUtOXC&GfMQ%S@}wV^qa+U_ct92Y-X#9%Nep~)Zoc*T zVN{~ye1%XA)C!O8@DtxDM`e);XE!#WQ$)ZWzL-0|XO9?42Q7oOBztHk5$VaHSSBC5 zr(2gQLFm@ZEFK(FF1jal>9BIkuCGiUrnTlV+Xj{ESXYh9(Q@T}1Bm+iFPE*Z!OVhd z#auPSe1JKE|C(PO(g}&q_x&I)j0-z2!#j=Hy_zGbGjH@;f)_i@iVe;CO`W#vnGtvO z_msOHMpe3AjkA|m`7H{?x?c6mO`2AoAk^O1XxY?K;Y9}2mh{JM%-w9(O4AE7e@aeb z!lt~|7*?8G$!f{O>#v4Y5+&;kTK(2a!3iE*P$H4b$D4E!90r$f-dtbPo->3@d%&m3 zN{5V0iV}LI0L21nwy=_#c>IJMHdXUVZ`0;{l54%cy+$S0b%)-8yW#et^|Ct=-c>(y zV{w`SzJ*_0^qYi^o3F*!pnn86>Tp4r?k)f|7%djFQY z@x`Hnrez0Nt1QPV%zE?_kPH?ee-KboJoymxWtt`j+<3aJe$7EUgF|0`_2XOR zvu7Rd_j0>`)|uTlRA1KiSgi$a33iu$(=#<4XnOhLHqgGzWU%$sK*-Dq-R;jhljt4I zPZLg3wWx_tO}U+P6E|7zEQbQrI#_Q3NMMzRoNU7qE(~sDI38cFXS{!_?V3VCT2{jC z&|~;Oo1|A2P@TrVd=g^rytxKNKgmX}JT=Nx@3XZ&JF3$xlC&>WeZs>B@GkZ*m;c&= z`QPKP%K28}f5hu;#r1y;Zwt4ziZ0saPyl1F0A0NKHupde=ptey_l5s}#2;gNEwvH- zo&1l}tRWBqoCsk2$31a>AzjeFhT#AAAxG#k4bn(VgRp-sXrFY)s`P)@AAt#ZI)E@^ z{R#guIe~j9Z|E;@wgTXK=WjW)52!#u3qtM+5CDv+8?ZE^{-^RGrUfQ4{_n*9o%p{K z|9?yrRfEXq<=NE)e9V|09o2uo>{?fw{-=T17{{1T-pT$`|A_KQK#KK#lL_#LcgO1W zDKa9H--ssmI>*`CVSzVgENU|7**;oW$yk(+FoM4Y3M4Uq`Woi@rd@DFp`x&YzOYh| zhv8LcX9$1mlR|HEU9;&#$LQr6m5GAiC08Ld$B^-05i68pOpY>79*ya6QZt6)7G1u) z%6dm)xjQ5uJsGe_o*y+*4uZv z;191i)kAwIeyfl!6fT8YVu}{ndK4s!+G|U90ueRF!19Rsrx?_L^aeb1HF`x0rJs)= zG)N~f;alkMNor>K{$X^U;8N)jtTk?8(dLed+7qR#@Xy*G!4IEXm)eZ*WY~%uX}pdy z!eg>-_g<@r)Bj9LHZ!YHUnChqT-bcP(Rt-qd7fGP(#*`KmF5?b>1kIQ@{C06qP z+kigYtmOJrT8A2H0+rmKI=j1|2l{s*JL&&x7YZPUQCQuT`Dg)#pP4CxyZv=6Im}JQ z=<##F|1QT1)%Tn&R0_dQFqj<}F=c_Zs(C5(@;Axc zT-NvKeN$8rblORSO%A@!$&Na%&3d47B#owTqTCABRujOapBXoL>1R7C)mXoa-w{5^Y&`XwOVYU|hrRrn6&>$*@U7PER_$a^;e*e>>m|FTEHxtzZkC@|NL|<9^E6XzxDRA^|s6Js>|>8)Q`~x=F)-lv@b~$ z1@$qt{4*@H)HPpQj!!S0j_>Ht%E)QGdt9P=2xe4K8Jm!aD>Zj zxwjIx=L3G{Jx_0@Ct5(2}s;v@Eg9_aD z7TS@~ao;gCwJFsbl7@bJg75L&g2kJ4!t@mW|0T@UVM4Gd(( zW#mB(vJwgFJLc4n!$q^CDxaAM?=kBcP`RPPU)5H5ZCUT4 z16|Rg;>#U3-$$Vc3MbuhjOn{Y{-|b&VjiZheF76t{lw8`TMpBAXJ4Pf2GiWP#?9tf z9@6tgWYI-*V5qh~TjR5R6Kd9vnl|SMY0Fmrqu9~(j?jwW>4XgL&BD7*)n*{$*mtHh zeK6gkD_SX$g?X|5t7XqSmJG~EG&l5OB&UX-q)m(z;$$3+gx}7cWaHER=mVx?hwAbv zPZcGWLQO^O%@nrFNyeO>sn>l{i?19Lmjky~14+7;?sT2jaIydRs8OxszArw>5M&Q6 zHnC~t{($#*)!bf)(0X0BZQf}4vbDeERck|Vl#jLEXTvv@2?+^tH5S+p9@_ZSLI81R z>YNpBbSS$KzHoW%>^?I?2u6mHhJ_tLvW^Qer(!AOH1WTg$zFixnEl6YWpmF~Rr-_W z8`*lT{i{xoZYKP$^%U`R%@r@U`4YB`n>;IgNJb(`aKBFWriVhc(--DDKXm?TOq*#@ zq-HUV0vY@sx#1h(BmW$ryqM>1!M^9Ut$* zej8E#s3JJA_Nu%*$D_rUg{)qfcw%yI$S?4&9NzoQ2^KJSPu>%)cJ+yE*jRC-WP!#|MA2 z)};gNV4CVeqt_ zay3N{;i>GhRp zYGY^D^B$T<%Slby>ucjL@)A{Hb$on$4@XH8T5gWZ7^!lxKE;+3Xg^3phaL{f;IZL5 zF#SX~0)qZ6+-Lvo)297SstUTDe(cTutrq-bU#9mu5A^;oU~nY#`${Oxp^}g^VNcjZV&5HidF~WZx#5=RN3HREbzV1(IzB)hTZrXcv)Ws)~Ifi&t+*^I#N}8lTy9YqQcGG52@m@KL-~!M1qaK-@*!VV{)G*uwx_?d!`tF^B?ph(igI0;S8SgvGxuP|csoKQBlwN5Awth4`H&`kg1bQsch+ zGA!FW-X5L2Ao%6%PCT2M@H_1MAbmwq3s_d7d6C}kstsLYFI>Y1iTw7&`IdBs_F^!U zW8jIKtoL62d-`JJSgN#$GqSbZ;@ZhViY1Dr3@oRGr<>|<{U3q*D3qfh3W&0@@a<1_ zS5>J};%!XgBVSa#TTd=C#!Q3t=xznev311n3sh*cv2-$VsK`@196`J|N8WC}=pC1H zSI<&&!Jc9$1Ds3g!|QQojtEY=a^6~rRrE1oxPKfpYa+Cwq9SR(m|9<}&$=erPIExM z=cT{v*-;1xyU+~fn349pJDJbMMfI-0n)AE8HV_}!Y-{p5z6;0=y#;xyX6h`wIgfZ zrBTb62m5}UpN;%U&x&W!eQ0!iG;Hm?MB;#S)p@rsW^9| zuGOAt#x zF1VQwmKGNl76MW4?d^Uedm2eXX#kVIDZyRPk(Tq%%f~nU=>IDxxC|8dJ8Kqzz#iqT zM6@EwRRnjS=sKaki~jgAvqaNIpR+F?P3XI_a>rvxIg94_C5i6s57(T@Zkv-=^OrPk z3Ktx_n8^0LQxAVii_Jpa?JWuJirKZn!Ps@&jEmre^~CU_e;X$o%tP*iiF^B1L9)86cbG9ETgQM%DVnw_LK z)h$;nYvnP%uJ@P18k=a1Il>n2D-VLiWEqFGBT#;!{!#>cNNDK31D&pPPmwcrinKBV z(Zil4mtUCCu7zM5m!Onpq?2x6yMtSxGMX;`g{?=P@VO=gzeD9+`8Wpjj?_EiXr3p* zPcgoU@*nADfjrmz&x0TL3jR$TZ2r~V-46($~H~X}=1meVE+n8f*51yAKy$Q5b{@aCc+C5_HWq!fcdtM990=h+6 zd39_1V5vy>_EclnW&5{4)M3@njCb|%_SIyU#EHi3k;dS?5}6>EXIa?X@A}{Ur&F4U z=&wur+Q2g~1NX0e2OUuqwwh8zidv5rYt6h+=dtcqK;RZZG}D8W6KTACwg{KJ>X7s~ zNXYz(KXq3xynbNuh=5r31$h7)dGDGf**mO1U6*w3zt~Ej+`4w~e1<$%9bU}5Iu_TP z5ROo=v@=Dw9p9xc=5x`G=Zk+2vd?Vk_T=Vf_x5I)g6Oa6nNOk2u1T(l`4FH*!oBaF zALsI;GVbn|#My|lR*1M$E3b0fs4-F&RxRE3CT@igf%}XIPypX!c4v9`@}UtUin*JO z`8>*>M%7a{yzFXLjx!B6f`4g3JC=rE7 z^5;81ITZHhYr)G927B%;1R$eN`&Lv>AmSsS54y0u|A!Z&*Od1%_fS>-(C&0s=wErj zf{(GKZh-&3ncnKOb&PE2$9wjDmDx~S5SETCEIcx;cN`;t9Oi`tqMSz;Ius6#Tk$S) zAjG)im+Uvcbr)FBtI0%a*4Mtc*`_e^}7& zS#^G;z-G+d6%9&FOXI)p%A91Y5Ph0cUJYjZ$;bLhJySw_OJ$Ol=N?SjHMb|>-MxYU9 zFsm$wGVmVFzZao9&H~HwU@zBy*llGpa&@9t&A}HQvJe{ICl#i*WifDcP zVcO^5JB#+`pND?)EwA;H!{={+?!HD5k8tS_(t2rf_594S4p!?pQ#)GJOtE*b{7n3X zkeQ!uP%QS9D3yQK0@d6e8b)xc>Fvb?dT*&=jdG0u8`WRu9t9bv)(X*&MweEsI> z*&DLvb-C6fmDZ!-#FitHGEX_6(!My}`j~V+8$^25J8;$er%nCUjGox|k)mm<{XDz{ z&!6M^9z2^UHL08T1%GH!;f#^ESQlzN@7v$sN2m3{caBp3Je`UdkznhW_2IKoUCR~F zJ&jjoyb(JnON~EK>2KU^p-Si8Xu1C{c*UjhJ@Uo3ec>9$F3!dYb0cm)TpxO3jdpZ+ z8KUcabwKA~T5+&`pmGtd?!@c5SzG6s1r_u~#XbIHk6WN4TO0%0*`gAK9`G%Rt-j{o zXk1!fwVFO@=XRcL@!4BndGY<(@MZ6hoToI~U~e}IBC3o=dgoU_Pj!?h)cljv`Fx`R z1;@M3-t@3CvDslLTW&FdY2k|YW|7v^r5&~G^^X0ESGPra&71Gbe5~wLT+d>_ejJd* zp>hQpFO+noLaUCDivg97Js~KtcC4MzX&AOJV$-MilTh0d{fb8qrJnNJ4A zsA92!>Y&SYBl|7a7wzixB06u2-nF}WLsTMcEy@#P=sZXAB1gmTVuV-z;5?}9vy+skRx8nq(RG1&!_YEDVg**w`EqJbjA49IxilD z*G!u7x%x=Y+r&5tIf1OAz=_}-cJ0_%yUc`D(e9M>EBoK)Fygo~d z0C7Ht^B(i^(dcKnQiN530a<`r{JyPmS2}JKi|GASgx`An;k$ci*>ikA_ax!xw ziQcbX@t#Hn-$%S_{DZ_>57=7+X=DX&Gm4%?_>^KR zNFQatY;qsD@!-W97QRQ^B63PmnT&C)6HYsVdAR6Y(B&i+3A)gl$N7^-W zyVNFQoD0DX7Hs!AiNc0K92|$Q@pWF5{y?Y~f|a{de&H2=9dqnB|D_S~+PxjzprK{Tn3=icwWxT-=O>Lp<|>L<^h_h zX|nF4)CmrrLqyBbvUlTqhM5KrzR;&wpdUA^ztm>GXvn-2={x*F)`CAn?#M@U(tVQ~ zyzxLMDmqE1;{&HrR>Nre*~0g<2F$PP>chiiC{NNl9|dlI@Vg3+wBnLf!(nlW$`!hE88&)+)B%7<&Ch~ekmgx^-_|c zE%kIMbQkNbmk8~n9_2BsbYw=lSTLM5F1m74J}&F=aP!NjEPfFp7jj-T7x= zXFsBeFp6vjO1pBXz$&B{vph$)wUuiOFC!{kFY989b|+@GE`Q(oYEE zo7>%)leFd7uz*da#I95xO;uPpUPf| z(>h;eahNupne2L#F~{IHcZ>s!29g^EjW6WC8>DCtw3D^H3OCg_V}e{a{QO|##-jV& zXk#&ywjX`v8@KO^dO8|592=<-1fE&ye?5O_cy0bqwKR+4wfk!R)&4iK+o{ZJifmd^ zl4n}0*FZOoE_v3j!rffmK7tIBA`dP#Q=&p^dG<6gU+Cuv?QWpFey6!$H%_)tqy-f; z2vJC^A)yd+ecAI+<}Ke;#lzN>``nmhT^KgP$kRx)Us#yjStL9k{(4fEP(4Z;r<=iG z7Von5S~bVb?=#w!}a6tB=V5yjMJtyGu1+Ar1J27T&Oy^W5-CLC-oC+ zrFbogTOp^}us0+69U)%$6_JKK(`bltr!3k;d!`^ENhFC2>EvzwWWSp=KN`Zw^zp5r zJr<88_NHNa2ik{NLRr%R4u9MYXp_b#-QVA;VnIGx#Fx>pM=pFMEIIzhfo$F8w+8XG zdG-vUy=i}y(RfRyQ2&{Kmm)7WEl=uzpCUHRSbKVqEyV;u#(KM6vSGm3gsyKG(p*~* z*{)@!g;gg}y{9dn$CB-=P|JRl{z7Ol&Q*B&85YHtlcAs>76x%8pr)o3OXd>-ie9CM z(f6p=coOgtaL9Bh2!7g!Nf-y+JbI-O?sH=?jXFTlkYQnoH=&qEY9??HlaX9Lj+CA7 zJuH=C3wrm103!F?a7ZaFG(d5(EpsxwESBCF)eYS@{D|rPzbtN2&>5BMq9^(gXf0;0 z6(GIJse+Dna9f1W?aN|{lVNo}x7Vj{Y0x4xAxl9luB*&I4ea?UL}(GI4!%`%#qzxV z-H)(>Z5+17+nwgHf`0%SXnt2dv8vL=62q0z^MBtJH!A?|wWMlX0#KB1s{fa9K6{q^ zvq0~~vh~(AITPs7a#8+>lLddrFEQvy_#74SU*o#KGX}xHxX6Ex;}ssXA$(5ocN`Kl zNJ!W$o0?mt_tcf1Lk@{aQxxfsqj|ccOTGwP!`LHanbnqt?6KT!b|S&}tLi~e6AM=B z2qMhv?)TrjZTY{2iFZSfDPMdIIsj|0A3tm3+;9|`)j(nz6hQf-8pUDId5yVZ%*`_e zMoEKjl|XCy3206Kd3Y=Zk@a4A^LXdA9=$yaA|Y#t|EK@H*Ypy+FSG;T7DDiL9!b^R zug9?n0As(cBLy?7rbi^yMEaA1H2>@oX^>&Pw@Npt1#3Wqo!kp?zF2ENF`YcBA8!$2Ylx?Gco{U(3)6zO|tX-*(bx-A&6bu{Y_1_MmXF%XJA z&ZU!HH`Wj(X7lwM7nW~L2#*V89X3>dZtXrNLxWMfjep@XNc6L_KK{{zGG6kc)*nxo zirfFkEg#A~C|_x3vsBZQ{A~MISvko6Vm{eTq0@uke@ina@@Y6t@(_0>yn8Rsmgq4w z9Lo67bK!7V)HjKLDIc-D7;LS0T00ua@&R5i!DJA$WL#x_g~V}>f6_a^6Hnm*G#bm> zEpG>~zeqOgTg&?ZM&#iq9Wsvd#JR~FY(z(^c{%3IRi}PgOo`aFXFAp`pBG4-zVe4Z z_hXrL`Od8UnB4B|?(Xwjb`p~rWDsbb74WPQ`giB9_+djJdlSS}2orhAzVU9cRlY!L zf@pspjJ2#!^$^VSsir5br$OYp!I9Uh)5X<+CktFUm3t1lmni$5iMD#Nw8maHa&tt( z1sg=Wlk=&6cYRS&ZsM_YOn-IyU*~$c9u207c74LoWGnzJvRhz?Y#Ga>QX5OZ$G!gT zhY;_<(M#cuJdVc&dTs=0M_S`mCN3{ttEG7K;UDs{fohj+S)bKQy(*?3JYz8n!4+1D49iV(CxZi3B5`f#xpHg zhh0UDEuUjsXHru5x7+9^R2n{ZT*#f?pb&*2qj##Ojv1VPDl7)v zi*NUpe?;Smli;&OO@4qUx!*s>U-r`)8%_5}zbZ)taF-M1;YPH)^H!c{7Fd_S`6{#~ zsh-m+U%ub)b#|_&)2d!*LQ3rD{18oqqD?&B{*BC~XqC#aR+-i%cxyaE%;UM_?~D4MvtuRLLuTt1I7de!-M3cMdJ4v4c9(oeoTDf zyO@SMlDsuyoLr2P#=h0JYcjAJb+RUF)=!ayRT5X_#y95YDxRv_=Z=~*l?&HlS}0Fu z!XKHhaAUFNXD*~A(5@vq(6`6rfNh}QsjMM)O_4hSx_KvM=hsF3Edm>2k^`ykv}ru~KqC z8e*kD#m@qk&$wIu?v#Sms1?a*deYlCFU2ed0EdX*AOXW35Nb@S0z{<#oJH;Z)-A@Q zNq{s8ig<(w3?m6=abU*$3eY0PcQ-(FXIVA3r1_O;f1M^DO^^6WB$$9=ezy-h3|bNh zC359`h=-{YjNl%ct$BCuLT(8&RSAg~poJ=HqALvxZy-+&MS1YZ|L*X$KakEC_JjMF z0>}YcNZDM)0G!?QyZ55@h%pVK{=;YPW`Cd1u0gB!Se>&$``vkj38LQ&$rZsDSbm>} z`2S|B9_K3V-f_m$|ssZLhXXF&uQ<8Di4CcxNX41qWka5KP(K?=5! zm-D^$F3C%+0c*S6@MeepBBKWI2y^3~BE6%t?gJ3*my|z>y(0n*2Z*FbGtWG_TQOb3 zA3Ad06-E<(M??sKH@A@?OQXB>vJUTdcHWW?$^0V13=nY=O>wvfR1}zQ5`YfZXc@f~ z?})$vTpCeRNN}XTRnm-)I|@5`8$!cnJ6CzA5O zaU|hbmc!{xJ$bB2UcC>>9mlP%*;bI_$;!a4A~pjmuT6B_W?uQguw6s_N9+yC&{ps2 zxx(U7g~i>UYENcttIJ2oj0yiz*}HGBB@NSP4U6>NqhhAo}@Jc_^QO zJNlZy&0+~>+V<7+QZ|g&ueA$;&@XtxHy6`E;SuZ1{M>F+U$K}@Q$20X+qkWq#YF4=!H7bMagI!M{TK5i8?qV}w2{YK; z#wq&Qs1^$7E#IXC1L*+?!;VX{=C!y;9CYOEe(~Z3p*;!rAzP}H9Q+WRjk|zi;48U9+5rM9g4;lwh~#CFNhUx zVKH1|a#Y}!1is~`=^lsP;7&Xi@^yP207MuG$`|M|NZIZURf8j%Ti53OH^u9$u((g7 zt5@pdYmla`rI#|+(!WlTG6aksJ0xdAnk)i@X`N9-5=0qAH3d&;(p|Y%F!h~2z%3mU zk07(h4y&n63F9P5-2512VLid`l7EHrCm{3;4ev!IAp8nNe*k{>RDYjOWsL_wMRB_1 zm)9uzLpxl5g|1@O-4;{^+bXW#c(#c<@M}0-0K?s8+T1?q?+`Bli=qGi6mhqeHePUx z;nz4|0qXxl7AUnQAgAfls6NF#9k;gWO0}vQ+2)_@Y#+KPo3u{>fwrsBhBJQv1a(dZ zA<`YMLc6*`Uo~dY2QaVL=RE&l*SF4bL%r>-3wzD%roHtGor}jwWhWL**VQLHyj-MG z$K>7o(CpV~9t9>TX7vHOcG)nWHFv|eSshVwO6VQJt~zv@lNdu&F#7>IZG)v89ld(d zAA`r3>JVl%8?zB&R5ts$fnt=ock`2_72g(!I^^lGvRU8JQwX#R!MDh&!Mz$zV&Q{d zHJ8R4rS^!JCu!8~bAPTS!66Ms9p);xBL6^&O?-zQK z5X)wka!Z;0wlL%2WQz=w)fd(MD|<@sy^p?$H+YncH#oX!jOK2sP;u$es;{;W}h>dLpZK`Ya&q5O{d1mcCbA`g6D-0Y>;WR0skB+71GAAVn@cQ&> z^NWp=mVpD7-@7r}mwgp2L|Ri)-8v$UPcZ0L5{hQ>B9WlgDpLmPiIDBmz20K*DyuT% zH7Ft0G-TWk(fKJGn-~<5>y*jvlFwq@QS9A&hWU+x2Gp5E#pNSFwJf9M*Yzrsx<0e+ zgDFZ8m$RQjvgOY1dbIT}oHvr^N(mdc`mP3+lw2xdm1Zc$b3 z9skI+wLQ#Y+}q6-I`jWDa^+D;rfWRC&A3dOYdhtrsO6FtP6c8%Qz{p?aEfqg+(JdO zMU)gx^JaG4iog*xj8VjKLvQ8wiCJoCDT)hfrYM>SE|{f5H6HJL(CwUi&i&{9`JVSZ z&-0%5d*9#kobx@2t35ms51>9iV39gPw(!qSO?TLkc7uzp@BbZNa&L_OHqZUeo}&u~ z>{|~(;-SuxRjEMW+5o46B3qIcyaIQ!v`*l~!o;qf3X-Y#nR|KSJY(;r>Pab@h&UVYr84f4n%nci9FLI(HYkXfE=EHXs+Yk7T1MBrdVQ;Fv9 zav}{&y!C~Y{6TgD*18@Bs#G;Ysj3qKq{b>$Z4FBEhP}9Y6_dfKAgvv~^IeOn$}&Ke zziydz$5WIFF&tzoqU6eNSXGc}rDaGAd#z$psj_y_>twf@sj>`tE;3^H#Nr|^;Xy$- zyY#~xzt@Ynpcc}s+Dx}54NY>c(=DDsfis27b7L1WZt+!KfNSn!H^ESp#}&g3(R1D6 zb8t0i+G3BtV*hF){XeFL>C!~(MEiE!F1g6OUeSMCnV)WE0{r7OCE-K9X=3PfSo}6$ zt3LO!GW*cxc%%XPx+xBa_>lJ!!<+Mryz?B`rz{^>^;W&`13s=^;qbJ(^L zJy3czy{FVj!f|#VjBawiun}Be2{aM{D zOr7?M)7p-ehZZX5G&V`;nsT+&iIQMBEc&1=K0;^iWf|h^s6MmcNb80-=4Vn|C#)El zvBTD$)Y}6SRU8G#JU1r{36tE#MkKoM{}whM{fO9!wDK!CyS*GCinSPYm|wTfRa&m! z<>sEW#)j3H@MrU>sRTk%54bxL#NE_)(=MC5Hf7!IC0M$czLYrO8&Ql)V*->TxY9|`Ce zy`p-PFnkUuz02;pLUp8!;iBP5Zz1*ydewP^!gymy51gF?mMF@$Ez7oT+qP})vTfV8 zZQHhO+qPZx&;3n!*@rbU$6PZbCX;F1yqAFoxYn^RphnSr!7rj$(%}eQ6PYyvcDS>p zvCB$M^IxqF`9yK3AX^wXkmn2Cpy|&i+nj@W%e? z+9&pM-3pmzxyMtJX~CJ3i503VEf@e_g#_f(A5U0&V%-ik;a!~YZCql%xAO%CrBPor zOS(TAC!U1TsH@B4F#5>&*0|os;m*`wYVRz+IlfE-V%r5Mc-I`+lM^1TOzLtCyM) zCsrEP&T$^eKW1)7$W@_+)2*_+EyRPdf^?rU7US{=QbMxR#f9lWTpOz-0Dv%c*db;5@t$s_ZmC`H#Ha zjvf5T<&Mp~;#-QPmp4jAPw#NG=ftV&yH2oCp%^1w^Y60WWRIhm!TKhe7I$R_jFzXA zZV7fQf!9~rowvYhJ;g0_tJnQ(``_X1*Tt3i;pD*Zm2A`8@S5FauTG!q$0_bc^n}DKkJrss_5wrpq{c-RZIXQRH+1iL;>?A8CZ_fX^0!y- z+4C!N-Y1@3gQZre32XD7`eF4PSqqlOFrKrcj@sclIRT4Xvb)wU<52_)&u2!ehgTUA zqFtx8-r5i2e}np#<{927b0Sb=<~`tx!*Q5Zi10Uu1O0I4^Dmy7OK;1N3fqy$hV4f^ zYv#{p^aK5W0IN(pJs(pk0Dx2F{}aH9QG|u@e*h~6Awe-tHU?oPPBFp%0jy%uJy@3a zzWT$kf~$!|#@9`gVGsuiw2Z8osWh>_5^0UCMte=;5R5P}C5WJJKI6auNPcl&{l2~}Hre3-1f~!W-|r|yGbI*8{8wK- zxIys&YGCt$f5!giQU$R;^t|$C=)bGG`q6W9XvF|5HZD;ehTO9V#gT5o_*O_1Rv=ZTR z+=y+QR8+dH!N{^6MhnJ?k+Y8(KGvCs7>78(8tZ zaMEuUHKIh*ILPG7C#*@rD9=kR??8Nmr6*TN6x>sJ2OaN%76FbWWg9F4zf^LY&1atS zh_nLEm#tgp<2%GkD$l8sJrU3Zmfh=~Zw`vc#s=b8e1uX*4Wk-Q1cAg+ZA_QNb6}s- zqqoZmj33h~^E~`A+c`H-mE8&%V?eI>*=jYk4n+e;9G;QzO{OCI?AbrE()A=8l*O~q z9HtU_w#r+L@VyL11CVx-M6{+i5~G9+6-c>OASWXoFA6sp_bzR!bx!Deck8D1NsV;} z)}*1MU}dBce7s~aw|@xB89BWFiqF`tE;4M$^pamTc~K?NGpTk(rAKKbtlJ2 zW3<7vB@;)j4J@Oq8~(%e3Bz)>a134tH6eNIextL~YTzcX3$5jA$r18Kf*j+nzVQudxbWON+*7j@tDJlj;_O1W^ zB<57nycke8Njh(&kG*gegwIe`Q#4X;YzQ|khz}Oz{mpuGHb?)RH2+Guq?yEMbvC&8 zB31Hk>pQAr>6-Ht@qy(ZP=K2gwa!2NrP3kXAL-F$Mf%QwM0C-F5AuIX3{E19nz&bC zAnvS4mb9s)40!raXomPmQdcD+5{F)D%|BQ(zFk7 zKG|q(8LG8dJwwdyZk78h{@k12Cep|c|E^Ud>r6-TMlKf^G#Nwk(V_-YCIzd^Za4!B~TOL2tBZ?Ve94hJ;vDvpzb77v1=%=36Ba@0C#&J zPgO81?AC7N0dksx(PDM+F;z5r<{i}|BduT2K%iu&CKJch8FjPaEomf6<73nKw+nbc z>^?xs2Y@$7_p3dFTkA+zC%5vQWgwo0U@!J41PaOWWMT^2CB8||QM;LI!ME*o>!+bh zguuC^p3LlcuQCDbH8M3>4r)XGuNom9$w2>L<#ZD6<;YdN=U^$%8Ixy-i^qj;qwly) z&YMOBH-%Q**vy1tA?RWH@%B2*PxhhQ()#EI{T%m*k}HqT#p$J@(~{4-^`yXWWY=;B zj?TNj?B-ngChx@4poQX9!XpPbA^N~m5Ep!*!2(!vT#7a&ZSQQf2sfY!pZ;S)!%Svd ze4X0XDzsXH>EuzfgFmSKR@*Hvd)=x>wP>@2?KV4?Mhv=W^T zucB1uW`ZhR=V|k?Yxe!peE7bM-;$;6zkjfIwzT4SQZva&>;!yYru^ zu(iHUZe@LDJvRjQU*YI`>?S<9EL8W^(Tf`EJXmXFYuL`8+3NOb8FNbyFD@$=b6wz^ zE=}n5j)3rL2jo_|cxGQS-Z+a)$cP8ej{ONWL93@1B+bWNKVP*||8Z!`E(L8(+m}`2 zb=z}r=BJ0MT0p0Enm_rZU)6L8_^6PRArXH`ZM)xurhS9ObSG$y-;6xv^-)N2hg6PH zf4rLJ?BydIZtk5euu>}l!g^fs01z9z%yu7u1&;_}ujp$R<-dLhH_L18OlUJhTM|rK zQV?OUz`s`89^A41Yx5$f;t9w`hqJ90)gcJLBrbNnB>`aiE4N(zlihTW*>)yQodgs$THpZ{I*T$zhRI{FAjP`j zv*DX&hRmvIrlCGv4V7%61syc}pv@Snd$8zWR|%kcWi z!&fDNITneR$BfPC@0(5r^Q~#zE6_8^W@X(VT~@B1xQr9C|!$jk6os{yx%Fyn}ab9QED$) zN#?C+g-cO$GL}<6(`HT06}K}cLkMveo=epq6dMJoYckd*gS6s$kvjus3 zvMd2Jv0qza2CixiyOno?otxaoz7Ako8$lBWoNnPywQ1`za55sw;2n;=(vpJf%%=B_ zicCpb6Z3|8jmN8%h=W@1;tc$`Hyxh#s}R7rbx6wEN?B0UI8C);k%5FdgI7EXYy)II znVuEvC)Z4-+P{?d({LV|k8!|WmFUV_NS@Sz(Tg>@l#Lppcphb&%M*Dai`-{qKA4Tx z?06U=SCG9~Q#w7grv1{2&_9K^F4*Z667XDHGLxB!;A?K24YYNZs?g12`V7E->jpTL zDZ+2b@b=#i2;{h2FoSZy!z!4q8fD#I2h9hT%IE%|-b3;2@Uo$&HFX1v&mFrdl7aKb_Rc9=Z*#r{gv=|^Ic zN8=s+g%DfUPtSN5?4<`W^B|g_ItR?=UI^VA{vn~>wNpFRBB9Xe#K@bzPna{3H8#G) zSrK({evzRc+=^$E)S`6D&~G;M6(Owe{Dz3Vs(4?IOOy3kLicuD*`m!4`|WXWtMsn{ zX!#7jOxA-{FDU7ULu2!5fA((Zg(^)I=^W8Uye_F#3Ot35Cm$UixR2naOz*x?M9*}xkjl;PTH)+=QR&oxW9`9hHkRVu5pS|R&v+^H3 z3=M;mJ5y)YCaoMv-0)ELGSekn!yjp~Z9CzuXINkorveDab7lM|<`yF7 z?nm~tPi@bp-bCYX;taEqGMjP^nXK4D&o`wRh_6WyRMreMz#K7mWVMXM9$HHxO{x*+ ziHV76W37-^chUw@jyM}4zZ)Og2ZzO7BfbWT1jXI-iSP>Hf_jfBKYhE_Hx^^9ed1k5 zx>yq2D8HHv{Y$a6YgCt^kb#hRxGka?_YokBdTmFualjV7M!2VR==vy-xD;`c;=Ui9 zCSh$iy3ATjGG@H5_NO=pHQc1x)8AENG(ppaF_uOm1wGhu1gz3|w>$XvC#rI%^KIb$ za5rBrpn7-9O?X#vfaP~EH~wwe!G9pujcQMLHjPcmKaBlo?+!>F;g|Kh4p1Trw=4wC z9^Y~|S3RVv6q)(B>5sTCHym@W%AUvlI>eUEK4jlr_r&ToI2&W%E7m zSZl03*JJxt8@H7Q1v`S~B`Uyy zscrXbu%Z$^57?z ze9pGud>Rl=@IUd9Ke);{<3Wbm{d~Wz~R;=J)@kU|sFv8T5Mmd$~ob1M;ls`$atz0rJpmD4C z*N^s14TLE$zW8sI^0zXcrV-#*@$G$YCBYByf2qox9R%SQ0sw#;;{PdCVG{cPnF<3V zBPX*UJ3FHwtBBD5QWfhiPz4;>Wwyw!E)X|2^7by|Z9)Y72LXT3z%K3qT7>ODy4zb2 z&1?Wd4x0LY`Q5v&w%9elKQ&9ohC)4i?$3pA`dx!(YeGAODkYl}SZ^|9JUc#L(Xw(Yspup45R> zS><0SdB8$SP{7U4-r3(<$^GinpT!$1KeYGCip~XsCu}N;79p%7_OEw2qZ4sAgGXl0 z-li*csbyVWX>NovfVXDW?i)a; zm$DeD@^Km3`mF%^L({9>oB;kL+)|$b$1-7%dAUmwx`mgcb^)(7AD(Afcig&w`ib}MK3W+KEkrvEj2DKc0LeA)1o>sFm8Xd#0 zQaARnb5x8^yjW_Y&~QbikeKTfU0z?&1)FIy9+aWd!b)hZ$>+OeG8%P`PhHKpp1hPa zbQhfw68#q+p{^2BLgK^Cp!x*g4sytZp5lVMNV+sQpuwwfA!A-$8o*2EWP4W0)CY>y zV+8s~hUR%@LWARE<9k!fa!%x+g>}n;PZcD`OncOAPuscEEqY`X+a54c>YJ(D#8oc3 zw~VRr#15|6)g*5y=7ela3@$GGT0=$$S&2~SY}BMXJ%hCs;;Vq-B6+&(@eJRUdUPiebc-8-Eg^a#a(h$HY2T&eMyFC^%JYEY0-NYf*3Z z+E#8Rj-T)B5TJa;?K;1J<5>YlX<_F?eSc5T;K(x!iNzZ)RyM*txM+IG0=h-HMbg9M z?TtEn@fr2hv|ZX2RsdZOwJH7|6A(XTT{Iimg<8ktj*gH|GS#JJdtbjE=^lBgf1Pb= z(o={z2w?te#>-sEHgrVw2Nv5rM2dV?KcB!7!>&+^{rJ$v-D?^YksLd& zf!OrCy$!%ysF`Bq4ezm;TkmM&f!jxuS+6zl^e!^=mtR9vJe9cE@2bf$Ly$Egs-WE3 zcW^UuD&_A+cos@M{_x&tMLp%@}l5CR;ikHfI6W`Yp-RB49; z_$&vUnfeRFo3@5%q^Y9dX`#acsctKu!>tsGT4^VszJ{PD4*Ks!8naas98cOirHoj~ zT_2eQsbGJ$R=I-*;zjoAxjHicizHw1KI7{0B(;KQiq_NR?PLNKYatX??{&WZ7j+FD zXh_{5C9}M*jtTALjdfe_F zN7<{8s>1!PAmxL-{{T|*vapJ0x!;0eNuC}uvd0k!`5E@XrT>UzaUT)%p4!mm;&)D! zztrz)8;iP&J`H8U!s}39=pUwpA2i-NB}Of~xsN2p#0?y|mahq_WQ_~Q;UC;Fdz%Ws zN0&tT`R+0C!IvF0p(yvNzayVrk+u0OHHNd-3qoU5tNqlu6sP32*WzYkRY~rovPZ$c zlPE+hjPKrr?H{Tlv!Q^1bkW|AeDuDiS)r4f{ z(Bf0>G`Z>z2P;Augh;~utB#?A<7)r2bz!))E)jHpF|_fNfudw>QP!v}q8m7+-zBpT z;nup#w@oe~z8@b&%LyiRfJEZC2*x{q5y9aIc)Ks-r5&H7Y(TU*sNrClJ~8S%OruQ~ zt&|QQeM=gJ6dl7npCxwFI@PDYS`|$zYmnEZ$pmG)JaCl15q#$Hh{`!(>V0cE@k$A5 z=g8D4=hp7k4b2=$i$ZcEL>Ad__|2J$FIes~4dr^z&(k58kHp(+3f);i1g*;{V z1&nM*!vnLBc7no2&K zLX6susSys|DB9`qcW8|ao``d*;#Zba5@St`K?G=3G}$At zeqETp{CU3k3Hv{hKvi6M@K|If#D^Ft$?5sT=zMEjwVV;$)!g3vR2bWwIld%+$BAim z#kv6XuW0&yK7i2HnL9?@o1qS_xqCUo9!EY{3*@pe~f z{S#nQ5`<0zf z`0JwL#Fs?3jlek3ds5q{EomH)=gDPgDwEidHlYIS*bxRZol+_~aqkz(01SIWoP*`? zeA20!;Ax`-91sT}RsnnQWnely)^hG5R$M{_=f}e{mK=4P_8(Y|8Hg=OXn}oT_M7Jx z1i(6D?_MKNp1w8TZ@6w1PANp@2BQ9)M3>Wi1Yc)6oCnt0h87Bpl~$oqN;52z4t7Cc zA&yuiXpSW;UPS?<$w8nxBUG&^6^#aj;DT|iZXCTU|0RF4-w|Vo!yE!G2Ec{^^uc@- z&&RA9$xvpPe}LAMCAVX3?TH3-3?bkxGxhu7jMs;+FF#+Y7p5no#%P{uEin5tR%q1DzhcErlriKUuF9C-!u zu4%fYYj+-%E1%ah`zSD*y|&iL*XGmf4(>y%jF@0ecBBE-|x|BMvKw-IxPosa&E z9&{rCJG(k{W61U00Bz3OjoRJY-GyT)q{?N-0MWK13hl`seX(`*J!QH>Iz>ijIhzl3 zIFw8D?$uwI&NTeYRaFuNWj)Zfj*@Jy7RnwcirizvADm)zEh8(}vNvv$eJ4 z6e~7cb6frs0HMR%g(S(rMq|58gz}6!rzKL*VqN zh;s2gTCL!WjrelJq688`K?&YD-@joS8+7UGsX3Z^!)hFuuC@b)IShl)t8-Hehde${ z8eztJuV{lEH}-aK%Wx{bS{=WwXRq%)bUg=!3w90QPl{2|Gf<4q3J$xqfqFQ@X^~vk zv5lwseMb#B;GeS#Wb?Jz4=2`N{g}2XgR0tY(iYbL0>A+0e&8-8sOiwHDODDIoK4Q} zcK5|-V}67NL8rB@oG9&&QzfcJ^|hrYbn2(1b3%hWRc5jO<_61k%TpA|?VD0sOxu@~ ztvzoPA;*nrnvLhgneCFVtXIM1hbcbnf%7p|D=^k6Nx9DK1Om<=g;ttht7z4A9vK-- zf=rd!XG) zNg!JXv?#~=?ae7W!5DF-61#Y-wSu~1TPOJ=f{ocB_5rXIjrDMmS-&MBrz7oO>@|{G z={b@CNMAksfjyb2@VQ%0Nh4DUk(2FoP;ICcrSR;_*f;~eE7Z%Nq-^l;zD8znk85t( zBb}1)mjyeJ1O5{#q~Qxt?T&e~Gj<;6CEU7C6Vnaw>0eZ3 zZF>+O<<(jg=u1vpR`^R?y?t4@F7B9Dtz^$JSJQ`YfiBP<41t+c z=n?`AQasN5*8zqp7CbjyvAv!pqdsIR?`7CUaFq-rvMQ><9I8Tus}GpzW)CFS<1grd z?gQX5?=$5oYM#(QtKj<22#nd3cmlZ0ya{>L_M_^=BOnL-@I}$PZnLqGNBSnwxGsh~UWshv!(rJ+U(mxQN;8xX?Zoz06231J;|3XM zyX1N68AZsx`eLa~;T2YU-Amd9l8_wUVhOi9tZmCTpyqwhVv8zcHFosfKTUfVVt*oNzDGKj(vSsi8_fl_O+P(36FDxt zejyP4v_;e-Wz3jA%DS&_-qK{rO`VR;7VG_K3=DAERd18QeJROyhL#WD z0;r>i<41ik`%dSGZfy&QIyf9{Njo`dZsQj5Pcb20D!WaT{!y{XMe)^ZV{ljwfc@jm z(Y@lO;1dt4Eu<8-^kqC8a>cYt(ZUH{54lodZ=7JktvuO*A1*%8LytE*jx^;A{K3PH z2nGb(@&JT@s3dUq)14r2de>5863SB1TSc@b!G zBf=i_<37{KH3g`mZ0qt>={7vRbl*1_YsCas)!fEPSzhsC`GR1VsqLtGY3b;MC-|A~ zI@_qwSwQSPy#z_~GD0kbG|LS;&h<=^$50;+d39ksdtoT?m)K{h{j&LgmhPpWu}$YP z^F{kTf(5QiSR~2b#_@vQn1hJdR7(%Fh~S4`VrPs$h#VR>jwgPhGC^TjhXsW2WhHlP zqDZh=pDvr5jHc4X>zQG}f&Nj`Bk~fU(Z&8*XVu5`&A01XI+Fp0Nx}tEqhJS-Ez9o@ z$Byy)->TgZNGX`h>&%v&wGO@PNv^#BHPmKZA1j8+*kh9^{HUJsEM7o(ZlJF*db7^I}dh27z7C1Q!3? z6(#d*vuca)XUtwDR8>)}CBA-FI;r}{4}-cKBGunB8S~fb4FQK21M}}o5OKef2OI+8 zrq*f+Xz_DrjB*FYRm1oGXp{0OB^OJ0*eo@MIuLkXUPE=Rp1BismnA>Ye0|Jx^Aoai zmz2os3OQ(D(b$(> zW^Ez7B`A~bpiMNeP3#_EzfW+DAGMIi_-z6QBqcP6{jjX5(Jt+9Zi+hkjRnB(ZVkQ%RO!AnU!L#Fc`q$KUB%45dk*o2NpJy7fv-u%QOBTHA z-gU~C6A%|3j|^TFw{Xa>j&7ibV1b89lLAG>wJAJG&F5z_ul`+8gCDaQ7a5YMcg_M%2?kN`aKucyBVi zg2uw~1?9$;663mmZ{w^7^WwclZqScXSV1(uhehO2M3T6HgIm92pjR2(=A!K<<(ScAU|a2gjD@?T%C+)(judaH8FW+BKYLSqbxLxdwa;H zsdj7g%SXh4cwoJL_9A@`;sS&?qQh!f3GmbXH`k>}|M6kcr*-lbV8#pIJh=+UW;Rlt z86(Ta`92LPMsc%M#5l{6_8BL{d?ofsEvUPXx5ugyzq;qubHhjH9^)uKo-HMh)s$7k z3>w(6YzXAqLsP4XaWPH@c4JFLI6u-5ZFBr3gbLDEC`vMK$G3IIuW0Kn^;9W#&3AL3 zuG8K-eq)XgjG&^O>B9!f_TrG*a~L$uv8-I44p{!d4f3&Xqd@$?E{HZZwWH(-ahC>= zgA$^UT*TFLNr$+tA@x8;{6z+j8=86!bs7ICM-3@ z_!{caRI4*$3d0cf*HkFCqH9HPvV-7|MXa zJ17>pQC^`7UO9idnF1r7IRzWM*b}(7#dAU zxZ}j3X@xm`x7nC(VWyLa9v%;9gI9v_&hHduHvNMKk}rCm@6@}8O4UWm!)`9ZQzi^> z-Aj8($Fj6&`UUxMsin*&ITZCy|96R$5Y^~WfjaSTT-kh1EBF@mCQt@rAlAnpfo`=A z&?|B|j)Z#8G8bPcSC@$s4A4e7O zXYSRC3>4Ky0uUt_bvzc3TxE>A`hh2(2zRcvlNZJ7If&co{y?f|FpZ@)I1B(%NFkvu z_+B=Lr-i79Sg4Ekl^%-?z`&a&tOY z&F?IrX6?IhsaRu}!2+xCQ+#^SLE*Z30i{%V4OCbawg1_C~{)0LMPT z5b-w37`aE2c_KALfaY5CB+>z8*4B>QU{kh zsx({LHT3TTw6yfVFQ;3U>jFQRb>HUcV7#x>I~hzL6joyT_h`~k!<|%yAxmhh@1SjaG;t+0+ z?MvGKUDa9G4oSC_aVcp-@RwyHAiK4mr}X%V=%pg9iZG)kRsrWCkiHYJ5*JPdrL4kx zGXrW-yEf)bQeI^p5bPEA9wEWxNd5ibGpi$?N}Yoxyhpq)Pu4$y+L)N^P`A>qj`Xxf zo&igfpl*l@9Te;RTC?ZN7$qd+_Nc=(I`r1#!kC5AP{2fr_<-y&TiJ@z&r=!T0Tn*s zxT`L6&iNomcnAsoQTak6#QpmGba^V|;$r{YvV%oD<*)Amx228A^TZgwZ@1Ib*Y+g% zI`b=i9&5bD-09K2Gy1sLzI3UyPJz7JZ$zHqc6}N*C#z%5&_neY(oC{hXKz*LIxml- z>irp`nqCwn1kov0N^9cL2IVd2K`Hu5i&9`YBup6d0}J$s!}%lwnas7$AW^8kA@@I< zng*Efs1@a~9kBAufh~V>TWYkF$KWrtZdp(#1nG#&I4Jo5Y~$#z1CVL3;+TWAG4Hv6 zKq25$x$n$i6849qBYlnjQ3#!cIu1zDA6^y|6s&pXp77aga@>@=8!1&$N`)nb>ti_# zI)0POYN|`A;5dHjt6TvzUQG@$Y9~5{M{(+~P4mI={er%kOsUi!U1eXCZO|YYjBv0- z0$qWLiV^v-dO<-ktqj}d@%4z!3@6Nv0F1k}x?N4R`)EzNemL`=Jk>b45~QD3TU?%? zxQi^PnFSRPp6lPA>@M_xI$7fmpN=VS1Z1Glea`^Xfjq|Tx^0%== zjGB;WK4pU zCsh$W-3e^K`LaLhSF%5Z6NAO#dOg!(_8|EqAI2Awt;w_5HL}-uzM15DLf`f9YrWL^ zx?mdV$~QFaCb=r~Wiueq02cGz0Wb!zP(R?nY{-##qsvjk?P9M{Kf*r*14ZQ-H zer{w~ZOfn)>hm1mwyU|s`pjB8eyTyZigtqHLNXbB#70l?aXy$q0;!dk5|oHmYC}R!70Xvs+JZ>(JrU{IlX8LGTA5Y`x!;ro}s+e zRijA29J_+Pu&01pB$>7DJ2vNtbd{za=4X%OM@>6J?h_XJoXWH%QOqs@ z>7zfi*096ET%AT@5>%yOUQQ-o6xAnT+y7W#kE4@iB_gNaB;r`1&qT1urcMs z`Cq0Te&*~*LN7P~Jyr|4U9UH6eS2`6Zx)aHo6|R}KzZMp!eyufdlqj`fdk1A z`m}&l3XYNU&aZ%v?U?nd;DF{sSU=ha7jKh`Ie5AM@u^Rc{jq?&^n?0E@AIJyvxA=b zfi-B&d?jp{8_a<5|ENB#z-xMtcbM8H2tvd}5YZZzz=r+NM^M`3@H?^X`IE?WPuW6c z^17%l1-%P~0Nk3oP36S=Y{2pK&k`*lm@%L0ofHj=&Of#K;_%Yep(%GB4bEfERH zJSo0AyNjsMGa*}aP1}e*RUbdPgMCFUu74(Iv2J*_F<=8eFbz&MA%Tx!Dv(g_&>TSC zUm0HB*v(^Q%5})P2t+M+0x;xu&%g=DzON0EwO{#!J?8K5>Bvac(jUQ>ff!fWM z&*0x;Kf`G485HN$3gi)Z1whIwTXIcFl$8y{sG3Ch9r7K3UXY!|alIm!b-vC{X^Mej zf^b>)Oskr>bPA~pw+ZOQ=TyqbunRJ+TgR<;&N|B)TCxbb=Jq#`bkzhH#L%hin<>6C zxm}TF*G+3I#fKLa7+;MiN`vGv4`W?yx-ZV?R(X62z@9&=4c%M*#dDQy`bRyYlJk zegd4E6RI$e(a0+qGhz&zodx2@Pq+tN!tRUg64V0!@;2=X_YVAODk zst)eCnsTZ0X+fx$xxV(iyaUgec)rfw^`uDL$0-mbeAU%=UNvKq)kUEA%Qp|{ZUFcs z@lwq+*xp%xy#4iOShatpl%oH4(DP*)FSYYFUSt94dQdSzaU>Ofr}1*Pw1$_!NxaEXXVFkq_}4+ zm*hFJ8*+BIAesP(hbKTygl7G(U97ly#cE9^IvF2+lvW)@ap<4kXa;~sDS(`Kmj|5H zuvRIu%eyH+C)loz9;qHRVzO=UKTZ8KO7b8@1NcFQOr~ouFUc&9bwOqP+0*BDZXJq4 z;>uw~FTl>1!lUN$EyMCurmrEY=X-G^f)67D`O@thHk35u^jsATF%Dr7u`0)z+JUGJs{(N zLHE}_V?r+R7|8ERgZt-!YxAed%y#5miU$IcKY32;K-C12taUt~<0Ok-mu@{AyvgDWAVCOnD9*JGZ#(*DjbSp)jbpmawCuQa2MbW9z z1OmyYal(1jyaxOFsqZF^KKznJsuiM$qz>A2~>7yEG5m#e~lg5*!F>OXanwz7n; z&L#rL$wMX8JbGf!ajS1cHhz^*&B+dI$Zv**l99Ed=Z}m8T9)Q(zxt%gzr&1mG=z^D z9z1zp*yyQ5?0NJt3)fRsWIJ0 z+reOy$igGfHf|uF^G9se$vqVUzMhQQp?x?q@o9-q3rf8rfpa>gvbbbFHD%2DZb-(F zB7uAkH{}}|;6qS;aK%nH81QwxKyBa_8Ag#;Nml3a%e)XDF8^-JGe)~-cRcD_$DYJE ztvCB{IQhy_`>O#-(zo3 z=(49y`XN#MC(`*th3P12d3*D>AMZvR2R8Wu&6NF-+hnA*0>NWiG*b3dg^gK)QVjz* z14rd$_ahUTO}n5vtwKfRRXrqE3hxcv(Z#p%;r}-?*N37rh7=($u&n%4JxX)Gl9BHh z7NXmOt(2EnnioqaZoul8$_)ARFiuH|1+_=+D6yPfHwaW~FzU_cQuvALZ$V zj&38?@pN1OrBDp=1UJ>Nhc5FzO6V4js;2(n{-4g408TY_i|3RnTDMPeu8uv_j^M6E zdYXZ)n_2jkiixR{T7<#Sm4;<$i2f244g)^~PTqLV5e~T8avXVJ$XM#0+>cr=o5(?m zlL0kM8@K3yu0r)N8MncDu1YGUNEgM?N!zNq3FUgd18L#;gzP;rlo^StbLaSk z#Zu&*9-~9lpB6B>DTTLw-Xrbpr%py2Vhmp*Q%Q%~$~er0^pZdz0-)r)f-nwM?}aBXdKx7X0aw#pbha3%P99!!!8pPlPt zWR2cD?Sm2l^oAk0(XNn?fvorr3$8?{E?6NH`&2?Am79+6f#0~Rt4veR-%(}~E=q%> zucY;1}Ad3I3iC(3P0 zAvY)-Z+0}PHWQg>KL^;5z|1o=@l~La8(rF5#Pwk|>Wn~uo~%%yT}?nNRybr?vMD4_ zq^p@LeE432BW&-e*A?vi`5^`A6U8eF738L9{eGKLj-L99GgM|I%49T25Um0u;z7PM z6zTmdb{f*Q@_px&RF{sfPTxr*c6Ff3*Q8lOnx^4fvstiz8z%hlXY#5LW;E7vz*A{S z7jsBp!vEhqpso3Wjz86RUN0S$4v&sJ=tgEJk;asQq4phMNY|%UPbNY@5OkaRob@q~ zUs)kB>a(te7kTw!4*Kjf&vKJtG%s;MTllonp>nl^H`X>yk5;s{@h@O}qo;b}*UgbQ zZ4<_%)v5EfwoAa8fmGjk5F6NY^j#QPUs#rW>*HONq+4+WEA)Y@NIcP`zg$k5*~ImB(o-!Zmy(D77@vWvV$t5f ze|4v;9Kk^#oZ21GE%J=22SGTg!5)tfmHlr;k@|sSs7#c=I{c)l6ba9sqpTCS(Bz0& zmXZhxCEjpJ$nT0xh1H3?g^z6}$y7PT#+tn}ibFv+lE?eqN_+hha#D6Ap9;K|oc%+| z223C2gFPcZ#d+lC`*w3nfQ&n%X^V_77uk zbN`RCb6n1a=@wvY+qP|U2Rr7DZQHhO+qP}n))U*wdB0mY7cl>3s#Z<)>ZZVwr>SC0 z1WlvBQeLo0@g?;y+;0;T+!(&K`5o3{@9Soj4*ST}(lC6*zm|do?}0c!sSW?)wH8{p z^;%b&Uw+JUY@+tWKLANJE|pm5vpJxGdO0UP%U5^m!`X4uQt3X^5`zO1vzu}MUG`Y8 zYWc1v9#B#W0{Y5|4_qrEl7@!bN5KV$unEIu7-l5lf{~?d$NAWN^wa~IcCsfHeF?qp z>ywx1jx89w*txFdsLrxw{%X&nPjcz~9;GSlcNC6>>J`#~rX}4&bX)H_s%d&Y(?Z!epk*yr_CXZ^a2X46xoSGz*{jY3S z&VkRlAb&BYb{%~BC+9f3yW5-&P@CA3U20j&=RQVlE1`!Dpuqk*ua@3QL&N)( zHTRce9Fe7Y)X?K~zGX!aLb|D%I_`0Z3fdxxq~I&;hzxW7LT0m}a}+{xipp{GmU!#b z%%otQW!T+oDm|>viVhA|vD%!aeX?)mMY~MyT!ZzOZG?8*VZ6~MWMj#Ew#($vVIVA< zu3&&VK0XqeIaD!H?ja7-&PJPKa7WRF_9l8h!T+6I@_;yxFW7l~Sx#vL_d&mXb;fTs z8SGX%X^yObo^L={_|C5tzr_mOb2pcx{x^}~a?t%b<3%pXJdGdJ_!R$E*lYEGp-lq{ zG4_5dT2I&Gs1owh)$zX2MbYZ$cH+|6BYDX^NxqgsxT72o<}7dt6|SZUxa5H|SHq@A zO5GavV2wcxU-U{@+Ki5}>+o)8L`Doc2u#5qT7bUM$mRXp{d}Jo5VZ|8pqBBd`HIxEVBi$ zY?7V$=lZiJV-P;Wm9xOx_+|hAO>t#bDiB34^F)+stQ(;|vs8OkhV=vyUS!?>Nyn1>X`7fkCzlJ|33`8!a`BG+pz4gDT zc{FG%ngDMuhkyf5tpE!;{XY{cT7dw_av6kInIs2aRquS4??V4>BqH%8q_=foUVs)t zmEfZB@zPrRAi^e8+BW%h#H_<_cm;t=T_VE`=md-_kV6t?$-`y6$IW zc(yQD=-*bvv7zBSh8EiYJS?iRGY4l5UB$Jz4&XHbWO{1!zt81u6=Q9nsr^V-jJ4Ii zICg){sd62Uj{!YsxXfyTZB_w0lkVtq=}0c@MO9 z#-kX-l)MY2RVUYTq~M!ib*?0u=FthaQ71iDzM91g#MK zH{Aq2V)RmUyv<%eF42Fq*c7DI$N)*~&E2)n$?D-k+$XnZ^7jCoAk(dl$5nFpu_wb9 z1uylpij*Mvh9`4;DS^+>UR(s*EeOWk4D11>;2K9ik~)n5(1YeZ+!YpBhMaLF_Lc!V zwC$7(v4z&?odX=wue-V`Gh|G5ArC8D{Kev;E>UFgU2|;AP+SG5rkM{QKB(6pZnk{i zfI8DQ6;3ACDbs#R);psw=0CF-DBz{N0z@2XrWKn#%LPeIOiF0*`3lR1Pq~ed-`pQ6 z!N?(3$KO87jix|6rbpOs=yZ?%7xmhnB;f0eA8#&zB<^afC@X~|bi!w^CS!0+*`sT1 zXsE7eM{!nI>AA)twZsZr?=+jfS^p!%?pK7cq3S;0+JeNl-;&hkfw ziKsq38`oGT{r5KO?;g)F0UIYN2G=*HmNS*5X%RCqsLZA1uvAEx{$DA(3T%G+-%ZIK zfit=t95>M{USyB~XRd>BrcH|>tu;)#sD7#Z;l6%5OoD=8gIwZM4hPFt*GW2eq16?6 zv!a4b5^Eg1TKgztpVS{Ist&ZWuSYoC`xQ=7iikJ)<9 zx7U;$ajI)>t}9=t1m&%i6NU%M`u1Rns%&}lQyH_zGc|DoZJz-%3^=}W8BAT!H}2U9 z)8*@mXqowcCpc8UT-(Z&*T!sIpB6fKv@O0G1yZ8hFGT_BON0_MkocnmEJd3=V*(9K z(`Fg6sa4oT)$>gHS@*!qu72GLfa)O0G z0bPs=Y|lr3D9s4>Y2DqNj+t2Z$KH|bP+@K&n>77Y(@Kw7{ScSS=%J|U@m^rDo;q80 z2A^ScEDZvcq=aX`W$r$)-A5D^Wrc+zjqxENOAi#}Jud?L{C<^yiFx_v^V2|3kW!AQ zrf8pXE2wz*e)2HJRUEu%bB{B%3ziCr9{K#q&js)Yp9G5$xQmwzt^4f-#T=OkzZ4}< zBjX2IZU{SN2;1#Lq}NJ=xgeboMnvLNMQ5U`qF#Rx7B)r6W5rDP@q1 zQ;v2s^Rzrzp3=+Sj@UMGImBZ@Rirm%Sf#Y)83O)#1;w#QMJmVvWx}*7;L*Op2&gO# zNBw6*D-QmIF-4;#@7CVq!cQ!KO?VKeA_Ok3!#K3nppB1PBb2>)*H|L9Xm$->8{Xoz zBTuOuZgp#B3vLfbpt@^O3U0-)kU9G{N0pfiCVH@`x+JLdw$p$)Q}%PRb-NhBK%v7Z z|DCyjd){aV1>83KLfFw`KV@G(nGOj~{s%$iZdZ31p4_|jEhoUerAIJse~7_xcQgjr zwSH_a1LrXb3(t{%&v*s?9aCnI)tln`7aeTLCZZrtGeo z3xT=bsE<$w%veu)do(3s(2Kho+HE)fyTpy3!6)CY?Y)e)3sS}0ML4cNLAUbS*LY3* zlo+FkH5o$aE$DQZpHo7E*>&hq4Z-}+9Ma}El$FpB>JCB(Ha+rZY2&9l_Xapb9dqlN z;9bAk7S=9aF9*Hc>>DP+>~dS{3W&q|n9(&ioPhHv|17rdQpbvn`SLC|zQ^EP;ftLmNwI41xok)8J!g%^M z3!!=Km_Xp2FJtH0`if|=%SoK72t4i>6EW8UYCr;8i+%8;Wi?NAomNyB5MtRxRgZY* zmQe8R=CnVM!!)bnp(&0!tdBI$7z5Qt^vHn?S~ED_)3=u;jxu>6&>5A$YvtVwzp;IK zOEUlo_FM(?2`n?L3fNNf?Fzev;!l_j)m^b%?`%=lP5d+i+>3@u0x_gVCZFDhp|T6E zRX)1-u~x4=?+v}!U9!Y=8b_$VIMeP8c$=;7_`0G#fPPySKabHmWK(E_qaZBX+$-lP zX$<07>OW?TGxM{~HOh2^^P}CcxP9xfEsP7pXJAO&sw}F!_9CH=;;GVQTchjkQ$7Ls zW$|@qKEgWJaM_SE#%e-YFdVCJ+M7fFBI-DTFZKe)tSrsStFF^6J|;iLWQrk7Q0Aj- zWaDlwR*&!kSAgVV8S%cE+l|4Im3tyGWr|t4M7DKMTP(>|$!b@wn!U@-dER&MtNrqi ze-ML}o#6LUdTDg3kACT|!gv<#FF_9++`zhDM135JBPp!!ZHAXzOi=k0_^H5V5Rpy8 zt*BXrVlw5*aY0vPNl{f8-9O2(rP};)m9hSA7;NY}v5G~IR)YP923>PV+WB*UsV*pi zy^3JUYvog+de zbP6j*LFnP7w&(hn)%>Spa};rp@lB(paUL6`P;^^S&|DX0GIr{HK5qdHspaD&77$>Hk8VtH|5qA z{34)SVf6_f4*FFD*l_GVf~W+Aq)ef&rNY|IV1*RFpC==WXM2P!hJr>h$Oro(M9%*a zlbDGbjecf3R*OoQmwv6>IX|drln{1p!q)3KKad)Gi--S3b(D@E)-<(tb3&HEhupa{ z&F$*I|0Aud^Zig{{nElQh=tZp>W?1-j~{{66T7!1}w5e%nfj@qHi50;n2NSzp0=Z2Ry-HcBK!v2USfG@M`6uRhY3n8|s-@{w zN*3MUPMno_k$yTiHVdqA@Q`fU+c+=hSW=s5mO|1Wv+#ETH#Sxp6YC7>6R47UxW18# zrHRo<#iR?E)`ZBr?3{cP8*Eh*FRc7~4}meiXry9--}!mvXN)T=0!?j|*`uV@sDQ2a zBHA|%6y1IDjI6yZJ(wGYh4Xz;)FG8XKn)u9 z`MFF10U@?0jr)E3^Jk3xEgKsX_H1DqkB)6Uy8R^0A-(xUu3KBC_mJ27Pax(6iA*FF z*7GO7j1ez0KmLN2>PY12xfi;l?~Y%DUNF1PADaZ>%DS>Je|dbpFst&voE20(R6!bM zyZk>vnVPrm6z3s!)Y%;B^Cg68Odyi#TA;JxzyZ)-C&@$2TaQpv%-zyFfvUx?_>kMi z$PgH;+-jC4!&|MUz4~Jqj0A1vwajIv0vMZ=9 zXf#7b4p8;u8GDrxsztyM^^&E=#FMBEaNrCYcsgkhb`}Pvw>{B2`_?7)cD=#!`R;dE z6R@=uclq2s-;jK%KOfg19H%Z<{7YOx9?l0g!d>#L2Rgnj^@zp4{&^qzfHc-S89w@6 zrZsYpcGMqq4~&HFTzvTIr59f)K1UVeU^-8jus>mmy0EF+QFZ@#i}HH!xtXD)+t6ws zS)&mt9vEAg;23VKT2Kf^ceu243aENO!nHzxH{vNAyYCZ6D)$r`TH}$BR7}UGCy&wpxK{%bzJQ0LYh|;O(>|6Gc_@JHVN8~lnZMmBgRb7L~2THxFd=F zZ!I=Hv|KzaL7%9=paXUDe7dN>-cNZHhJ3UEAaB_{y@;~iqKaLuD>hH6*1?C{vNQ5I z+*NWq8=FKPRhSC$qmhe>giQ>+lZB)UEBM~dm?tZcQmko|%Zt7co|n%pw2J89&^X3g z)n}}j9w?T?bvaF2fQIV=hm3?Y9U4kgbZFXFK!>9Z=#Aees|M@q%)U7)kx;QllT)f| zb9y>IjQIIfOm@G!f%4a(9K+)AUuJNdm6tn)rt`pcXP1Cv5F@Kj`xyYAN>E086`ah7 zjsi9LLU|sgPNGpfHU-MdyMsQcVfo$Aq{2nyLG<(yo@H)DYiVYc>SRPbTPWAN{GHfH z8AkSmr?*NcWLoniYZqy7s4EQmfo$Wx(4Rb@I~7PnlMKQx__ioo{&m2Iyt z1FhM8{-QaSE+{Z*<56lYuSce1FBs`rp|Fa)7$Z*L5F?w8E(V)hiyJf|u#}QbB$kvj z!x_N^i47BNtxNo~R%SCfTzJg>PuZOPI`nz(+x_}=%l-Q)c=n@z{>}xN3w(z&cn+9Z zXU>_xpQ1)@J^h>4{KpF>5%%sJcC5R5=h@L6P@{ikn3ngNh*#S}-pscCF?sS2Ejk-6ru=8TirM@yO3u84-%L z##2i`+0HOheEGhu^i%ysSY==I@c;uBjH$#y)7^|@IQV^503^JXVr`fVT77Pvdw+Vb zZ+1;MEoCrAET@R`eFdRDxWm+k#PJx{k#5iP3YB!vw~f@465Zw3gltKE8zqSoN* zOBLXkF!+2Mz~TOoGN&`iDhpB-ay)7*Kl7d)wh_x{U5s9>>h@93Jtj2&#DD*!UCo}h zkF6+!046bw-_rjDADcYGWTK}hUyA}iCkTNH&B<`tEH@f)d;<;Z(0$*Di&`@hDzli; z(_vsGHe^>>d7R6~kJbULBVc<|SM+!iT^iMSy0jBe6;$V0916rj#jV;eX0i&HpqfWs z#FwrWgAyVLk*;$Sp44!)Fhe^xWE1V@}uz>PFBrk8XHW z!AJR^71e4Ex-FNLnuU!!9r8XZfg4~SKOa`80}KGS463}N38QI4&Ukyhy})aRLsoD2 zxF_%)oh^|mXJR&NIN$Wd-jMj3L`+-^7bcp=7PAIL?qm0!pWtdqN`#G9Vx2Y#K9Z%b z1!gg>MlZ1NPe~iimu!Dv0@R~dsQ4{GsHgM$o5fe~-oIl7q8W37SROe~GXQE#hy1$RDt2axg42(Y6>kfTddU^CK0euDv3kPUd}s zb&{bQ;1C=f+F>a^L)k?^SH=)GJNu1X+dQ3A=GLc%Z=dQKA7X=*f*4d)msfFc#qarm zHo5i`-6yq`@o8UMg)+ zWy+ZkFMe9H95aS?8xt*pa4SyC1( zpnXg7!iXI}3nWa>vbWKpR@UoLPW(mWsJ62s`gtN7fVmZ|@L9fHn>1sEr3T>Tb9i)% z>qcS~#4u%n;&nD1yd{~#L#+^Bx+Oc#eShz3up(Ed1M**T4|x^m55+USzDB_q*0%YyCqo>0G3=iYY^8a(y=9E=EyP(6V$ zda&~Y$ZwlYWvBv$%^t7E(?AO##?38OLz}E7JPbG1lBGuw{V{<;1eS1n#h)~5e+N_7 z5O^+IeVM1H*b(4)S5ByLUZsswRAWO1*iWOfV_o6``7LsRitW@t~#eJnBWN?*nIj5#S*#kiuzNf7VTcei=v&)O}e$X zZGB^x9`44l{5A&hBijCFy(!J{x2+ld&o;X7`P1TWP^!||AprU4gHdVa_o4a+;(scv zJO+5%`u_yu)H44s6&44F1k3+qSj-}v65<@}oZMXO68}?SU3HtODBCnMNGBDNP=OSp zAp>9FixtC=EP{~<`TH+=!IKw+hZ7O~fviv}4o12_f)X!&MG=v_AQLJEE8cs%_L)8H zGWuF3i(|1h_n0Xib`Wp$_O_fK)e7U*HCn4E}X z#*-ap+aEX;sXv!Lk8dM$(Fo8Jzww^|9IPn@3;=;gcT<4dZLOTshs)9F!gW z=B>+_STBQXEED8Ha7uI#j0;E4%cZ(c9V43ueljq0X?-H=x#{!3@o63sN@N#V@v=0T z@sr(;U*D&43d#9$1M8dK*uPRLs@K5bRa69oiyxO1hwQ{%x{gAAjrBW2(Y<1+s@T$9 zZhLLMjYvZ%EB42`N%0KSAQZTQoX$Cq1H*+fGW(F&xRhU?pfNb#&z&&|2`E-4Cy#Pi z(A_JDWtSf?TyBlHwUP#$a7*l2{!O{OvsWcV!#1Wp6(}wn6+@>TJl}@Oo!K)){Sx98 z@_@1OZVTY~X{L}I6(dV00eB%c1 ztQdcTm0wT6ERTyO@xcg~@SC}`lvTC42=%==^Kp{YO%Au6JCk*PA}5^6o+^(mhw>cU zpaWD8pPxbCck)n6Jg$lG!^-rop}AyH?TIXGf+y%y1VYqSR%1GUDRuuM8W6MdTM#R^ z$`aq~YEn(%&r-kBimz)CQYsNsVHG|4E~vTGFYrj2B!3&Z!}k3ZrD4#dM-0|d;`gzh zW?nsc$Gs*?j73+XVq$jFIL0{7Em;1oxGKJ6f=1*H<&!@UB}Vq_?k-uu(A!H!Pq7$^ zFF?rO!fgcqIm$W+Pu3FG#-K&c?Qus&jM0NNK96>8obgp=pY)rggKW2Pxj!@8m4}j;^<79zTjLpR)btog zVcrswEa%LcU|*AVQwlzEik!b7&f1XQ233x6(UBtwOOe$x_L`XEdz7*A0f7YMo_Di> zhzwp2Fff*T#ckh+O%)6{eI+1HEat7-ZA7n4W0%@Zq7|jteH3P&JiByBRkZ08o=RW1 zvkW8%0^S8p-z9yhGy8kI2PMjEm}iV%lo+%+Kg?gHA)RbCwM1y|fIqRKo~wNNlS^h; z9ridf@Bflx5vW^xq57O;T)SDA8i_clIs{6y2aDm`=c$3GopZ*Vh@OBt>)eLSx6ZnA z4$r;JYP;&TkkORdCO-Z&LsD0Thrju%S<;W1>Qi2#C+91e)_$5uj0r=zdnVx%lfE*8 zH4;hPCD!LSj9hPt=0z1(liO|SHigq;D&TXf zaMyqYq|{#w>q90Nb^bLuTX&zu{dU7XNfho04g`D5FXoopuXaX`B4i}vf6T0`0h!o> zOpE)thR!F=SbmG2Kw_rN?;a*ic2l|?HhS7wyXcW{|FKj^Z{NMbdfBz3s00_*yFQ#= zJ#z#5%ceG%16AB<-ov~y-E2n;guHBYuo=;jg#32WZu1*<ewBB+OYaK)$s(F##@ZZbGvtKCXw&h=&>N zmH{>Abeaco<&-2*5knd=uUkjY>D`jxfYLR5(LU`XyL2+H-cgUX)DL}w1xZcyT?Q&tvDBr3KuOqH- z3|R_G_(m%R9}_k92Vy;46F1{P{(v0~)2&MG!ve{;IVN0c0O-8;DXdM{U32ss19cDo zz(YkoDY02l-ud(k+NV-7>WdJ}jck}Dh{FMHEgI*E z$fS2h1=VqKKWMN|UDO$-C&#wws=ODlps?BpdxKeZiQFV<4pMXdYvJ!JtYYQF4!j7| zpdc7k;`@K!d5g3rr|&QTn{q(G(fPPN16=f^V^ieIKXO=783Mq1q3~CL#0cr7w!b(b z9O-tITsN!k&<12h!JXbjQG9a43?OwtwHfUD({kLXc*l|K;~xIVYAw>e9SCR=ZBndm zdX79mB>BZkS)7?9HFN?}lhCr3))?!82W68~8X@)lYoJ#j0}Pt_g&`1Mad)>{ABpNM z8al>1?F_X&VZ3(EMk$>HIN8qEu1>cH?}VLZ&-SD=WGXiU-UHvCvE_S)rvO!hF9+$d z=f{6nv=vi@zoP97r+c)Go^tfjdeOgA;Pz3nP)E$h*JZ0jm|>OQ5T*SiwZlpl$d*@W`TAs>x!AG~yB)f(C2exD!qCns zbtupdHjB)ZbJ=y*e|^U^ev+(~cK2UuCz{8uZC>AUe=>G@+IuZMi<&AXa1k)IhN zwBT!0f9LJIey5FLVwF_>f9JSLs)wiaGum6Pv*K^?V0DNnXO(eYRhsYyaR;U) zkr2IdA0k7~$)p`fCCoB^D zfbC`xLvBo|bJBEO#x-><2N=ERLP z2iIW8+WPR|%WH7FJm?{M(ffgLS1TMvfc!b(pA^j!6{}mRhAKB}&rd8CMwitl$0?zf zP`&#YyNMgJHs(Aa3vL@Bj7Z3&mvyh){|LB)EB}~EzUK1^9D5W(xF}5_=pN_z$Tul< zcJtc~B}x{=^bE@X>vHndHaF-?1rK%aUGy_zofSFb|3Wi1MZyo~NV_CRrfiVQ~jkTtMP-hYcvBt+G_ zc9(;uCw-@{Byvxr796YoEEg1wm)4!CcVbJ0t1%V&jIY%{ zPJAjGx@AO}Bg&Weq~>gm%LvD#XSyL;q3khRpx7%_oUmV%F+s|H8TZ-rlNw;qA=f-A zp)F3Z&HTFRw(gxb@8bQQvqD^sqnD1K^iCykD9Wr=Gas(|1GvBKA#)PW#-wFCjo{Px zi*DFPwkOj}CKL@C2sdvXvApX(Up87i=&|W3dRdhaudc(^f7ZRWUX*k;=ra^}c2 z?4JRL^CKn|)vryB-|zraBMs=sQR+nT%e=({#;Z;;x+}tu=&=Rkr}~z`xehD}efR~S zz2y9armfPT8=~atM1#|DDvla12YGqIQ7anGyGUm@IeM)^XMN|X(Y?pT8mNC^Lq(R~ z&uP27J#YV|d#F22h|UX=A(F}cBVg>L1vc|_>2{4pzIMCst%<{ITn6esSzZugg{4z6 zR%O5v{=G7Z+7!y4LUdm^k=RIJ5oHx=sWF$jS9P<(MlDxlYWRvu3|D|zhM^)8?v*6;)gVF~8uL!*R5tjAWCemM9scp<(J=zT90g_Sn3~%jrGPwrreH@eM zC9FbkXy1r+@8-G=y8d}jq*Tek3A`Gr^!cCT*Q!H}-8}sSJ|{h$c)8r@L$2E#7fXIH zL@n-73-b=BsISxMhp)_5Xfiv`F7&_MhE>*3JUkCVxSbjC{O4Pt2OpeH*COmz-4+w& zC!KlK-9Y_t@KI#$j5+>IT7@c00Fpma3_`^`myf}K?w)|K^Ed-ev(O6rbgGG42PJiAD3Yv)@BB-V4}lH*nheiF;3i4yCP5LvwHk5wbP zZg9{N<|OVf+vtoDZ|c}W@;38g&rMpIzX?{~7$nn1N2E|3bGU%sgEB64c8iHUjgcsq zC;+X9KD5(zubK0ELEFm+bN?LPfc{cOlnmF|=>)b4Lf8vRQW360U7ZgS)|Hh&39t%u zq?u&U+{|fnFGX(r#R)l+z`w-R-Uv1j!t(Za!gzbbw0)1=tzPg*7+7Zt*r@x#a9J`J zC?B||u-witiGPH%Z8;DiPbC^1fSQkW+u@QP^r@S0|I22 zs$&mzoJZ;S$Efx4p|8{#9(zHwhx3$uM%?27Jk+j1Z5JY3ZDtg&noC+BH(YTSmrGT$ z6GkwWug>vNAGG%=%VdP*bW$oygCOrK@tMiB7*E=|!&O5g^CIP~Z4++94u-tSax#Xh z*)ojF%0x+sfQ+1*Sz!WMk|OU|FY}YjN@=YK&fV3oyK_bT!7*;X`q1LZh;aVU zv3vZp_AozfLY&+u>Bx~DF!e-1U9MA)?&fh0CRCwRl9%pJFigRe?KRR%CKS; zZFv8w7dZ@tRC~pgnVsIV{BphJAj~*XOTT$}W^^BDXbEV+ugE2Ruu_7DM#mA%3LUTF6;2F}-pEpab0Gd&1g+fylHLbp5jBg_C(70E;` z7Zy+fK42X^kH9J&oc2et8^@o)MezxfFR_3iXAMM3CWYhdvXApsQ+!P!SjC9c3`wo~neVIQ(mQHUKZW$|_MO!V9BgvA2JaVUMubymwV-Z&fEiGj?N|&&zvN z0ifvy>!ocm@fg>SS#zrjyc#CzO+}KGOd}VwrWoyk7|vUMJWTZfHAOVwD({hem;t+GODs5Z>_*E(~pGBm9!7jFD;vzpst+^x1wSY;xs0JIh_vw_0OQ@O#eG9 zz_-Jl5Qn13_xr3gew#Shzq+FD151z)e*evK7H>wqG=TQ}X%<|HL zpT;_)va2S>e{Zk<-YoD7!998!>F=9-lCqfm$e*VOyu5$1BhHT9Gvmn?MbPNW65U^{ zV{sg{<~`ck+L^2p#Hg8zSLe%<72=raE=S%&5d*9TfOOLwO^vl(JiGoyF8BF{fAZFym- zBPEq8&We$OWgD_Cz`vqOgF+wWBzRx@ME=IVo|$2w7Qbu5ky!pK9lC<7n@sKOt%p9D zNbf;|h=X`tMkLdBg&l2J*~9k_O%LQh2x zIV@)jzSq(C5V#4W&dFM1nL$`>Y6z`ZAhB=9#;TN@__HljL!Ifjl!Np6-YcUY8OVG_ zpPgZ6qM_EJF+kYp;B$KzGc9EgTTtr(3d1;jqYoev!k`p7QlDvLoS zCdW85DL4dzQ$u2K|3!-a#!Sc39C!*pW5P9PKjS{qR23`M6C7ZvjWwYWDXcmYN2q4} zyFv1H+=4;^-TZk2g&1-Zh%dLNAdjjgHDEODiT& zj8k^#t+t1<0BG9}v|gdrzb+yi+;pK_(dU@YHP=UK>fWgx_YAp33dPC z{OkC_)IjuZfjR52Pq~RGa{P}0(L+EHV^lj1-N=hKZXY87fhTj3Gzy91x4hFG;9=qK zn`T$e=ciwZPn|dWH78h6&%lXu^{0z+{=#b zKYlo0g780n8~NrUGACCU7+%36hLq6f0))>OxC-i=FB%sZejm^r1t_ua8ONRsBN}2E z@-?!POHQAKIx=x*n$Z9nL8CwZ8Hjt$33Kaf# z*mPZJzTE)Ej}1?cO7k^W;`;`n=`IXL5^E)5@+Repjk|pbc6M`1<7KDlN)3XoDL1G4wk|7|S?_GuPcxJj$teGAEroG@hT&>u_Z z+@?eZef$LmFN#IRn^&HNJjmf(4zLnhoBmvZ>Cj&@v1Iho0~?85PbK`ogOYyTS(=cB z(e#++^V?c^NgQ4UO+My_8P^hNA26#C= zBk9j=6TK+$NLp+<8lvD1WJ9i*ai6B z%@U11w}cecTkxGxco&%vCW9HFd=crXxczW^=pGUIdVP^0Z)8cc?y=tXQZ`rrNft4u z(e-h>^tQaYVQ1i1pZsURPs&HS;Ks(TU`gbEH|WqGglDw%OPGdM+mn3gy9H=eJJ@s? zngus*RmpKQL}5>Ekj0^^613gS*XJCX&>|rU_EZW<_Pv`uZBA_^Mg1I)QH)_P&QpF6 z+MYnuTkOjd2z`#W23o1d#AHb5{!}hH<&aBZy8B}@KzDJWZ}b_Jh8v7OG)q~Oo+&eZ z9w1`#wlT4F?V47X8nBm6QqiAGQBh82VU+sTtNGfd-$8uETpTPOBZQInQuB*K6u$?a z^$Rk)i!xS@%<~lPRSWT;U5u3z|1T__EEGC0`4@?*(7ZzSh)3?%BRsS7Wd?T^XSvfOCOi z>l<4Z*0qb>wK?t&SS#qH91t$_eq5}uK^HrIidA!)l8~vy;)^0j4Zdn{m~|{>ywwYR zrvOH#u@J9~-M{ozJSLcc*BgVNgEdc*xxH;wCG4Rd7OL45Z;oKuGnWwqA&$Szhz;N+#_n_pIW{3n*8hp-(9aLG)mOi( zYm4nHec*cfmbJ-z^6`-s_*$?A&w=kJ>55yUa(HMmwe9u<&XstPZn1m48{9Kul5*hp zQ;Eu&ASw|LF7Uzd`uuZZk9${d$(QVD3ui*^NUQcOrg150j2UrB$g9P!@TJN9atsS`C%klQ@sP6|59Ga*<4jA_$f)q(5 zaa;#S(<-tC4|SD(3&Nb0D1*mOQJ@IC`H@)a*z!P*yJKSHcdOI z;Q0eO+bpeKDf(tlYtVCnjvF<>ujzaIh_1W*m+`wP&yFh6hs(>rO0I6;4MrDgj#=q5 zm-=ZJR2lVMUO5-)%!zl}jh(3v6I_Wg41FE8hsn985Aq5~U8fPW<=f(938Pgq5i)Gn zWl@Ft9&hvC@&I^!c+X5HC{nO+n!P)Ctl*D)knpzXg2^tWQ4!VWHNWkND?7|Y_Y~?g zpX9@l8T;E-wYU?RbpYehEdjmwHc%=xdH(C0RS(Hp=#O&1va?FvuWQ*EUoj$t0cup1I)_Hu0Y7Kd~MLZ z;Vv8}9x8@C=ekPw+FqCKMgwiy>gB~2Lmr~Y0ZTp3;hw?TPvo`05#-JSn3eEt9_1T9 z5J}PNV3qD(Cc-W2U(Wzky%>WuJwiE@{8@i}xNMl#K7cx30Y{ZXlN^H#(Kq%{jXHaP zA3Yreic-xMCIf5UMw}`32mtT8P6*UwY(^-aanyMxzqDp$LU->bw%565+Mv4ri=Jj_ zhpZOMs4Xy#y5t%;meYPJnn7;Rxw^AX);S+Uno4GDY@>L>`wY#IM#CC{L*b?bh=Y{stv2G8-mKVZ{-Em_oE$) zKjUj|#<>iyzx%y}!~VtH0CxGpjTi=wuQ!MJxQog6lJ ztM{kp8H>OpH9ZZ0{KL^=E?v%2u&_p}nKTfPcWajsB7TV6n8O8UuOJ40- z75&3?cjDA)o)P7TElSLD9X$j3>$C9`GHK~&d51*i`9sbnNm5#(LHL8z*X!Rq(LE|U z4`(_lUg`(j&(;I3Do$eT!(oVds(TIgby0^>a=97oVK#a34vn`K&bYfgP+PP>S;v`( zi@m-<)<}55q{fYRj4w5Ic=4<@7C!(JT)2NR&x{~B-SpQ8g}!Q7$rtsjHCYT%85Q7~ zpr*WgQ$8&$)8qX)y&4;>rc6Z@aN#~*$=3*Pe;z)6mM0P@XDl(W= zFrtWkFg9hY=MVKO_mx08_Ic`0g8M5_@O5QT4(CIt^Av|lC@23O`j^rUhY#8R39(%Q zeD)05QA+;N*ZhX^<}0xq$$0bf%_D(VMN_mX40)iurr6-6H?%oBx4FJunxY9W#!W?9k^5V2>JAm1lqGq#h0(sqSO-jM*-9jfqR9PaUya=7_oo^v&A%0f<(eGS?YT<@! z@x7!q`zQ12-o^mIYP4)_Pri5~nwuGqWqma@PtkzdC1-c0?g3e}m7p?KNMYA%e64?I zxE|0dP!YR+#w_P*F})H=LIZpB=0-y=&#kRrxu`L^wbch8&~{2 zUF0=}Y}|H7u?`e(8xBLG*X{hLL?j9JXHKg4o&M+K<_}|#vF>wGm&czGp`>+Mo-DQ?f$zn3VB%D(vJ{4>dT`fJFM@Q2LG{LEB#@KUfxr7224H#W#=LNHQlrz>^2o0 zhX!Vzi}4jnv3_BhTEUFM>g&P*LAL2{Fb2Jomuo7G2$Pv_1vq!#uY?gWdOka;uc7%i zK0~5AD;rEC#8$~JGAbcWuLO6;@E|VYjJ4?J4K90LqOxmn?JRXRD9(hB8B=hz`-f_S zr`8)Pg~^RlQ=2$=n%%G5DRs5O(>t@OM|9Ni!2?+d^(Yiv{fj`G2&m?lUD@eRY9ZX$$RZiY)&TOGw9HI4jL?5WycVjJX8q{;41!i)6+x+z z>K|hjtZH@#AzjOT71?``lI`-2WqxjVt+WM^BsHiwjk7erY>LT~OG&YH&-EQYdfY6Y zJ@?ElR`h3Y$w zo5Er`lsNHG;Rtd$W^2O-ZqAL0qV^JlwXjFOUNa{cqYXOu!WVd1ZP?S5B|X|zql_jU?B@GjD%aOj?lmFa4D?M=3S zc2-na5J9ZY9Akj52HL~lwOul-UzGDvxz*elwoMjCIgt7KQgK&r*6Kh5uPVo8xDGDDrb>F#32K|XGVINRW2y- z6YO&fYlPB2jqQjx7$S{+NQ zV5AhMzm5kEWd;NVfy9c$4j%TW%o^JOK4Es!TL3ii?Rm0^fPvDrJ#KzlNo+qUc! zF6@g7lqQ|IOu6YHFKAPa&nw9$ZnwB#piKUn*J|?~7twcA<*d5g=&IH$RFA)Gy&R)E zCC1XhQn~=GrWXfl4wb^XJLEBA#G;JU>C2@+Pwr@?~q9DQsXihE+x> zhru|<^`J1BW36!^q01^8OuiN2+`Kg{GyzAuZ&9%6z#{ z?}i!$!8f3o5$Pk$Sm%qeH^#Bu^`xK+u6l+21WZB-68UoN;Jva?e&=I-r}a%Kk#DUD zotaXu`n>{Fn&}rw>Hu?Ic!@qK=wTwzekB+K-ZeIKkbF@~Pkw+{nYT*A~PdKOCAvi$j#2Eh{eu zU5j;pPrkHPGJh~A6`a6}KPtbn*FdkzSVW)uiI&=`0UUlDA4$JwAtJC#2f|Ezw3`U0 zFdf*IZrg&N4*ZP?@Kda^r=IOsVg&@-Pv5~J7$DP)gyqV4Zg=g@(ex=}mVs|d{R?;T zJV-lcyr^d&YKr-u{HnK5enkYs5`4ZYx{TtxA8D{H;!@5B?VFae*>bc0jQC_6cBYQI zfvDbw;@$;a^R5c3tN;DYPKn`KDp*p(J_>UzOLv483^=Gh6Pl6HTrvOEq07o)PNDkH>pRzR)6vZR zM4)f|bzDtrntNWOwR}_VCf2GNXL@AIbJjmED5Tqs=2mgHxx))%xJzdO)9iix!+XTv zrQ2^Be{E!#f{Ky1r-s-s~~U{oJaq9@&4E2YZ4PUM-I96T5Hi2js=P zb=^KU=E=Brx%55;Upb5`?+;y00m?$fP-ghzOv90SzYtLY@=q#(o35|1*!B3PATm=i z(mp8BP>0C9?=~>^`Hq|Vfi_*gP$u4^}4CJtgghz0M8-G%#95T$Z7C)U1C(sG18R{dC z3#;0o<5oDc%UaJHSH#c>%;*u(*)pf4+;rpG87TUHQA>GCc;{-RTIoGn_S>(<*5 z&P*MrLAmCqk!J};mFM^e>Y(Gx6Nv_sr8-KrK=1j!gT*5x?Q0m(k6HZiZ(k z>GHfhf8>JZlJ&idx(VG$1OhLP_11nB6|t9?6h%Vp7s7HSSeo%YvqkKx@xYnfNFIEt z-R35RfG;nl1y9+kGXG75r^&G8RyLuL`=0o5jsK{fxWMP0)1?7Y{h$$ zzuF19kF3QB7j533D#vBw zGGIQomtk*$!}84wUlSH)a=a9O3Yv$6yzo`4Q2!r%_oEDNbb0eRA03~ZWh# z9%aX2X_qd3svCPaFq*HIL zo|jj!<@1KYsl(!2I06#!yMWEtchcem{RVTum3Xxp;FGhD5!#{pw*FSR2hFDm0-S48 zdn`XK)LMH(E<@RwFCPt3(kK+fgd_~?&ga>?7H{XhmpMk`6}6U~pdH81J=>$Doazj2 z>n%=)^YA&J9!r;^e6_ATZ1NkA))hUHl>-N7LlX6^{n>$dT>2q*-AP)IsvQZNGGRtr z>sN)`ijbuzmrpX(dj8W)7krB=YNyt=eCMI--#-$8=b6qA@Kl`K4t#|j1KzqrGw;w*2flkq)J1JjR>3)%-=G1${cL7@|0OoVPGvYZq3djf zq`5en8cv;AP@Gn$pvy9^&ht8uPOXd*&1@h}I$3QRx$1(uL{^|y6CaAAL>V0u5vDVL zYaa{);i4Pl(1d|zUPK}&0$pCV$(&S-4Uh+v@<@w_)$ zq!ja$_=*$5jN~434%I!MMuSv<%PVJk#;Bdjs&%WUlSea8Z1>dxqM5DY7)z%rRGKGq z2zu5Ic}c8V?*BAsGAB4Ay(*FqLlv0M5jJ;;LAjFBC%^B}gpCX8( zeYq!|K?`9B`%_$q=r-Ru3Ty>nS@~clM-Q&Br5f)(*;Q-PNiYYE&+)!_9n58KZ>hjd zHed`Ew1n-ri)*Ss!AhD?+NHpMCphLvvxb!ML3_J z&vo*n&TUEKBQ#Cw{Fal{U|;QdU1u;WfnicU8@e`>)|G8FHiJY85U9FB!}P@H@?j_+ zUGBJgs@`c6k4yNzG|*yg%Hg#u8R2|Lud}3q8aexByr^u|NcvVv#lV(UXwmPUH|vo2u_gly{(N8Ojw1djVT< zp-F5`JGyvubc+ch&DgjF|07VU!{6eu**c@zdX_Leg2@p%p8;mWPCo1S{uxwbcMCY%Bd+*>gDQB~aKc_GxxIKSp)^q;XK>b-3bJwv=HsL(6`QD=Gn z5kG-Dllu(D0=BI#p2V%CW@KM7^by~w#2PgrIp5zj-kR&=o4dpzg4(N3U~(I@U|Ay~ z@g%?Sri6!lD^pW;{F<0y)H;<{9$8N@GjFh|DtN#mWGe7}Z{ro!>NUi7-0T=0M`{B@H3!R?8+FN8DS>VWt4eY6-YBeon#b-#2yU)x^u@Zq z6@p9aek^$Y)@j;AO;4_7HwWRGq{f`UcB98|GJT|{|7kpf4XcIA7vO%^VBwiaRP3R% zS4E%Us_k{2%GCs+z&hRkme3?rp%y)@wASnbBa z9+v5>XC^gL_owBKr;g2uZYC9n_?4MTjNw{{C^5tR813YpbR_kmE~eU~i?D!_y5{qx zI*?fti*W0#I!%DK*TMEz+^--&JpvJT_8(d1`8fLaBPmi3dOCP~ZGvi>X79@K)51+c zn9_e?BoVoan?Sq7{P;Pu>GHvo2xsnqP}aFa$v)kYh0QE>rKtwS;Cc&1-G^h&-^-%s zU$3QwQ$1}%R-Fg-$$cbtGyB{Ssz$7!C+(HiR7#oM*O~Znq5>JiM=QH|bUwheB}AXE zvnBW4{)p9I&^d51w-%n0+!y4);49=X*q2nA@axR{+h3(T<}U3Z8Ij|%36m@H)6iQU z_`rPxj6X6BN)9d`SF{QeEK?=oms8Gh?Bi9*)}BYXq?cPsl~w zcCT01#r&s%2AgW9kU-VgHK0WMf+wi37@M*YHHN}EBT+cf(T4Lhpq^wSe7i$Jy!$Ew zSPz7^*+32b#DCV*Z@TcC#N-bzAW3u>lrzaXO zeNLl148|nnuF&dp-J#K}eO99Vy4xsCd=_-SCm*I1trvVN;vMhb?7n0hfd5$GB`aVj$Mq~a z?{9Jj%Sq03;6CA+cnugWy2iqOh3~uxuDH$y+dVA-E;{XdgDQJ%$BBq^!+~LRvkG&1 zaexKUMpAPnAm@LS}4Ka`%;kR{9k9h>!ElD|!*lYx$bqhQlsi5wo-PEAj-( zIl=FFI#{7yFaNZrP|5E<>vX`zFvq#=R^ODpa#%Q{uhHAGGe6r{BruRSUhTm*g?x&} zwsb3Lor#eM8`hsS`j&#T?EKR!@L~_~W96~(53!Mf-R`pUWm2AS#1B54P0J0WqlFwF>kM% zCuUI($F!GBwSrqZz*hW4MU26$N=lK z6x6r>!#1MvTmNgzTvEuzP(Spv{O0|M#(Qp_%2qNgAJ1h|Bc*}`oqhdZIUh}6xtA{$gP7t0)9xS9b4ewvupT-DBaYT z3pJS0b+Zs0H3n1()y)_pmu*(F>t{a37j9K@rTO7ww33yN(Q$imp8n^@b!cvT7X!{~ z#r(}`u>G*#scO~%qj&qIYtucDQ*WB{qU#2u6azJkCY&u0FQ)$LC|*N5OEpCZVvZX`pS6jH(X<7RscU^q(5 zMeR_3+tzo42jgM{ct-xI|25{wpXSr5nod*xwlAch-~6orLJscCz!A!KFtUd4s}(B) zG7|@)%U+k=?I$u88+EdjnRGS6e{Vvccj$P%#gcuwzHnUnPUVuTVr>dCixL&1n}0@Rs@gX8jCF<$MZbe*C`iY&kRtqBZEwg`zqK{* z(}G^tV8KS!_yKsN(yx;|Xt|jav+T{5bJ@D(KpIuF{fh1znAlIBR;*6tvpKWEqdnyN zYye4lrt04pxvYKvsDTB{0aDtU5J@a19{v^5D(QgwDKiZjUmtPYpNADFf6|zg_2x%afVt(^Z&hzJLFau7p{6$?%C=#ZyHkYkk;>SuIyenQ;wZz45ee<6>hI zpuey|TuumcCat8}IJ_3734*h$@XmbclH+7jmR8pG^XL9*4#>d@<>{cx{bPwiKg+$H z<&#Hvp^a*;-->~c>`ZP!T+KzJePC`E$qfR1uylRKM#`xH_D8E@xd@GLlg!1;CxsF- z@Sj!tlJWM%U~aPN0GP&xI}@g*RI9&}{!8C<niwP+UX^S~3U z!^+om1M>Le*1YN>i<}a3y83|rxQ(#o6XfH;-R%D7IYa;VeA3@RkSfEiqoqdN{)4DC zNl^byQ=n;T}A-6r1btihmniiN*WTTxrM9^ZNvb*g6MNKksd{ z+9Qvl2CI;t)JEkZYiVb6qLuMic*HEYw$h+P)6G&`b*%E?Z+(3#ZvL74IHP#k z0pJmTYt--=3H9rX}Bi!a~=)b|{V@w}QV--FP22jd2$fXUEFf3{pWWMA-3#^AIb z82u59{sB0yl=BiQdjJu)IcF-NeryhDr+}!#dwy=uJBaWxiQB`9ssme(yXim^cdo_w zU-aMkln-n=qrl-Jy@@p4t6ECI}+AD#OW#G_-r;)l9qC}eD_l8CJJ)$V6y5Oe|K{Y6uJM6 z#KO7WGOa`lGn7Z5hXyZ;W^ zuvb87pz{rw|JKa1zmY+YGH4uJfWzXe|Eu1CN1 z{@oXSovDtd$Gx4vaA-M%Q*vE`Kak>69?yGV*WHOw z@_qrojlUaQL;Y*(lFMlSU7{Y2UCOHZVSKaMnPscH)O|)hp13RXhRNdl`g{>Y@1Od* zW2h<%Z^YK4+ZG%hPi%VPFJka9Dl0eXVXbu05PiDPneecyX5p=Ny{w&UbM8U9X`Fd5 zd3#$j;kD}P^2dwcvpaP?vJKnaH5Vi}+0pS_7esbs+LccxnlzRmKHm)ne?9lz4&}*mC1W)&?MKK&yB|7R$>(E{>6No zX62zYx)frX-;&d?Bq`-e^Ht-7QNL{`Dyf{FM4j=Asi#Zbw%5TQC%f+E?B74N@TaI3JPUp;pXKx>M z33;a?otxg(kB0O6;%x8vy=Lf@*3VQHdG_}+qg?7z)F|lW5GM|vQJuEivkce8$G&%l z<+F{4FFV)E^IF$eu2#W|EI%qb*6YJ(nBj2o5f zT>kw`l$HJ}Nrj8c_8;0j14|Bc?QGoVSD~4f8@lPT4Q9=G9r&H;%bYYXm+Ue2)wJZ_ zmMcA9Z@g5;%AxBH^qIt|+Vk;`j>t(*T-V)? z$}3MOnvKJ@Li#SQ4%)G+yI1qeoKn$d*cdc2q{XSve%}*b8OK0_(`|p*jZLCyKPMl& z6G~5j{}3-dcJ=mQA^-rra{nj93xgp0pZ^dq3~bD-EFvtNBFv&}{~=ziRUtW+w6O7E zg4-n^SW&@(zg2mhX8{7 z1;MHpK&QPs2IT#8g$42WIIa8ry#rVEja%T_65z67&HAs*E#r&ni(6l+^@FxPa( zippn}YALd>uIj)29uqed*%q}Ex7)8odioSXFNRSb%O76LX#G|nbCuJ8Bn&4k0@3R# ztES0D!Q)BI$vW1w8TJ6a`9}{t3~We2t1*8X(o|h5>`Q1e*wgjEGDLXmNSswx zFP)%`G58exXlx}(MC2i$IILp?gs$YKlrL=`79h;V`2N9|u z%{VbdiHr(|`^wMG1CWJvc4?UXmWW_saXl+SGdg)K_)<>Mk9HC@$Bl9&VH>wFNIWIn zjvFj^U+NR#0V7zn+ybhAUg!^q?%ARi@^F0Py|6MLA9lC`s$*LyA&>XQrqnt|LtAYP zUMi=l?PSch{x9n0bx&QTArG_u{P09W=om}gRUDjCJ)2%}37a)`JDEgHMUl2p(i$M* zS2b|{rn&!A!oa90hFsArc%7mUs$Bkt(#0ug!tLqJa(2yD!BFv{JvWlB z`~Z#?)T5jf+&=QtGYPc&$TG>oar<-t?LA|*V7Mqq9D6KE|WtuTCam2e@bEm&12{7IP$In+=NdbZDDqx|uL zNI_bYa28|3k^7VbM#ay^`?-!E?OH5l!NBc5E0olLzv_8a#~{RoYvf7~e9R09He;pa zXmbD7+~Bq=mB`0=!Yf}lAw_T$u#?crC(yn-z9O4-0}aho`9z*g?u>6jjaJ(Sn3TPB zNskniQw2ZVVBE~SP3vKrh)rq@4Eh-^zE^3wmw7_(Rw}20i5B|TcjZ*}y=-*)MrSl0 zaX`!|+tjgGh3|f0KfSY%%CdDKp}hMcts@~jsjOSmihqAh)OJn1S}96#`y4^yg^xqi z?q#9_{72UO+?HcQ!dFmy^>1)Q{EV%q^@%+YewC~$aczXaTZyxdzq%9LZgx4XNi7+M zG4+Jm@Sj%E?nf$BiFgaCa3GI&TTr4YZ1E(}H`ltiqd z{fYIJ*kIas>8%tNq~s^8m<5(_AIQ{l0GB(Rh7Gg;YEY@rsfX^`wyu4$xK&P3jF8VC zDYkTioOQOU5P(|4>hT0#P0ydsLg0ZQI%TRYyQ@s;45^!t-*z}^tA-tYGArmBY~ggL zBJsNmPU!E9oikWVo46qrW4B8mdimF`r{fSIxj8om`Hi4i#Z{=hMZ2DZTG>SKasA8= zl-K!hW_#WlRlY11RPcM0VyXh?Tqi48XE#)E#Fu}@Xn(9@c2kyyXezUIy=`E;K!>z0 z;=;c*Go5ercC0RMAnkPH?u}0KkdpxQq%x)8x4sO|Sub};MSMpMOT(Xzj0&I@zZZlP zu@^!c&>_s(hD(5|?M@z7UmF-es|(}0G1XS^4SVKXeu<_;;X2>HZa_nA7lJAm8r8=G+=5;qm zGaKgd+t}h}_tQA@SLzx%J!@=oL z_{aj>iIN)0fpw=Wbxj`iTS%2xjg2db6GZfGC?F@*4QQ~V_i($nP(rma=^LYY9LG5g zwfwON;15jHI4(ZEp@u6W>P8-fy!z&K(Ck?h5B(KGMR!-6FUpNZ&}lE0*ID8^M6-HNP{eptUdhl%s^l)O#NotcS)B?9$Cmo;dn}m zLi{Lui0q;?c%xM_#3s~Eg5zuvC{t$0G*uLv2T=4|iYlcinHIJe_9m+#c~BKCX;rH~ zh+1`2dqZ9)DJZrNiL~Q}-8V`n(DM{_wPI&&u4(9JAv_&4{Kqi@DrIf(@lfvU#rPNf z%y({m<=uF^f6DcW;!AbGj7f(+a_4@CK*0>rL$X*vHq4dTG)irZu=W6&h5>>0>FSHb z5K4!SDC9Qh9T8&Rlyj;0NcFD6=Bg5N>sE z#xffWV<{18uRN`iwLhGP89*Pf>Xh9ov^>*$zDAn+7shYN?T z2V*+19OyjGQ5LWv|3(}CLW#!s{W+3H&TB08RrrWUe!vdg=QwO|lCv<|k3bB_2TtY{ z&!LDO{O%!gUf>TP6RPnPx&-k+@Y(``@w&nm|iuG^hk z#}?8DS3_uTG(RE$0R4BVd_P~PNngtwcYr)F7yvuQ?9wR&YDZL1k{@e8fY~3(&)<52 z64F6%0D>qL_MhzH31#z=2j=anUOYkwhTa+NpOIfm;;yO5-Fxtu%XN0|;O7|^9BkfJ zpOumRVHMeRAVok!Mgcy1EO^Za+|%`jniMEmbD=?WfgTN)R_fn|_BT#yC8)zu%nz?7 z86A6vsFK!}@c z>j7J*9lz?ug!a~V=UU|g@%Ejd6SdJC0hek(6Wc3s+yGQ4OjNdI{KMC5wP~C=VYwv2 z(L%(5{Rqqf(4LOqL$gj`R>+xgj(DfkJRtyd+0Bi12`5+z<_B=~p4D3vJsUOyWQo*U zk~l+ur769lKTA%Q07Igf1Q6_rqQK^rb%BA9jataOGLKMEBweRD*l(Sx90s}Vc8-wq zwlirWrHJ_vI29Na5bCfTuq!J{z_gU~L)}s}#QGa#|A@-q<8E+pN(@UAwNyd#4wWl- za?y0_zc)WTIDDPQuKs2x!M_Dp!mrcNQtpeSNqmOh(mmptj@6P*i|(xax%?V153%Ao zok^BG7_qXA*HS8$2ksH8UE&i(kL=eGUv6P#$zL&;%vIhVlPjh&T!daqvO`}s8`1F)MO4NqOZ*xM3ZPlqc(1@|&k}V*Zt-Xf3WS6- z54x80OjOjzY|YBd-(hK$Nl~2_p(t};5fg85;)CGe<;Xni(MBey$hI)sHHb@jg$ONf zTHt2#;Rk!I0@F#!Pd3QuSyN5>Nnu$hp?^SlY?$CjX8k83S_qvCiR>T(Sp7RIVpl(Z zOqzvpfasiIlZBEBHS?ID%~-(>96)^VOq?eHK}J#Vt{f{^Ls0aykg|erz*jXJD)|M0&;J;)U$GzicnTZ-T&RK3Br% z*yvCii4fT^3lr(`=VD@<;=twd8=RZ>r{`0{&gok=G1g%IvJ;)y@nx|wi9OF@0)H_9 z3o0N(;dC$2@OhVh*fK`rb8d7nNySN3F95`f95uhxxKbBzZ$SO8;?cJ~E?m4~cNA|% zu<%TEAs-(-uud*eVu)*oKHIz#8Xwh(jE}yp5+X=FPHZ&S5>3keeDxy9COttInZPg4 zqdW_H3#U74nx{P&Q2I{{wBU6PPqjeWTO;y{#x>LF+O z^?+?D#}pbnesb&N^X_N}?!3a|4icS($&$b0^d2i>oCu)bM>`p4Z6F|9A;TrXbXaqh z@X9(eOLiHj3GHljC)~&^p@0K`6*C5r4piPm5?7qePPLij-)alKp5}1=h!AVo5C+?u z8cHTK8#9m2^gltXpVsvTwmgQM>_7%S@xsT%eBgv7j8bLB*`#F)fBBqiuF$O}9lN5g zov~`XG*M;k!W*sdF5SEQ;j{CtRAWX{s@D_;BYEDl2W~+R-+er4qPe|HpXE0Yl3MZV zDRUU#u}BDTy~64%;ou$SD7@I86uvdwB8{hP$Tl}L%7HVoLop&z85+MfT!sPdB=K$- z{@x#X+xBv&TzIr(9O2XHcx^0+@8AojFzLud8mHAZw5m_HdwSI1;ZOCw_NFTJlOn~7 zby5$Fl(g~-QH6}k4EVO$Iv^j{ne4hA(s#Sa`zbvf_BIjN(D5ZhvEUetBk0y8zrWdab1(!At^H%;EGP3Nx!VgyVakEwMk{#qNvh#r*qyo zqg0t0ljqttI89w|I^ld>YWB_Mf@dnZu*JlHrqhfzW$))qO~S!m0M3Xt<>w=ohHivX zvx%jj(z?MNa)0niES?765!#ebwYDwkWSe{KDZP8=d?QK=?PHw%QHRW6$d zQn40EsFj_&VNZaZFJ-lZ&LFgrf%$k7oQ0wPYiDH}=|t;d%ld6nA~+;_dow3bMmMm4>*;^(v8<-GFXX`c6!I``BibuXb3a!{ zDTeJ7<|!22D@|N|0Rn!U{Ipxt-QA9t z6`hK}t{1(2f1J+BAqa8z=^?uWk4Wx~PB93Vs_hJ~4qy1mI7nTeLOEX89xy`eG&&@g zNN4yCejr-Xi3SVychv_GE8z4wQ$tUtZ?pp9y@hE@*k863 zFZu)gmX1os03M8H4h-j1AGvdTyq5#Ec3xT{-f}D9^|Jw%PA0djr|Mx|`mom9u*)cp zJ_aSy9qs)`%Gc%J$mlmBC#~mihQ1c1^!d{n3>^ioc_Y}ns74|QhH0$PF3pw%Q5ts zB$VeNV*xvzMF&qnJ^s~F%?v(^F2zDcI%pz^#mlc<2=q) z)P^CgBft_7ZX~r~z|_ytL1BUX_ymhzd%Mo{LgS`5{iSWu8L~b+Bc~Q`grD`t&Cdr& zmd)6=``WiUn|}Fr4M?mU;o}9G2f%270D$O{3JaWC=zM~*W4ic1Y zd_}^zogG(jYunBC_z@qB9Kz|^i2cUox=UbN!L0MFPNZuNZ2pBqc~@&2@FT90E})`^ z_#@bO%>Je4xZMYc0TEkax1X%L_Ss99(0dBw z&EQO~N)#P(w%SqoT#MKuKB@A?xweU$XbM@MPdGV^?C{6d6`xeJtecxgPQ%TH4ae|+ zaI3f5=x`tM)^mN&8bu?8nqbgd3m$|H-0mX>mqfT+s|wl-rDV!aHPsD#wz3naYyWZ| zw;Ei%it$@7h*i_8`*l*#TJf$HL(+JBGCyS`vh5gF_8C@n*G%18#M;q%v$Lr#Y|_rpI35}b za1o!&=5DkIO}cJKi;w07f=wH+{x^_q1Bso$@tYh1UStrj(c|s~AKwXF;K_7x3w(t! zrh7M*9!u!8d7hxN7Q(V=x^5okdzaE(pLg)^Drsef!q9GwPfn<|Y|TwKpYF#iouK?C zSVV&K1zfLjVEpofU%MR>K&Hi8^&hx8oBc$1kTaK>=Zd_ZD390|l#=$O#8&T`FpEdr z`>Qp(;cjT>_!DjH6C4^sZ-&ozE%2vf`Mi)OUZkZ?ZEh=j`N`lquQ75vvo&!@0IKGc zHP0B|VOhMKY*&b?Q77MtgLmEEM8}Q@W3jh6q<0H{>74IrA``!CC{$qu4)-B1tu*~T ze1U>>niSL9Q=MFD6R&?^ zE$P7*N!U?I`?fN!cYxX(uk@RAM81l+u{PjrXt75Hk}Six4`7)J%}rfmYNQ>R6zMIu zgCD0xMV=rsz^0{lEMa%wD&#-M`+iyPSM1BTR-9Go>Q5SsA&9&NYZJ0|Od}!pF zW3}@lavdh6p5Ns82z(GwE3EZwHWAd4O(K~yGz*;i{ z<)WW{h?_1uDpz0I30<{X^2E72s(cUsPKe%@2x#dQWK8-_NkP-Rt&D)GlzUctK?A9x z<4(5dlTr~sCC`p7IguL-%#CdPqi4>lR4n*q2?@INjIUGP3HtFNXXNm0zpeC4sH2oh zr^mN*Lm3WgGYCnxK1>R;!z}f0z$l6}%A~*OXzCrCpsNf7Ux>e<-G_z%q5by$fj2!3 zM&i^?1`AXA-rkO?yjXRp>CCLc26Ns$k`tux(vBtmQQ?iVJhHR1v+^QnH2il%_wF3) zyX5Or`u_es2e8v!iEAXQWjV;dxvPat03q4i6g+i}a>LHkm?|}Am4(l|>(OX`JHy_* zsLk&oO<$egbKn9TmrUK&20x?k5%k%x3Sk4CS}~vA-Pw%Hs+Uf`-C2YbYqgj7D5Ps7 zJ&$gF_z{4-Y81VU*Z_`aHH)TCEtOWae2D|O{)^sh4mqaUJ;$H$zQ@NCk%gN9og_Nh z#+qD2b4v&l-DCckJ&T^MwxaC5iO*zOm*{OyFU9dD#h;cUIal`LI0hp$xAZWl|Hs)mtO)`vX|!zHwr$(C*=5_dZM&+= zwr$(Ct?4`S%?sQ`<|a3}jS~^)=g0Q`%Z^0p2}BV!V@N1EQ7FAb4_ytFmw6%M%|zBa%)Vh#T7zlO)^=PvPmF?GuKunO;OZ%Trrr8ME9; z6bZP*7>EVFkH+4}aO^Xa{&r{rxb~egH2WHgsAv?c2_z6NheB=6j`s)p1US$a!MTzG zIr<`3Vi6~YBz_p(-q~t^u|GR^4C>1~cQDKp-9n!yJ;Fo-@ncf};rz7XZ!1MLpM!1z zOQjLA<4h#xgo*B&g-d7)QSE&(0dmiB{7s7eoTjK?yxe!W5mgV3BJ>yL_;t)`M8he4 zbO5N8aHVqU&=^$g5IMv7>HA+K?t{F7OollTW-4Nik8|8TeCNBrxtP~};=F!v87qDM ze$lZ%xBlmT|Jx=lM|!RjMFIfm_;>yrKE*1;`X5fkz$z>x#>yrr%*iPH|9mQW_Y>c^ zY#=@KFX1QJ`e;vzh{#JljFPM29||jz-3C%ZZ4-RrOM(W|hNyvP-bffS?TFvEm*3n+ z?%&;iclK+~tIv&7p4YBfd)}zfX=*|{AE*G>zi)mCXZ!zJqx`1r=z##(F987XzLN&< zfROOh11J8pf&-BJ48HvOL6f|iqyqxj5Q}{2-$R)o5iW9MB>!jz;u@4f=g&ohf2n7g z0RjBrim(6n)voM(Iw$Pp=6;rGnt#N`)@ z;Dn$eau(49M9&CD~Tfy@=4q3S$JlR%V8eXmv!^1+>vWiaX8BrP)R3dEO?iF%ssgvt850*-QdsgF+GdKF|e zEj^%@LpO5gYTazR244NgQm4zwLj{Ur+k*yLaT6CIzqr_Wq^GS{{T7qw0r~mac%~V= zleC==SKMn64%9O4NM|L^S5~)KZ4qm-yiYGIo80dIR{T| zCI37^a|ICtsaHIe$a7VMOEzO;fFh8PZQ|AGgq7G==dO0IBtJ*5rMW;ydX(NE8$w_x z4GYhWou!g}VXe3`^lvD2OAL*VO>uso%m%J^Sc;IywK*xT%!e=uEAb%3C|e2=71jtA zNmo2Uv{4oceF9)6h@YRbs}WQt%IXt_6e`9syH@lHhkZrI8;`)pAboUhlV z1xI-F(aH`xtFHv%I#1S2b{|u0ekmmq9(70*>bD^w(5kkS8~#F91x3xr9EoTL^qSIw zYGgOBf~;n@AG2D2hNGX{@bz&?4~GWWgD7gvd*y8B)2+2A@(SS7D9POksEg6#=LUZ! zGzRGO>!Jb&;5-`%F)j zSq{I>)}1g%_{R5G1o>4x#P+3;UDQ;jcx5veGZ7Toe?tEj)Y>TBM0 zskr9PxO`?bVDx{4G_?h$}OIg?XN0YuhSrq_ors_63$d`7SPZisV`?Ch`W zzmNrFPjtnrDa}uNmbTih+{|S$mA(4*6ra!L$hgLp@l{hpuN;w0P*m2tvQ$A1$XWw} zG9U7s+o*RwohHJ9_XIyzva{fJD#WK>AJkUdDqAs7OOGQaY>;I!?Dd!d!TGF3I-uhV zS9uNV3`6JzI8kkGv%(-0B5N=TCsxmfDr-Od9#Bi*a-WU$eDJF%d?x5fcKRxgga79SjTE1L*I#Sn83}O{Bt5iH@LBh?K zrB2`@_Qf>bn{G`t`wu~sR7|z~ygyeO5XRf&Utnsz zjJ|9?92D9Ld>c*O6ud<&-m^7&W3 zQ6WaD@uuF(ilO?&n8cdCSm{G3Ob)qMqmW2Ab_m3q%^ww{9SH2M@$Jg4^+_@J#40a4 zFe816QZ@UMQO=%*zGhZc4(hhq(LoUYT$ynmN|}`bHdqBkCl+sZ~f04 zo_v<>LiS{xdwDGrv^wnXHd&j|Xe=FGCpd2RFlU+kv$3=?6EGh^KR2y8}e9ur^9q)X;S6%7*I2@S|~< z*~;=Tr9hwSbXH-xSYldx*w69k1z}&(7w$PW!2Bg}5c0@)j6BNkjGoO?)yARb4~0Q! zXZs>o)|~czzyxXJIMZfMBzH@As3%d&!n&2`5yg_0ukBrW0!P^>7UGH43vovKCbKnk z>Kh}fF+FMIqCckf%ltOshkf{JIZihlGDF7y{&L!mNpdxPs`4KwhTH^^OWeqZUvG^^ z`o7pCio4A6f_IbDDRSpYK3^*U6mf8L>U=;NU9OYb&K0HlY-O(L7f(wt+oxn*5m2y;svCXw-{r}^PF(a{wdXf? zt+Ly4T@|1l*JOg|r%W@kRSU361btE#_&L3 z#?J4)j8s-9^I$NElEyE;J^19k$$ofnvJ`b6mxID$-q*`n_LKlzx6_v=m8?z#*q#T*+Xnd&W}Se%Et}-)5y->!h*K%ckEp>ww%0&GWg93Fo&s1@M|Ke zI^h-1IW+F5K}W|~KK1JcYpI9nTuHn>2fD3(MCCRHDtXU2;t2dVr;9it7nFaZKGQQH zD%$pKV7`V!7jI!I3KW>WWX(=W;`!AWUB6;*nmi0t)z28dWxu6U?R9$`a$m&C z<3L$UYcM&@#Wm5PJ8~`#N%kZKdwvE46~sx>a=T*H_>ib=T0OMeEV!xfVU2UIT;Dhm zPesA)4?AlCBxUgpiv3N4O?^uDoNRpDc&C0TXNP6BLG(bN;Nq6>)+uf$g5zDiYd40t zT*wIAYPz8UE=vbxp=C*nKEgrKKT%rvZduvu7yTX!cRjs$c@)ALc=v4xrqbH2 zO1oY%TziSaUiT8Uu64>Hcrr}}b@o#)NydtOu6+bG(JIsvcfAnYbV>C=u56-`gdP5Q zHE1NJPW{4uPDv|6bFx^Q-mvn$U-pDw6KN#H47>|()V=Mypb$v6oJ|b)hG3LBIh)ON zqYXU>)^o?L`>uGz9ZBvXj#tYxqYjlrNU$rc0HPiQ`o=5g_UTb-o>6#jG+M`4-^LM; zI&G**D#uWH_6meQGRPliXjZZ`Kq?sAaaUa|f#kg1S4=<~rvxD}ar*94k*wbj6Eew*hO&OMw3hS3(WC@c zheS5J_>O~6ly0_NX?z+ysSo|I8O67d2_jcLcFM@*MgfLfs)UOJWtlW5L`-X7L2Fhh z&(p;BBTi-NC>73buA(;L8O-<6hg2O|uM~Z9)y%nY?37^ktug|x5hDFuou;P4Pt(tQ z7Urj!#swPeSHkymyl3;os(!~axnbyH|5&+m7h^dZD*-S{&P6*E->w99CJ3sEyk{ha zQ4~=(j=@&=Ms{qnXzZklN7+2&%bmZB=*Y1oR9dt+_>g^6s0!;GMni*!2;xbp;NYe$?chcBr!8+Q3P~`a^n6>XczSxBETi1(S5_~4s!y2scP{dQl(wrma89zxrBAQke}IddcxO0Hy+vLBou+!ekyeK=I)VZ*L<7@Ss?AGk>or1Q}g ziY&CNyBLU3dGcxpGv}F5WpKeckU>c4&SDM*itpG_JwZ>B+g8DXpZk>FlW(BO$3LR7$`$w9E zyp_>6v=c!fyW9TDDtQ3sOCY_v4EASWkp6^w;FOcGygRjY^81Ef!e3MNM1#(*r@hw?E|Fy4DO)-lV~yqkz5BZ0%HAI67M&TS)V(iVo0 z(SnMY`!~uJ2ncG}!H-wTG!dEhR!0 z=AjFF2piy@15>x8I5GgFXvG?W@xw5?u+#{OR#;k9c2L*;5cf}7WqsfPc)Y@GYk1!k ztwN=B%XhcYnqHiHZOcI8y93%&W|AgBV?nhcwO`0_bI`hID|#52)+?3B-i|iS(S_=K zG^L(o@eCpp+Q1`VXIsXym4rO(8R}qpz!-GjyVv1B`~jo$*$|$e>FrjmS43CVk*h>w zduQ+y@?|y*1^~OqF9q?dYyO7+pRt--@C73s1OR}6f9Jo!7DCMbOD!1Kgg9A5*f}_b zS(*P2TYxJh?KZ%(3IO~Q>Ue<*%bv-0Af2;Hq>xD{W=b$RhZ9I3A|M7n>4_+u2V-TT zD2hm!69wi!c^>|Db32`GyZv$P`F5RM=WR55b({H{(tWYIuk&u_Q9igbP{!4dDVDzox`#r#AU+}z`41zE@YV8QI(E$VW&IE& zqmQ9)HxqgK{ndBpFx##{V^LGoJ~w}N zER4{^NJuI*l>Q@4CK8r}xo3hVxTmLDRH+z~+%P8=!|jY#*W~}?>U%2$Sk6#L@R(O& z>l}oj-P60p`_jK6XwEfd0%l<6>~Q+C=>YHatPG@8No?nKB3ZL#hiFGG|6YSc`nLbF z!PwkA5B=~Ptkd9b$EWc$qgkOGecC-kw;sPy~{N(ycx2K9wn)~}^ruywIrM>mfxk@#!L8qbs7<ccA6mHtOd%fTV16e9g!7SQCdBRfw^ zF8&^cZa&pNJT*k%i4CV6`bFGMvDIkDc^D*AOOG&V3^lyt`{$_>JKkTl z=U1~^My3TaG>Jc@4sj`A+)pp#1b-IBX)Tv7FKY|Ehfy57|JXF&#Rn(an{?Y=*Ul=zKyA#Ekz-V6P_<+)`6X>ua+nFL)<_M!!U&_%zf6K-^ znfF9}p8@)gH_>8Xo;@;n7M(obH;+W$P0v#E%L8Pt+qSjdA8lFsihqB z>1_jQTfXY%(sa;kd$iR`p5!$TLP`>CA$paL(e}n3F1!qUs#{vkaL>S>>|1wA2XvyB z^~NI+JfJ{r4x}PH!Vp`@E(qj&6k7Zil*x#q(3phQ< zp0Homu<^qhL!J?kWFPM6b6NAB#zu0loL~`Dol|(*BD5~2gf;K)YGpU=!ff{~FbQGOSZ@Q; z?yzinY#;X0vs~ocKwa5&5_I+BgF`{(p?BN8pXX%qq7Ph#;EV729L@VHHiim{R~W#dcjIeG?#YU_q}UiRd#(pK{*-k_BO*hJb?8G>=5xCJLjac>%vFgL~4|l7lyg zI$ScUJ%lW?2le8|w){ya+k|s?K91Y=!*rzG2Y}AdiHUWyXZliKFJ=aDBEPpRfy7m7TS??kX>4PtF6n1X zixVHZ=q3KM~;kMV$2*E~k^GM8-RtU2sqJ8Mt{FQXz;hwYodDx8ZJnQ2SBb}GR z%;J5`>IwXfhd>Sf@nd%QxY^&{?f_HnZ0kEJVyTPjhdi6vx;qfQ--xvDhGO&U(0F9& z=&tA!qQ3h*>Aas!PTcz4Ng3~Z{mDyE0Uwo6rnwf8$*4{m>^S;ElL+Deqv zkxK}z_Ksz)3-vzS7rvsiQQ57k9NJ?(8Tdz#r-#ft5hu`eK9&6sMkMfhvCA4%$E+{N z#hEhM^2%vwTc$bAw2}xP?&}2Y*U;upMgC)5bg$+qtq%|OuMnVs!U=->c8y;vxj`8= zhg`I4cQp^P$K5Kx_eu^ijnIi44DJ^rL?G^Up}lx_=a^uDo3(-BZd7oNa%;MlP87S< z?q|=gr65-U#R?Rj4KnlPJI5XMNYPmYS_oN-IqFN<-E8^<>ft;X8NN)Y9gfi|Rd@ny z%DwmH$#a%aVaf6KjaM<3rAB2d|KWTEQa5MTnG<|IDl_0>-6V9 zQOd;7NH}T3&EW0+Pru60J(4^%Pj?w9OE8yAk+^6qH74s1m^*M&aYv?O-ug7Y$ z-`bfeTw@hVME{y$uJUP!6cs@b1CSbS5L18eg`Cn;4l|F}7n_Tb1YxSm@i0Dw z>#1&s_XZOg`PYGv@uB+R+HIJi`X+4;x=(Ydhd3DA97Jf(%@KX(3C-!A{ih)+^`L;| zOT*({)az~A7y4%Q0;!Z*T&rvnx!LSO)43vn<{crLC{6Fyj@~xF<52r2@oIS69YCNc z$>w`YwN%!phzg5-+yMm=Eu@uXMwHiZ+r$q5vcuha5eF!p7ZZ)*tD#00742KahG6&6 zVbKqJ9u6KXB=0PIW;3W`*uwzqd7&L;b>K4Rt3#oYni6S~t<1-tV3TP07?NuDd}j}p zUyU$8ah3bVK`TLx!0GYR^uqiUC?yomrI4dRK<$SrZfWY6h4#@L8xuVs)?p`Tf3IDR z%tQe65EYmqZ~swr>}|trWL!9^iYjBO8|9U78SoY*D9qagLErF+Ky(xNaMVMl%;^x{ z{hK@P4k9#JgxH3As`12Bf|ZDPb3{szR3^8?;F%P!w(OeO?UmV^>AR+XCB+MOhOG8& zCi`7TUq#5?yO$~}t!rG%j>abV*+%j98YdQ-SZ{e+X7M#OtLXFg(ny}7K@k39s%=@9 z_S~6|JTk=wK_0{WLp@Z2|0w;NJXkgp@1BJ$495&5cr!~d(dVHGhoM`XLgBMntz!PQ z;<4bp&SGcqC006RRta9J-8{jW4o{~0?A9L*tKI+wLv#*LVxNG-XF(Lwi2q@?JI3 zh;N5w)OkpYPqLK4$03zaHQD^XE5N`t0LB%QJJy@&S=5fYQQK46w#a!E0u2B8!+^eGEmA5H(ec-2}z** zSI0?rsw)@5$l&(DYKXcDt)n(p9>o5ZaIZXc=}I|}|8Y2s?4PFtWtL?P=JP9!j?@^T z>1H17%%mB%Ai!|jLxf!!0FVnb+00~P?^*33Fk6w!Vk?tQdC&&E8L1VeOR6SKruv-2 zUzM0_m+qNtnI5w9v|^qI_u>=)RrEnkLYY9%J+X;@Div=3wI%%-=snXW!X{^(Ffb;& ztMWE8#_t6ON1<^KN*K`$*_piek$OInZ0Nru&bERYdv=|RKGsy}A8dXSl$G6X*dPnn z0C`97Qq>J(;vm1f=U9}L>{6KwVk`jx%|!TNCZA*q*~o3(R%=`+JE@mNTYii?)RtYm zILsL&aklF5jAQddLS1ZVgC+S4 z`N^=MfO~@SPD-`TwRDIamr=z)a22&cPDBPz( zxT2BCpgFC14Nd})0fMPtwR7&+zr0b(VuMyc)B(NR#hjN(@(ep|eM^iO&)joNU`D*6 z<0qU0K7?dT=ILsYp3kR83Jb+ruhz3mWz}5(_X^1@QkOKJ0#;|OvX}{{hrhSU;+J~U z_%jTTs=CxMzaZDWobE_Tf<5#!@?({iI`UbVi1bL^P-}xlx&7CxQ1d#DO+UqwroGa1 zvqKA7w-x_%5qtHiQNK_2B3+a@E|KZw?H-C$y1cU&co1f^d84cP8r8=pE~jOjz(eIe zaAm64*E(s-JJbEy!UX!|5kNRm0%xo}1}?EWv@rgqva|oJzG#rmFc*n1huK6u3Tt@j z&g{s~9a84zRLV$A?7fg5oVxm)^`>aff^xF_4QZK)8o#@ytqU6j0M=y|1HI63M>=s> zqwzp$YbS88uC1|hP;i0uDmGYCClRe=yGFTsE7-y6UD53Ah|Yf_7i#4A+ZjFq=T(!r zMR`R|NwM$vy8(?7-CggON%Bq8nb+1_q#5%;nn3wV?T6dO)^d9jiY;{TT8B^{SmU8( za|PO$xUCjy*9fD1l7%RBA?(jB@16`>l?e=jVyY%dzoBM4hm2U|Y$2vkEVzD+NYv00aNILcE+QWwL*H%_P!V52^zES*Rl+ z!PQme%|aV4eYa?9!Xz!MVZwG+8;$TV)4SzRe%16_w?@Y#Coy8)7G0ZJM?lp?E{^4bAlbTInn?Q?R1ZHn`} ziTf-j!d?E^*EOU)Ad~O8q4t+^wq1TvO7ZIMM%8*aQzm0k>j>4k7@<1dPuilw+Q_8W z`iNu9Vbh!XW*zCyf1$Gy+n2O9CZew>d}Z>n)Hk{kd&u~A)2WyUS<0YZm~-S3nH8z% zjri1Q+R(>OF{*MM8GE`Pww<+%Gw)b+S8r?n_2T-$Mz zFcs7DqZr~al<(`D_*T4NX2ZuZJk(B&f}E@^>3~XY%XwYjSFRP|Dakf-%M%id%-Bn9 zAUr;%<>j6Yi_IQ=KETvR08rb}-ft~3eHxDlJ!;2)ju zh_>>Boe|*&qYxPuo;+8Z@%G^lA@F0C6rKjiT|DR4nuWe-$127_G|0-6h^p;=I#zgh zCH9x(=^ZjBZRVA6lr5+nDg%Cb7oDFva<-aa0c|871%05XG47H2nnmRCp;6FNlkm?M zMRn_lmXYnrcODQq#N%LW1--8$c8NyRJ&R1bvMAIty<2v36dk3%0gSFPFj;X~^-w%h zQ4RrkBw`*;$TOy`drN>dR_LGvs7aC6B4vchXS< z|8T~(%>4ijo^l?=qfPxJ*}jPR952M!Qi)M6d}8K)45KT`i0cKpwTG3pI<0vuw08Y1KUHiErKv&GH<7x0_agwJ24kJH3%(x5ApOP+qWN%% zY1I0Xbt{TxoK#KaB)G!rz#3++YUjq85)-wl9pq1iO!}GNTbsD>>QHO3ka6V(_&qUq z_a~bGg^ZgBl$>m&|E}w5T7ieU&2{;=dr#@7`{l%`OO@(d`NEj$-=O z+P@&6d7X`$q6)+SAV?%=+UryTTqwK-#g5~IO?gN=wwDwM&n_!em*zgjgCy_w)XoD9 z*0Ogi|4I0l@lsigDU@00w30Ew!Shhd}e) z71w-Mkhu!6De*Dv%cyy`+)?8enUovBHm(;=_wv8ZRZvW95Wq>k7k~wq^B(VK4~gZ} zzm!o*Xcu(%2D}BOK+hmKX*^fLDC^BPLo9e^eG3L;_<%1D%twAqR{|6m*Q0MoZC6AR*u+ z#w0m~p(Y^WG*e4FA|+2?_s!e!+Vy$e`rXORXk_MHR@G(I?XA49z{NyeHgjCl@Yc}K zSo_Uh()fK2``(ogBiGPCA<@tP>668n3kLpLG!*@69~gl84ZHI5J%QALbucvKRXbMi zy_b(dux|h|;}KAJiGz@$sV3K0<6pKl_z(8o zy6c~Jl)IbzS=hN@wF%5+o#+=wpU4q@22h~rl-Mg<#0dc?6q4rN3(w^Mq=vvq>NJ=4 znda_vAx&O9h8SI^U?gOKe(m?PKx$*w1}RH=Vv;=a?$ZU|Pc3lyi+~gE5hr>#>k!3^ zj_dq#?ww-PQJ~tbaUU1lq0Mi`3%~ucz*Ym*mk5Z=FQ3OQ@J)>9cce|`KLHi!H6$5g=klJcUiJ1z7lZ)d@hBqRJe`?T=yF9jA% zQ4$#JK|@>bw;M`fBz^yRy5f&m zGgi5V$Gg{+yrSx&?=lh($nx^?^r;o)>OJ}7HsaEoo4Lr=s!BBLDl_Wlq5plV=T>Y! z{7+zOd$Wtr3NdOr2TPZIL=El+JyfRXLTMPPI0d;qc(#nT-}z2Hpvmg?vR?Q-CeU&&2FKZ%)mad|pL6-IN(T zPKS`gx|Oni-1V!f$~3oLXM4)kbKQ@#ZuS8pyv~L%s2uxJb#UUDgYjlgJ0i|o5(R|8 zX7=)$yknFoloR&sxrK?M!YHU&pVke7P06p)6i$G?Pnsy|TsW?d1)PSK-*88k~bmVI20=LJuc|asVNn{Uw$`+e9N|qD3+oa%lYLi#(%^B1 zM>{TYM^T+5=J`K0Q>DW%RfAA#E~H_Gg~Fa(C=r|dR`AVDxWK@RK6@p)#k}>0y*Yox zk+Km((jsOcy4K$6U|t&=xkdaVXD(=(WVEu)HkaiaY0#JNtxn}fB{yqafn;j_6a`rn zsi>S@x|YHz*SIvHPt49jU&*jLg`wd)@bxuP^(u z9k5_J+62OUxQsopTte3-Nj=`Yyz=F;NskGT5wi{R8f5wuAi?xA`-OvEtUt;*mK1!y z*i2d6fSak*l!P2!v3si?N8pIex^+Z^^@{^|_@XSu@o}8qNC$^JI$u1je{JbhTS{G6 z4ugkfB;_~vjsKbaIdzfq9=f=dD6>OkAPQKgkYbjVh({)zhG3e9kz;@aD}%mQVT|vB z1VfyTh98>q}2ee30=7#Te1oRd;Jc@3pMlt7NE#dGnOM99?!gCf#pw zTF$WgZLDrwefOd*8|lTX^;5L|h4tLR3$Fa_;MQdzC0IH*HhbX@Z+^mH;0e)yaC+)Z zr;r7idz8#d`VIJ}ty^<_Ze27&F-GL;bCRwwNC_cV-Z288il&O(?K!);<<6s7i1G*& zKE)4^k4N6|btN;J@$f>Y8XEGwe%v#El z5D@4nU+bGgAj3FLvJ74JzBkINt!_FQC2gFhu7wK$;=~NXhHNda80m_l|F+Yj;*_PT z0`oIA6NRDA<6(Xx{5+ISyr zxzJTf4ceRGICi7uRa(U4f5%f`H*UNX@Oqh7#-C>coR)I$8aLx9){i0tcd=7n&cv+* zt~e>0ln?;z&BK?1Y4K}MmP+mj%L+<{RdyMM&cwN1lK@ENL8q{jW(1`BG{w(*5#lqYV`^G~Od(%p< zsS?{E(UJlU-WU`wm?SJM!?!&&lv3*Y=JUz`rVUB{!Ws0ZUBa*QkQFl>h4KmbzXW?4 z6~Rq<#Ue3j_jFC}E_Xtu>aovP;F<~7M&2&TL&K27Yn9C-ne@?dBaF=24~R#U@sq5b2lE_bP+FIWW@ViqS5if| zLLUlP#Xn#?<+Cs%sJ>Ut88HE1adwD`fhduT`)!#lEG>>)`z#0I0J%@mtf^gQ8Zv%3 zc03~KB*$c5weMN#6D}Z|eCGjdRvNQ`6fHYu> zZ!mi--8e%TdFUu_58FIScq@ph7GH7RTq~ zFirr;*IAKAFa-ivSRMp5j(vq=ldmsy2K6uK9^UftYm8=yt-~(YeJRq5;-5~s%tRzyq3nN(ODmqfr6eLGliw=L{^Dt)Tl)o27BgXG}y z$lsYQhoYPy<$!!Nd$QDp9SI77srsE#*60=TP4(I&;d#;jt2keI-RY|(lVsuiI}0fk zc9i?3Wz(~f#<;Z%W}de9@e;8d z;8)6L**>FJLt(VsI33K|t3oiO;CdDogv_I9Z)^pRJg-M;vMd9gZ73AAX7+BHb%#3R za7#6@l0|lF$wOx=!}DrpS@v()ZL_z{ZHF~b)0$~kw3#u}FmugF!a_FP>UeK`P70k7 z$-!+!PEv<+lztG3WV$tIh=JUYeKjn(V-j_eiP*O&tn;3UKRC2K^k?$9M+vz535mz- zV2(27By|1hroO0>0gg&n>`qNeY(#hBU4Gn0(xYz7&d#oq{luRbDMm%=+WStOa#mqk zziB^3i4g8_kJ_XGM@ysUE1iGoTNvdM4T>TmP0lTYSY{cP=Jrwx-H0qFdbyy(!E4Wh~3OFXL3B5>NbZZ60 z_!=zi2IZR?P-f}*1M7P`D>htPTF%+M$@&QclwjxkBRbN5`zzUbK!C0V5yC~Utv^2) zb-$dy)M37ZngGeb>F|{9i1ASu5{do1PkGJT(60gv7ri9P9Y{eDTKFO*CCm%O6eVe$ z8U$`$AJo7SiH~H7eyl<_LW{twS%tAfdb`xnVo6n>&=1E<>c-2w0RoxWW&#W2|vIQfB;?{4W*vU4q_6YV@q+jP>~7^10*A{DK~CLW?fH z2@MAz9%6;|QHCyuncEex5vN7@bt(TG7gPx{2SNu`fWd>3{R<)TulkOH>30ejl-N$Q zJIpG}IwWi!rL&%A_^m+;IS7X-Hz7&cgaX6chmRnt_h1S?Anfn}v9h)DkU@nWkHl$* z1?{7w#RW0|`^a)2QraWqt(X+3VNgM!{~ee=r5S50HQ&D^kiVcVV|t+**+6RUSV>@@ zVxPy3I}Ho10ea=IB*hUQA+yNg0^8?yCaS^3hUP&*H6P z@g{cx39m5qC2MhbZHG1Oa?@ZxdTBWD74!9mg(vn|Hhc+$$c&uH2M6NQyo;*b*X|lx z`N{T%Ops9{6>1D*0l@%$HD_{yx(iHqE9847u@vVls62W+9`Ec}IFOR4aO&~uDj{U* z2f9QsUTaYDw_RIWje!Eb-N-qii3E{)kJ6iaVg;}W?JBFagCoMH+zVqvX=I?a=2)om zy_5v%+unOqLt!9Y2Af%X>gxFwN`mnoXc`#@gkUPW^n;#$#eed|S?lQy6l{7KEhx*~ zvmgKwk0Vz#f9#12alP;>hbXFl`u(pxW8vR5)4Z+oX&31ZFM&9ygm3Xp>vjteiq2SV z@T+{W(mNbDGY)6c@GZ%CdjM=0UaCWXBhPE|2IBALc}dv7|FzQtCh!=m7lAa>i`#Zy z;zyhZyN~aihu;k%e8=gM{+Y19+m@^Nh=on3xtFzOw ztGZ`yX;&ZW#o5=9h6ph|RoUFYfm+OOo)}kw&|;Yf{7-i3X2TA&MA9Kz=#RXG)tyi> z!r{wN*!cR#^GjD3)!X-v_xBUi1=xtyuTS*60X8{@()lXLYnaNek;~mrMW)n}V(O|% z)9_d|H#IkCEp0Yx1ZcM;b$N4`S2tg z3wEh#32k2LSav#Nf>10IZl%GTrYp6szw7Na-5NhH zr{6~ZdGZ4x*eK_;n2GX!h-Wb5o8qnVCAidd)n81Lv|xs_Ow&jLc7FCnF9#GmxvF$O zfgMD-;Fd#})1P27NB<*cH4xR5Xo=OwG-w*17k(S(;N}9H@YpGnRwMOF8H2tVli9}h zJKjGu0tQt>fA=*H%3WB2+UK7)wInqA-d_E&0wY83dGX|kjT)x;Z%@?A`+&UtlhW*C zhBd(aH2pnH$T*hNypGJlu%@Z+2H9k)8&c*t1j$)*GkQl-3#3+bW zE;~$U90yOjD|=d$#WNA3a5!@9a*m>@tQ9qkFv7L5>%E=)6>O(-&h+bGY0#@{-)v9K zCdb7I6)4@koZ2|aA4|Sq<@c6- zE+tT9lF3r8Lb?JJ4)JB9$J$d)*E3q&t+8}Nrj{j{k_&@?`%QCBE@}GA88tfn+I;GA z>~kH|9cJ}_wa?=sXs1fM$kOrc{R~`q6*#)~{kgsJxnd7YsZr9PxlMkA7u==w%e|1M7S2Zk4zQbC+u+t{Z7UcEu8nn+2HR&J zy0u*{PS`f2uN|!f#9&9?6iql4A8{kz#0@15wqM@_fcGYXG41>!&N#uiZWX;Ir4TshA%yFo7IT z{$KG4KVV>ixPVO+`(IcXe=aAa>I|6zH^94Vrt|9+_w`Z=M%-F~4e~_&+w$|y(|adB zXq=(P=Y`%ZevfX3^Zj_2hSP!m)*@eHQ7&75-EL{o;}zO22?Zt#=-O_-Rst9*16n>K z(OWNPkLDNIq1GW=_VE+zoekZbCr+jlMg*ks0bC4x0OFl78Cp1wN8|fn zq&0bjy9GwJ+Un1$b!L%>tWZx78$&}~?h_5w^UnT-vdS$&+3DlRuZ9q@=1Rfhl}1^I zd&ZV3YsF1S8Q3u=qav?}{UE7^6w5*PjmC}pSnqZNs2ZCxBrmx3mdXtqhKq5Jh;m-d zoQwJ4yG{5EkHd`j?JQcSVJW<}AHa;7hsLA&?&gyauB5`~$%gln2$$*Yz(2-fyo`=n zsTGdUy3wh}MipTw5pg$Ub+nI|R*Q`g*Qt&KEq@d29=5UA?W$+j>M#G&g{O5%n)#W~ zleKzAQE_DrLtqL{rk&g9?dw(>{|zAl=sasf+fvdi5MJBd4RR-+$R}CYR#;F9C$|tj zM%2G)EXQrBs@xg_r~>abayRL+9nzdnK}MW-9wBTiy3v8H+uG@VSn_!{lu7*|#L8)&A~zq83@$4ds52Nv-9K+aDEH&GLV+mi#u5C{?D`_tiA;) zj!lRS%W7J?bTjNUUmU*5eSi90MPXwh|6GWL9+LBOr@8wR@{o-B@r)41HcA$1@VWK& zcMMws&8v!TU=wbJa&!iMmWFGQ@b@7IV=J8iFo03wbV0abo-VZieY6SZOzPWErjE8k znMpN<(CGK_!HGBiRm9R0Y^C#T0RR!|^|Mq)T$}`t^X2(Q{>Woh(#X}!sLDM%`tP9m zwoi#*%Of%hjoZ^QZo5h4!X}K+%Wysm_s)~8)%##VS-^BY=#hXc z3ACy4+(-E+MR5wl{)U=jb9k~3jad?os6-2+9Z8EaA1=W1Mv;?}_e%nbx=pPOTav8F`#<;(#_LY6y!EN2EIV{yk=(d7`-e_cm@ovRJ>`8m`EELIV`pj6Z zM3Yiim)&9Jf`jEtm_hYma0iRyoWm_%-HdjBI@^Jv{&CX;HSa3C6je7{xmek`QR&I{ z9n}M$onca@;SDPZ8JPz(2{rIk6s7uXR|1NuV>M2*HW=os5I~ReFBV&e8J)HK?_fQ| z2nZs6y)fD$k@C1pHUTTr6u13tu9|dYK$}OVcZW=y@c&&jD zPFZ<~=J9MT-e+QK-}^2#+qGe><U%oYmOt@|*+DWM>L|sh&kX_r zsfGt3DOvjW zOtC-UAb&&BfucirF9AISjtW*97mZeQ8CnQ-=*(rdgr%yJ1_ROSpfG2=D_dNS?aIXkoyPj=n|D>K(y zkH~Z%%8tw^2rWAD zyg$opklIiO&VaWQPk#OmkObTurO8 z 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 literal 0 HcmV?d00001 diff --git a/docs/admin/EventManagement/EventManagement.php b/docs/admin/EventManagement/EventManagement.php new file mode 100644 index 0000000..c655301 --- /dev/null +++ b/docs/admin/EventManagement/EventManagement.php @@ -0,0 +1,19 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: EventManagement.php,v 1.0 2011/01/25 19:31:47 cscott Exp $ + * @link <> + */ + +require_once '../../setup.phtml'; +require_once $applicationConfig->commonApps->base_path.$applicationConfig->event_management->version.'/controllers/AdminController.php'; + +?> \ No newline at end of file diff --git a/docs/barcode/FRE3OF9X.TTF b/docs/barcode/FRE3OF9X.TTF new file mode 100644 index 0000000000000000000000000000000000000000..1223b010167937c2ef56cf949f4b4fb62bc0b9ad GIT binary patch literal 7220 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 IZmh2RFRl + +iQA/AwUBOmY8/uEM8BJ4ZA+2EQLSDgCgqHT1WtBW34v7JAQr4+1zCzUaeGgAn2uu +stjL0d7RVR5C5p2zpks371e9 +=jqNv +-----END PGP SIGNATURE----- diff --git a/docs/config.ini.SAMPLE b/docs/config.ini.SAMPLE new file mode 100644 index 0000000..d49e692 --- /dev/null +++ b/docs/config.ini.SAMPLE @@ -0,0 +1,664 @@ +; +; Travel Information System +; +[common] + +applicationName = "Event Housing" + +; +; *** General Configuration for Event Housing System *** +; + +; Base URL/paths for front-end of this application +url.front_end = CURRENT_BASE_URL "/Toolkit/Event_Housing-" EVENT_HOUSING_HOME_PAGE "/" +url.admin = CURRENT_BASE_URL "/admin/Event_Housing/" +path.front_end = BASE_PATH "/Toolkit/Event_Housing/" +path.admin = BASE_PATH "/admin/Event_Housing" + +; Interface Selection +default_admin_interface = "panels" +admin_interface.panels = "panels" + + +; Basic Customer Information +customer.name = "Great Lakes Bay" +customer.long_name = "Great Lakes Bay Regional Convention & Visitiors Bureau" +customer.phone = "989-752-7164" +customer.fax = "" +customer.toll_free = "800-444-9979" +customer.address = "515 N. Washington Ave., Third Floor" +customer.city = "Saginaw" +customer.state = "MI" +customer.zip = "48607" +customer.email = "cscott@gaslightmedia.com" +customer.internal_email = "cscott@gaslightmedia.com" +customer.from_email = "cscott@gaslightmedia.com" +customer.letter_closing = "Sincerely," + + +customer.assistance_info = " +If you need assistance within the administration area or have questions, please contact:
    +Gaslight Media Web Site Support Services at 231-487-0692 or +E-Mail us at info@gaslightmedia.com +" + +; General Travel Information System Options +option.member_db = "Integrated" ;Use Standard Member DB: Integrated = Use standard Member DB, Separate = Use Separate Member DB +option.conventions = true +option.reservations = false ;Enable Reservations for members (not event housing) +option.tickets = false ;Enable Ticket Sales +option.packages = false ;Enable Packages +option.housing = true ;Enable Event housing +option.registrations = false ;Enable Convention Registrations +option.tours = false ;Enable Tour Package Data +option.reservations = false ;Enable regular reservations +option.secret = "GLMTravelSecret" ;Secret Key used to create un-predictable values +option.admin_help = true ;Enable online help for member admin area +option.email_style = "text" ;Email to customer style = 'text', 'html', 'both', 'pdf', ... +option.promotions = false +option.member_edit = false +option.member_assistance = "For assistance call Great Lakes Bay Regional Convention & Visitiors Bureau at 989-752-7164." + +; Misc options +misc.letter_closing = "Sincerely," + +; Set Database Date Style - uncomment desired style +;misc.datestyle = "SET DATESTYLE TO 'ISO';" ;ISO example: 1997-12-17 07:37:16-08';\n" +misc.datestyle = "SET DATESTYLE TO 'SQL';" ;SQL example: 12/17/1997 07:37:16.00 PST';\n" +;misc.datestyle = "SET DATESTYLE TO 'Postgres';" ;Postgres example: Wed Dec 17 07:37:16 1997 PST';\n" +;misc.datestyle = "SET DATESTYLE TO 'European';" ;European example: 17/12/1997 15:37:16.00 MET';\n" +;misc.datestyle = "SET DATESTYLE TO 'US';" ;US example: 12/17/1997 07:37:16.00 PST';\n" +;misc.datestyle = "SET DATESTYLE TO 'German';" ;German example: 17.12.1997 07:37:16.00 PST';\n" + +; +; Event Housing specific parameters +; +housing.system_title = "Gaslight Media - Event Housing" +housing.select_method = "List" ;Method of selecting Conventions, "Pick" - Picklist, "List" - Detailed list +housing.sort_order = "Distance" ;Member list sort order ("Alpha", "Distance", "PseudoRandom", etc) +housing.hold_timeout = 10 ;Hold time in minutes for accommodations in process of being booked +housing.require_member_ccards = true ;Members must offer credit cards to make properties available for booking +housing.proc_method = "authorize" ;Cards processed by authorize.net (see proc_method below) +housing.inventory = true ;Enable Convention Housing Inventory +housing.golf = false ;Enable Convention Golf + +; Terms used to refer to events/conventions +housing.terms.event.norm = "event" +housing.terms.event.cap = "Event" +housing.terms.event.plur = "events" +housing.terms.event.plur_cap = "Events" + +; Terms used to refer to a housing Property/Hotel +housing.terms.prop.norm = "property" +housing.terms.prop.cap = "Property" +housing.terms.prop.plur = "properties" +housing.terms.prop.plur_cap = "Properties" + +; Terms used to refer to a housing unit +housing.terms.unit.norm = "accommodation" +housing.terms.unit.cap = "Accommodation" +housing.terms.unit.plur = "accommodations" +housing.terms.unit.plur_cap = "Accommodations" + +; +; General Reservations specific parameters +; +reservations.promotions = false ;Enable reservations promotions +reservations.hotel = true ;Hotel/Motel reservations +reservations.campground = false ;Campground reservations +reservations.bedandbreakfast = false ;Bed/Breakfast reservations +reservations.condo = false ;Condo/Home reservations +reservations.marina = false ;Marina reservations +reservations.max_days = 15 ;Maximum number of reservation days +reservations.max_rooms = 30 ;Maximum number of rooms reserveable at once + +; Calendar parameters +calendar.months_before = 2 +calendar.months_after = 24 +calendar.links_before = 1 +calendar.links_after = 1 + + +; +; Other misc site related setttings +; + +; Image information +image_server = "is0.gaslightmedia.com" +image_user = "greatlakesbayregion" +image_style.1 = "memberPhotos" +image_style.2 = "tbs1" +image_style.3 = "pgs2" + +; +; *** End of General Configuration for Event Housing System *** +; + +; Standard arrays + +; Processing Methods +proc_method.1 = merchant ;Merchant processes cards +proc_method.2 = authorize ;Processed by Authorize.net + +; Processing Status +proc_status.new = 0 +proc_status.descr.0 = "New Registration Record" +proc_status.unpaid = 1 +proc_status.descr.1 = "Not Paid" +proc_status.cc_pend = 2 +proc_status.descr.2 = "Credit Card Pending" +proc_status.cc_paid = 3 +proc_status.descr.3 = "Paid by Credit Card" +proc_status.cc_decl = 4 +proc_status.descr.4 = "Credit Card Declined" +proc_status.check_pend = 5 +proc_status.descr.5 = "Check Pending" +proc_status.check_paid = 6 +proc_status.descr.6 = "Paid by Check" +proc_status.comp = 7 +proc_status.descr.7 = "Complimentary" +proc_status.failed = 98 +proc_status.descr.98 = "Submission Failed" +proc_status.canceled = 99 +proc_status.descr.99 = "Canceled" + +; Payment Types +pay_types.1 = "Credit Card" +pay_types.2 = "Check" +pay_types.3 = "Direct" + +; Confirmation Methods +conf_methods.1 = "US Mail" +conf_methods.2 = "E-Mail" + +; Reference Types +reference_type.misc = 0 +reference_type.event = 1 +reference_type.property = 2 +reference_type.state = 3 +reference_type.team = 4 + +; Reference Type Numbers +reference_type_numb.0 = "Misc" +reference_type_numb.1 = "Event" +reference_type_numb.2 = "Property" +reference_type_numb.3 = "State Rep" +reference_type_numb.4 = "Team" + +; Fee Method +fee_method.fixed_stay = 1 +fee_method.fixed_accom = 2 +fee_method.fixed_accomnight = 3 +fee_method.percent_stay = 10 + +; Fee Method Numbers +fee_method_numb.1 = "Amount per Reservation" +fee_method_numb.2 = "Amount per Accommodation" +fee_method_numb.3 = "Amount per Accommodation/Night" +fee_method_numb.10 = "Percent of Room Rate" + +; Member/Property Amenities +; Static amenitities set system-wide +; Only 10 fields in member records for these at this time +; Needs to be replaced with managed amenities list +memb_amen.1 = "Air-Conditioning" +memb_amen.2 = "Barrier Free" +memb_amen.3 = "Coffee Pot" +memb_amen.4 = "Hair Dryer" +memb_amen.5 = "Interior Corridor" +memb_amen.6 = "Microwave" +memb_amen.7 = "Refrigerator" +;memb_amen.8 = "Shopping nearby" +;memb_amen.9 = "Indoor pool" +;memb_amen.10 = "Outdoor pool" +;memb_amen.? = "Sauna" +;memb_amen.? = "Whirlpool" +;memb_amen.? = "Valet/Charge Parking" +;memb_amen.? = "Self-operated coin laundry" +;memb_amen.? = "Free parking" +;memb_amen.? = "Fitness area" +;memb_amen.? = "Room service" +;memb_amen.? = "Conference/Meeting facilities" +;memb_amen.? = "Restaurant nearby" +;memb_amen.? = "Restaurant on site" +;memb_amen.? = "Barrier free guest rooms available" +;memb_amen.? = "Pets" +;memb_amen.? = "Golf nearby" + +; Accommodatation Amenitities +; NOT USED AT THIS TIME +;accom_amen.1 = "Cable TV" +;accom_amen.2 = "Movies in Room" +;accom_amen.3 = "Barrier Free Access" +;accom_amen.4 = "Smoke Free Room" +;accom_amen.5 = "Jacuzzi in Room" +;accom_amen.6 = "Iron and Ironing Board" +;accom_amen.7 = "Coffee Pot in Room" +;accom_amen.8 = "Refrigerator in Room" +;accom_amen.9 = "Microwave in Room" +;accom_amen.10 = "Safe" +;accom_amen.11 = "Hair Dryer" + +; Accommodation Room Categories +room_category.0 = "n/a" +room_category.1 = "Bed" +room_category.2 = "Room" +room_category.3 = "Suite" + +; Accommodation Room Types +room_types.0 = "n/a" +room_types.1 = "Main" +room_types.2 = "Bedroom" +room_types.3 = "Kitchen" +room_types.4 = "Living Room" + +; Accommodation Bath Types +bath_types.0 = "None" +bath_types.1 = "Full" +bath_types.2 = "Half" +bath_types.3 = "Sink" + +; States +states.AL = "Alabama" +states.AK = "Alaska" +states.AB = "Alberta" +states.AZ = "Arizona" +states.AR = "Arkansas" +states.BC = "British Columbia" +states.CA = "California" +states.CO = "Colorado" +states.CT = "Connecticut" +states.DE = "Delaware" +states.DC = "District of Columbia" +states.FL = "Florida" +states.GA = "Georgia" +states.GU = "Guam" +states.HI = "Hawaii" +states.ID = "Idaho" +states.IL = "Illinois" +states.IN = "Indiana" +states.IA = "Iowa" +states.KS = "Kansas" +states.KY = "Kentucky" +states.LA = "Louisiana" +states.ME = "Maine" +states.MB = "Manitoba" +states.MD = "Maryland" +states.MA = "Massachusetts" +states.MI = "Michigan" +states.MN = "Minnesota" +states.MS = "Mississppi" +states.MO = "Missouri" +states.MT = "Montana" +states.NE = "Nebraska" +states.NV = "Nevada" +states.NB = "New Brunswick" +states.NF = "Newfoundland" +states.NH = "New Hampshire" +states.NJ = "New Jersey" +states.NM = "New Mexico" +states.NY = "New York" +states.NC = "North Carolina" +states.ND = "North Dakota" +states.NT = "Northwest Territories" +states.NS = "Nova Scotia" +states.OH = "Ohio" +states.OK = "Oklahoma" +states.ON = "Ontario" +states.OR = "Oregon" +states.PA = "Pennsylvania" +states.PE = "Prince Edward Island" +states.PR = "Puerto Rico" +states.QC = "Quebec" +states.RI = "Rhode Island" +states.SK = "Saskatchewan" +states.SC = "South Carolina" +states.SD = "South Dakota" +states.TN = "Tennessee" +states.TX = "Texas" +states.UT = "Utah" +states.VT = "Vermont" +states.VI = "Virgin Islands" +states.VA = "Virginia" +states.WA = "Washington" +states.WV = "West Virginia" +states.WI = "Wisconsin" +states.WY = "Wyoming" +states.YT = "Yukon" + +; Countries +countries.US = "United States" +countries.CA = "Canada" +countries.AF = "Afghanistan" +countries.AX = "Land Islands" +countries.AL = "Albania" +countries.DZ = "Algeria" +countries.AS = "American Samoa" +countries.AD = "Andorra" +countries.AO = "Angola" +countries.AI = "Anguilla" +countries.AQ = "Antarctica" +countries.AG = "Antigua and Barbuda" +countries.AR = "Argentina" +countries.AM = "Armenia" +countries.AW = "Aruba" +countries.AU = "Australia" +countries.AT = "Austria" +countries.AZ = "Azerbaijan" +countries.BS = "Bahamas" +countries.BH = "Bahrain" +countries.BD = "Bangladesh" +countries.BB = "Barbados" +countries.BY = "Belarus" +countries.BE = "Belgium" +countries.BZ = "Belize" +countries.BJ = "Benin" +countries.BM = "Bermuda" +countries.BT = "Bhutan" +countries.BO = "Bolivia" +countries.BA = "Bosnia and Herzegovina" +countries.BW = "Botswana" +countries.BV = "Bouvet Island" +countries.BR = "Brazil" +countries.IO = "British Indian Ocean Territory" +countries.BN = "Brunei Darussalam" +countries.BG = "Bulgaria" +countries.BF = "Burkina Faso" +countries.BI = "Burundi" +countries.KH = "Cambodia" +countries.CM = "Cameroon" +countries.CV = "Cape Verde" +countries.KY = "Cayman Islands" +countries.CF = "Central African Republic" +countries.TD = "Chad" +countries.CL = "Chile" +countries.CN = "China" +countries.CX = "Christmas Island" +countries.CC = "Cocos (Keeling) Islands" +countries.CO = "Colombia" +countries.KM = "Comoros" +countries.CG = "Congo" +countries.CD = "Congo, the Democratic Rep. of" +countries.CK = "Cook Islands" +countries.CR = "Costa Rica" +countries.CI = "Cote D'Ivoire" +countries.HR = "Croatia" +countries.CU = "Cuba" +countries.CY = "Cyprus" +countries.CZ = "Czech Republic" +countries.DK = "Denmark" +countries.DJ = "Djibouti" +countries.DM = "Dominica" +countries.DO = "Dominican Republic" +countries.EC = "Ecuador" +countries.EG = "Egypt" +countries.SV = "El Salvador" +countries.GQ = "Equatorial Guinea" +countries.ER = "Eritrea" +countries.EE = "Estonia" +countries.ET = "Ethiopia" +countries.FK = "Falkland Islands (Malvinas)" +countries.FO = "Faroe Islands" +countries.FJ = "Fiji" +countries.FI = "Finland" +countries.FR = "France" +countries.GF = "French Guiana" +countries.PF = "French Polynesia" +countries.TF = "French Southern Territories" +countries.GA = "Gabon" +countries.GM = "Gambia" +countries.GE = "Georgia" +countries.DE = "Germany" +countries.GH = "Ghana" +countries.GI = "Gibraltar" +countries.GR = "Greece" +countries.GL = "Greenland" +countries.GD = "Grenada" +countries.GP = "Guadeloupe" +countries.GU = "Guam" +countries.GT = "Guatemala" +countries.GN = "Guinea" +countries.GW = "Guinea-Bissau" +countries.GY = "Guyana" +countries.HT = "Haiti" +countries.HM = "Heard Island, McDonald Islands" +countries.VA = "Holy see (Vatican City State)" +countries.HN = "Honduras" +countries.HK = "Hong Kong" +countries.HU = "Hungary" +countries.IS = "Iceland" +countries.IN = "India" +countries.ID = "Indonesia" +countries.IR = "Iran, Islamic Republic of" +countries.IQ = "Iraq" +countries.IE = "Ireland" +countries.IL = "Israel" +countries.IT = "Italy" +countries.JM = "Jamaica" +countries.JP = "Japan" +countries.JO = "Jordan" +countries.KZ = "Kazakhstan" +countries.KE = "Kenya" +countries.KI = "Kiribati" +countries.KP = "Korea, Democratic People's Rep. of" +countries.KR = "Korea, Republic of" +countries.KW = "Kuwait" +countries.KG = "Kyrgyzstan" +countries.LA = "Lao People's Democratic Republic" +countries.LV = "Latvia" +countries.LB = "Lebanon" +countries.LS = "Lesotho" +countries.LR = "Liberia" +countries.LY = "Libyan Arab Jamahiriya" +countries.LI = "Liechtenstein" +countries.LT = "Lithuania" +countries.LU = "Luxembourg" +countries.MO = "Macao" +countries.MK = "Macedonia, the Former Yugoslav Rep." +countries.MG = "Madagascar" +countries.MW = "Malawi" +countries.MY = "Malaysia" +countries.MV = "Maldives" +countries.ML = "Mali" +countries.MT = "Malta" +countries.MH = "Marshall Islands" +countries.MQ = "Martinique" +countries.MR = "Mauritania" +countries.MU = "Mauritius" +countries.YT = "Mayotte" +countries.MX = "Mexico" +countries.FM = "Micronesia, Federated States of" +countries.MD = "Moldova, Republic of" +countries.MC = "Monaco" +countries.MN = "Mongolia" +countries.MS = "Montserrat" +countries.MA = "Morocco" +countries.MZ = "Mozambique" +countries.MM = "Myanmar" +countries.NA = "Namibia" +countries.NR = "Nauru" +countries.NP = "Nepal" +countries.NL = "Netherlands" +countries.AN = "Netherlands Antilles" +countries.NC = "New Caledonia" +countries.NZ = "New Zealand" +countries.NI = "Nicaragua" +countries.NE = "Niger" +countries.NG = "Nigeria" +countries.NU = "Niue" +countries.NF = "Norfolk Island" +countries.MP = "Northern Mariana Islands" +countries.NO = "Norway" +countries.OM = "Oman" +countries.PK = "Pakistan" +countries.PW = "Palau" +countries.PS = "Palestinian Territory, Occupied" +countries.PA = "Panama" +countries.PG = "Papua New Guinea" +countries.PY = "Paraguay" +countries.PE = "Peru" +countries.PH = "Philippines" +countries.PN = "Pitcairn" +countries.PL = "Poland" +countries.PT = "Portugal" +countries.PR = "Puerto Rico" +countries.QA = "Qatar" +countries.RE = "Reunion" +countries.RO = "Romania" +countries.RU = "Russian Federation" +countries.RW = "Rwanda" +countries.SH = "Saint Helena" +countries.KN = "Saint Kitts and Nevis" +countries.LC = "Saint Lucia" +countries.PM = "Saint Pierre and Miquelon" +countries.VC = "Saint Vincent and the Grenadines" +countries.WS = "Samoa" +countries.SM = "San Marino" +countries.ST = "Sao Tome and Principe" +countries.SA = "Saudi Arabia" +countries.SN = "Senegal" +countries.CS = "Serbia and Montenegro" +countries.SC = "Seychelles" +countries.SL = "Sierra Leone" +countries.SG = "Singapore" +countries.SK = "Slovakia" +countries.SI = "Slovenia" +countries.SB = "Solomon Islands" +countries.SO = "Somalia" +countries.ZA = "South Africa" +countries.GS = "South Georgia, South Sandwich Islands" +countries.ES = "Spain" +countries.LK = "Sri Lanka" +countries.SD = "Sudan" +countries.SR = "Suriname" +countries.SJ = "Svalbard and Jan Mayen" +countries.SZ = "Swaziland" +countries.SE = "Sweden" +countries.CH = "Switzerland" +countries.SY = "Syrian Arab Republic" +countries.TW = "Taiwan, Province of China" +countries.TJ = "Tajikistan" +countries.TZ = "Tanzania, United Republic of" +countries.TH = "Thailand" +countries.TL = "Timor-Leste" +countries.TG = "Togo" +countries.TK = "Tokelau" +countries.TO = "Tonga" +countries.TT = "Trinidad and Tobago" +countries.TN = "Tunisia" +countries.TR = "Turkey" +countries.TM = "Turkmenistan" +countries.TC = "Turks and Caicos Islands" +countries.TV = "Tuvalu" +countries.UG = "Uganda" +countries.UA = "Ukraine" +countries.AE = "United Arab Emirates" +countries.GB = "United Kingdom" +countries.UM = "United States minor outlying islands" +countries.UY = "Uruguay" +countries.UZ = "Uzbekistan" +countries.VU = "Vanuatu" +countries.VE = "Venezuela" +countries.VN = "Viet Nam" +countries.VG = "Virgin Islands, British" +countries.VI = "Virgin Islands, U.S." +countries.WF = "Wallis and Futuna" +countries.EH = "Western Sahara" +countries.YE = "Yemen" +countries.ZM = "Zambia" +countries.ZW = "Zimbabwe" + +;HTML Area +htmlarea.enabled = true +htmlarea.setup_delay = 1000 +htmlarea.start_delay = 500 +htmlarea.plugs = " + editor.registerPlugin(CharacterMap); + editor.registerPlugin(ContextMenu); + editor.registerPlugin(ListType); + editor.registerPlugin(TableOperations); +" +htmlarea.toolbar = " + config.toolbar = + [ + [ + "fontname", + "fontsize", + "formatblock", + "space", + "bold", + "italic", + "underline", + "strikethrough", + "separator", + "subscript", + "superscript", + "separator", + "copy", + "cut", + "paste", + "space", + "undo", + "redo" + ], + [ + "justifyleft", + "justifycenter", + "justifyright", + "justifyfull", + "separator", + "lefttoright", + "righttoleft", + "separator", + "ListType", + "insertorderedlist", + "insertunorderedlist", + "separator", + "outdent", + "indent", + "separator", + "forecolor", + "hilitecolor", + "separator", + "inserthorizontalrule", + "createlink", + "inserttable", + "htmlmode", + "separator", + "popupeditor" + ] + ]; +" + +[production : common] +; Debugging and Testing parameters +option.preview = false ;Use "preview=1" in links to support preview feature +debug.level = 0 ;Debug level - 0=off +debug.view_parameters = false ;Display all View tags and information +debug.housing_query = false ;Display main housing query +debug.pricing = false ;Detailed information on pricing and cost calculations +debug.checkout = false ;Display checkout processing steps and data +debug.mail = false ;Display mail rather than send it +url.app = "app.gaslightmedia.com/" + +[development : common] +; Debugging and Testing parameters +option.preview = true ;Use "preview=1" in links to support preview feature +debug.level = 0 ;Debug level - 0=off +debug.view_parameters = false ;Display all View tags and information +debug.housing_query = false ;Display main housing query +debug.pricing = false ;Detailed information on pricing and cost calculations +debug.checkout = false ;Display checkout processing steps and data +debug.mail = faLse ;Display mail rather than send it +url.app = "dev52.gaslightmedia.com/app.gaslightmedia.com/" + +[chuck : common] +; Debugging and Testing parameters +option.preview = true ;Use "preview=1" in links to support preview feature +debug.level = 0 ;Debug level - 0=off, 1=Show Function Calls +debug.view_parameters = true ;Display all View tags and information +debug.housing_query = false ;Display main housing query +debug.pricing = false ;Detailed information on pricing and cost calculations +debug.checkout = true ;Display checkout processing steps and data +debug.mail = false ;Display mail rather than send it +url.app = "192.168.44.3/app.gaslightmedia.com/" diff --git a/docs/config/applications/EventManagement.ini b/docs/config/applications/EventManagement.ini new file mode 100644 index 0000000..7ef5dd1 --- /dev/null +++ b/docs/config/applications/EventManagement.ini @@ -0,0 +1,227 @@ +; EventManagement Application ini file + +[production] + +; Event Management V3 + +; The page id in the toolbox that is the entry page for Event management - Generally set for each server +application_page = 121 ;Page ID for this application +application_url = "order-tickets-online-6" ;Optional URL segment for application + +members_only_page = 122 ;Page ID for members only area +members_only_url = "members-only-area" ;Optional URL segment for members only area + +option.member_db_integrated = false ;Use Standard Member DB: true = Use standard Member DB, false = Use Separate Member DB +option.events = false +option.accommodations = false ;Enable Reservations for members (not event housing) +option.tickets = true ;Enable Ticket Sales + option.tickets_select_max = 50 ; Maximum ticket quantity that can be selected at a time +option.packages = false ;Enable Packages +option.teams = false ;Enable Team housing features +option.registrations = false ;Enable Convention Registrations +option.select_images = false ;Display venue, event, and other images on the selection pages - other than maps and such +option.cart_images = false ;Display venue, event, and other images on the cart page +option.cart_images = false ;Display venue, event, and other images on the cart page +option.checkout_images = false ;Display venue, event, and other images on the checkout page +option.cart_promotions = true ;Permit promoting other performances on cart page +option.users_access_all_members = true ;Member contact users can have access to all members data +option.ask_for_likely_date = false ;Ask user for a likely date they would use for non-date-specific tickets (in cart) +option.confirmation_voucher = 'link' ;How to handle voucher with confirmation E-Mail: Off, 'link', 'attached' + +jQueryLoaded = true ;Say whether jQuery is already loaded by the site +jQueryUiLoaded = true ;Say whether jQueryUI is already loaded by the site + +ticket_hold_time = 60 ;Time in minutes to hold tickets in a cart +session_timeout = 60 ;Time in minutes before session times out +admin_session_timeout = 1560 ;Time in minutes before admin session times out + +; Front-End Appearance Settings +default_front_interface = "tickets" +custom_css = false ;Should look for /css/EventManangement.css in customer site +voucher_design = "Generic" ;Design file to use for vouchers - See /models/vouchers directory +site_has_foundation = true ;Site already loads foundation - blocks loading in ticketing front-end header + +; Admin Appearance Settings +default_admin_interface = "tickets" + +; Ticket Selection Process Options +option.ticket_selection.start_at_cart = true ;Start with shopping cart - Used with cart-sticky items. +option.ticket_selection.show_tickets_on_start_page = true ;Should we show the tickets on the selection start page or just venues/performances +option.ticket_selection.force_section = false ;Always show section selection even if there's only one +option.ticket_selection.include_options_in_ticket_list = true ;Include ticket options in ticket selection list (date, quant, etc) +option.ticket_selection.select_entrance_on_consignment = true ;If selling a ticket on consignment and the user has to select a venu to purchase the + ; ticket from, if entrances are listed for a venu, use entrances for selection rather than + ; just venue. +option.ticket_selection.show_cart_sticky_items = true ;Enable/disable cart sticky items + +; Image Styles +image_style.default = "tbs1" +image_style.large = "ticketsLarge" +image_style.medium = "ticketsMedium" +image_style.small = "ticketsSmall" +image_style.thumb = "ticketsThumb" + +; Terms used to refer to events/conventions +term.event.norm = "event" +term.event.cap = "Event" +term.event.plur = "events" +term.event.plur_cap = "Events" + +; Terms used to refer to a housing Member/Property/Hotel +term.prop.norm = "location" +term.prop.cap = "Location" +term.prop.plur = "locations" +term.prop.plur_cap = "Locations" + +; Terms used to refer to contacts +term.contact.norm = "contact" +term.contact.cap = "Contact" +term.contact.plur = "contacts" +term.contact.plur_cap = "Contacts" + +; Terms used to refer to scan/claim locations +term.claim_location.norm = "claim location" +term.claim_location.cap = "Claim Location" +term.claim_location.plur = "claim locations" +term.claim_location.plur_cap = "Claim Locations" + +; Terms used to refer to a housing unit +term.unit.norm = "room" +term.unit.cap = "Room" +term.unit.plur = "rooms" +term.unit.plur_cap = "Rooms" + +; Terms used to refer to an entrance +term.entrance.norm = "dock" +term.entrance.cap = "Dock" +term.entrance.plur = "docks" +term.entrance.plur_cap = "Docks" + +; Terms used to refer to a section +term.section.norm = "section" +term.section.cap = "Section" +term.section.plur = "sections" +term.section.plur_cap = "Sections" + +; Terms used to refer to a performance +term.performance.norm = "category" +term.performance.cap = "Category" +term.performance.plur = "categories" +term.performance.plur_cap = "Categories" + +; Terms used to refer to a ticket +term.ticket.norm = "item" +term.ticket.cap = "Item" +term.ticket.plur = "items" +term.ticket.plur_cap = "Items" + +; Terms used to refer to an order +term.order.norm = "order" +term.order.cap = "Order" +term.order.plur = "orders" +term.order.plur_cap = "Orders" + +; Terms used to refer to a voucher +term.voucher.norm = "boarding pass" +term.voucher.cap = "Boarding Pass" +term.voucher.plur = "boarding passes" +term.voucher.plur_cap = "Boarding Passes" + +; Terms used to refer to a promotion +term.promo.norm = "promo code" +term.promo.cap = "Promo Code" +term.promo.plur = "promo codes" +term.promo.plur_cap = "Promo Codes" + +; Terms used to refer to an attendance +term.attendance.norm = "attendance" +term.attendance.cap = "Attendance" +term.attendance.plur = "attendance" +term.attendance.plur_cap = "Attendance" + +; Terms used to refer to an attendee +term.attendee.norm = "attendee" +term.attendee.cap = "Attendee" +term.attendee.plur = "attendees" +term.attendee.plur_cap = "Attendees" + +; Terms used to refer to an attendace log +term.attendance_log.norm = "attendance log" +term.attendance_log.cap = "Attendance Log" +term.attendance_log.plur = "attendance logs" +term.attendance_log.plur_cap = "Attendance Logs" + +; Terms used to refer to entering (attendance) +term.attendance_entering.norm = "entering" +term.attendance_entering.cap = "Entering" +term.attendance_entering.plur = "entering" +term.attendance_entering.plur_cap = "Entering" + +; Terms used to refer to the start of a performance (event) +term.performance_start.norm = "start of performance" +term.performance_start.cap = "Start of Performance" +term.performance_start.plur = "start of performances" +term.performance_start.plur_cap = "Start of Performances" + +; Terms used to refer to the end of a performance (event) +term.performance_end.norm = "end of performance" +term.performance_end.cap = "End of Performance" +term.performance_end.plur = "end of performances" +term.performance_end.plur_cap = "End of Performances" + +; Terms used to refer to Coupons (advertisements) for vouchers +term.coupon.norm = "voucher coupon" +term.coupon.cap = "Voucher Coupon" +term.coupon.plur = "voucher coupons" +term.coupon.plur_cap = "Voucher Coupons" + +; Terms used for front-end shop navigation buttons +;term.nav.show_selected = "Show Cart" +term.nav.show_selected = "Cart" +term.nav.select = "Select" +;term.nav.select_more = "Select More" +term.nav.select_more = "Shop" +;term.nav.select_more_of_these = "Select More of These" +term.nav.select_more_of_these = "More" +term.nav.add_to_cart = "Add to Cart" +term.nav.checkout = "Proceed to Checkout" +term.nav.purchase = "Click to Purchase Selected Items" +term.nav.print_vouchers = "Print Vouchers" +term.nav.delete_from_cart = "Delete these items from your cart" + +; Prompts used for shop checkout fields +text.cart.checkout.first_name = "First Name" +text.cart.checkout.last_name = "Last Name" +text.cart.checkout.address = "Address" +text.cart.checkout.city = "City" +text.cart.checkout.state = "State/Province" +text.cart.checkout.country = "Country" +text.cart.checkout.zip = "ZIP/Postal Code" +text.cart.checkout.phone = "Phone" +text.cart.checkout.email = "E-Mail Address" +text.cart.checkout.email_again = "Enter E-Mail Address Again" +text.cart.checkout.ok_to_send = "OK to Send E-Mail?" +text.cart.checkout.special_req = "" ; If blank, don't use +text.cart.checkout.activities_offers = "Please send information on activities and offers." + +; Other text used in the front end +text.cart.select_assignment_location = "Please select the dock you are going to depart from." +text.cart.select_likely_date = "Please select your likely departure date." ;For non-date-specific tickets + +; development server configuration data inherits from production and +; overrides values as necessary +[development : production] + +; chuck's server configuration data inherits from development +; and overrides values as necessary +[chuck : development] + + +; john's server configuration data inherits from development +; and overrides values as necessary +[john : development] + +; steve's server configuration data inherits from development +; and overrides values as necessary +[steve : development] + diff --git a/help.html b/help.html new file mode 100644 index 0000000..af07d38 --- /dev/null +++ b/help.html @@ -0,0 +1,96 @@ + + + + + + + +

    +

    Gaslight Media
    Event Management System

    +
    + +
    + + +

    General Description

    +

    + General description of system goes here. +

    + + +
    System Structure +

    + Discussion about system structure. +

    +
    + + +
    Non-Team Events +

    + Discussion about Non-Team Events. +

    +
    + + +
    Team Events +

    + Discussion about Team Events. +

    +
    + +
    +
    + + +

    Common Proceedures

    +

    + General description of common proceedures goes here. +

    + + +
    System Setup +

    + Discussion about setting up system information. +

    +
    + +
    + + + \ No newline at end of file diff --git a/index.html b/index.html new file mode 100644 index 0000000..2f069ce --- /dev/null +++ b/index.html @@ -0,0 +1,17 @@ +
    +
    +
    This is the report area....
    +

    + some stuff goes here +

    +
    +
    + +{startScript:h} + + // jQuery Section + $(document).ready(function(){ + + }); + + \ No newline at end of file diff --git a/models/admin/actions/Accommodation/add.inc b/models/admin/actions/Accommodation/add.inc new file mode 100644 index 0000000..746f00c --- /dev/null +++ b/models/admin/actions/Accommodation/add.inc @@ -0,0 +1,30 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: event.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/accommodations.php'; +$Accoms = new EventManagementAdminAccoms($this->dbh, $this->config); +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/rooms.php'; +$Rooms = new EventManagementAdminRooms($this->dbh, $this->config); + + +$r = $Accoms->newAccom(); + +$this->page->accomDetail = $this->bindArrayToObject($r['fieldData']); +$this->page->fieldRequired = $this->bindArrayToObject($r['fieldRequired']); +$this->page->fieldFail = $this->bindArrayToObject($r['fieldFail']); +$this->page->addingNewAccom = true; + +$this->templateFile = 'Accommodation/EditAccommodation.html'; + +?> \ No newline at end of file diff --git a/models/admin/actions/Accommodation/addRoom.inc b/models/admin/actions/Accommodation/addRoom.inc new file mode 100644 index 0000000..c5c9d1a --- /dev/null +++ b/models/admin/actions/Accommodation/addRoom.inc @@ -0,0 +1,30 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: event.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/accommodations.php'; +$Accoms = new EventManagementAdminAccoms($this->dbh, $this->config); +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/rooms.php'; +$Rooms = new EventManagementAdminRooms($this->dbh, $this->config); + + +$r = $Rooms->newRoom(); + +$this->page->roomDetail = $this->bindArrayToObject($r['fieldData']); +$this->page->fieldRequired = $this->bindArrayToObject($r['fieldRequired']); +$this->page->fieldFail = $this->bindArrayToObject($r['fieldFail']); +$this->page->addingNewRoom = true; + +$this->templateFile = 'Accommodation/EditRoom.html'; + +?> \ No newline at end of file diff --git a/models/admin/actions/Accommodation/detail.inc b/models/admin/actions/Accommodation/detail.inc new file mode 100644 index 0000000..b8f20cf --- /dev/null +++ b/models/admin/actions/Accommodation/detail.inc @@ -0,0 +1,31 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: event.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/accommodations.php'; +$Accoms = new EventManagementAdminAccoms($this->dbh, $this->config); +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/rooms.php'; +$Rooms = new EventManagementAdminRooms($this->dbh, $this->config); + + +// Get Accommodation detail +$accomDetail = $Accoms->getAccomDetail(); +$this->page->accomDetail = $this->bindArrayToObject($accomDetail); + +// Get Rooms list +$roomsList = $Rooms->getRoomsList(); +$this->page->roomsList = $this->bindArrayToObject($roomsList); + +$this->templateFile = 'Accommodation/AccommodationDetail.html'; + +?> \ No newline at end of file diff --git a/models/admin/actions/Accommodation/edit.inc b/models/admin/actions/Accommodation/edit.inc new file mode 100644 index 0000000..91b903d --- /dev/null +++ b/models/admin/actions/Accommodation/edit.inc @@ -0,0 +1,31 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: event.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/accommodations.php'; +$Accoms = new EventManagementAdminAccoms($this->dbh, $this->config); +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/rooms.php'; +$Rooms = new EventManagementAdminRooms($this->dbh, $this->config); + + +$accomDetail = $Accoms->editAccom(); +$this->page->accomDetail = $this->bindArrayToObject($accomDetail); + +// We need this to mimic stored detail for edit templates that show this on entry to edit +$this->page->storedDetail = $this->bindArrayToObject($accomDetail); + +$this->page->editingAccom = true; + +$this->templateFile = 'Accommodation/EditAccommodation.html'; + +?> \ No newline at end of file diff --git a/models/admin/actions/Accommodation/editRoom.inc b/models/admin/actions/Accommodation/editRoom.inc new file mode 100644 index 0000000..f891690 --- /dev/null +++ b/models/admin/actions/Accommodation/editRoom.inc @@ -0,0 +1,29 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: event.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/accommodations.php'; +$Accoms = new EventManagementAdminAccoms($this->dbh, $this->config); +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/rooms.php'; +$Rooms = new EventManagementAdminRooms($this->dbh, $this->config); + + +$roomDetail = $Rooms->editRoom(); +$this->page->roomDetail = $this->bindArrayToObject($roomDetail); + +// We need this to mimic stored detail for edit templates that show this on entry to edit +$this->page->storedDetail = $this->bindArrayToObject($roomDetail); + +$this->templateFile = 'Accommodation/EditRoom.html'; + +?> \ No newline at end of file diff --git a/models/admin/actions/Accommodation/insert.inc b/models/admin/actions/Accommodation/insert.inc new file mode 100644 index 0000000..00b86b3 --- /dev/null +++ b/models/admin/actions/Accommodation/insert.inc @@ -0,0 +1,40 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: event.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/accommodations.php'; +$Accoms = new EventManagementAdminAccoms($this->dbh, $this->config); +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/rooms.php'; +$Rooms = new EventManagementAdminRooms($this->dbh, $this->config); + + +// Process new record +$r = $Accoms->insertAccom(); + +// Get success status, false = fail +$status = $r['status']; +$this->page->formFail = !$status; + +$this->page->accomDetail = $this->bindArrayToObject($r['fieldData']); +$this->page->fieldRequired = $this->bindArrayToObject($r['fieldRequired']); +$this->page->fieldFail = $this->bindArrayToObject($r['fieldFail']); + +// If invalid submission +if (!$status) { + $this->page->addingNewAccom = true; + $this->templateFile = 'Accommodation/EditAccommodation.html'; +} else { + $this->templateFile = 'Accommodation/AccommodationDetail.html'; +} + +?> \ No newline at end of file diff --git a/models/admin/actions/Accommodation/insertRoom.inc b/models/admin/actions/Accommodation/insertRoom.inc new file mode 100644 index 0000000..43095d0 --- /dev/null +++ b/models/admin/actions/Accommodation/insertRoom.inc @@ -0,0 +1,50 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: event.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/accommodations.php'; +$Accoms = new EventManagementAdminAccoms($this->dbh, $this->config); +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/rooms.php'; +$Rooms = new EventManagementAdminRooms($this->dbh, $this->config); + + +// Process new record +$r = $Rooms->insertRoom(); + +// Get success status, false = fail +$status = $r['status']; +$this->page->formFail = !$status; + +$this->page->roomDetail = $this->bindArrayToObject($r['fieldData']); +$this->page->fieldRequired = $this->bindArrayToObject($r['fieldRequired']); +$this->page->fieldFail = $this->bindArrayToObject($r['fieldFail']); + +// If invalid submission +if (!$status) { + $this->page->addingNewRoom = true; + $this->templateFile = 'Accommodation/EditRoom.html'; +} else { + + // Get Accommodation detail + $accomDetail = $Accoms->getAccomDetail(); + $this->page->accomDetail = $this->bindArrayToObject($accomDetail); + + // Get Rooms list + $roomsList = $Rooms->getRoomsList(); + $this->page->roomsList = $this->bindArrayToObject($roomsList); + + $this->templateFile = 'Accommodation/AccommodationDetail.html'; + +} + +?> \ No newline at end of file diff --git a/models/admin/actions/Accommodation/list.inc b/models/admin/actions/Accommodation/list.inc new file mode 100644 index 0000000..1581bdf --- /dev/null +++ b/models/admin/actions/Accommodation/list.inc @@ -0,0 +1,31 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: event.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/accommodations.php'; +$Accoms = new EventManagementAdminAccoms($this->dbh, $this->config); +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/rooms.php'; +$Rooms = new EventManagementAdminRooms($this->dbh, $this->config); + + +// Get members stats +$accomsStats = $Accoms->getAccomsStats(); +$this->page->accomsStats = $this->bindArrayToObject($accomsStats); + +// Get accommodations list +$accoms = $Accoms->getAccomsList(); +$this->page->accomsList = $this->bindArrayToObject($accoms); + +$this->templateFile = 'Accommodation/AccommodationsList.html'; + +?> \ No newline at end of file diff --git a/models/admin/actions/Accommodation/update.inc b/models/admin/actions/Accommodation/update.inc new file mode 100644 index 0000000..4f8c52f --- /dev/null +++ b/models/admin/actions/Accommodation/update.inc @@ -0,0 +1,44 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: event.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/accommodations.php'; +$Accoms = new EventManagementAdminAccoms($this->dbh, $this->config); +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/rooms.php'; +$Rooms = new EventManagementAdminRooms($this->dbh, $this->config); + + +// Process new record +$r = $Accoms->updateAccom(); + +// Get success status, false = fail +$status = $r['status']; +$this->page->formFail = !$status; + +$this->page->accomDetail = $this->bindArrayToObject($r['fieldData']); +$this->page->fieldRequired = $this->bindArrayToObject($r['fieldRequired']); +$this->page->fieldFail = $this->bindArrayToObject($r['fieldFail']); + +// Get currently stored data for fields that are display only +$accomDetail = $Accoms->getAccomDetail(); +$this->page->storedDetail = $this->bindArrayToObject($accomDetail); + +// If invalid submission +if (!$status) { + $this->page->editingAccom = true; + $this->templateFile = 'Accommodation/EditAccommodation.html'; +} else { + $this->templateFile = 'Accommodation/AccommodationDetail.html'; +} + +?> \ No newline at end of file diff --git a/models/admin/actions/Accommodation/updateRoom.inc b/models/admin/actions/Accommodation/updateRoom.inc new file mode 100644 index 0000000..03fa6ee --- /dev/null +++ b/models/admin/actions/Accommodation/updateRoom.inc @@ -0,0 +1,52 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: event.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/accommodations.php'; +$Accoms = new EventManagementAdminAccoms($this->dbh, $this->config); +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/rooms.php'; +$Rooms = new EventManagementAdminRooms($this->dbh, $this->config); + + +// Process new record +$r = $Rooms->updateRoom(); + +// Get success status, false = fail +$status = $r['status']; +$this->page->formFail = !$status; + +$this->page->roomDetail = $this->bindArrayToObject($r['fieldData']); +$this->page->fieldRequired = $this->bindArrayToObject($r['fieldRequired']); +$this->page->fieldFail = $this->bindArrayToObject($r['fieldFail']); + +// Get currently stored data for fields that are display only +$accomDetail = $Rooms->getRoomDetail(); +$this->page->storedDetail = $this->bindArrayToObject($roomDetail); + +// If invalid submission +if (!$status) { + $this->templateFile = 'Accommodation/EditRoom.html'; +} else { + + // Get Accommodation detail + $accomDetail = $Accoms->getAccomDetail(); + $this->page->accomDetail = $this->bindArrayToObject($accomDetail); + + // Get Rooms list + $roomsList = $Rooms->getRoomsList(); + $this->page->roomsList = $this->bindArrayToObject($roomsList); + + $this->templateFile = 'Accommodation/AccommodationDetail.html'; +} + +?> \ No newline at end of file diff --git a/models/admin/actions/Addon/add.inc b/models/admin/actions/Addon/add.inc new file mode 100644 index 0000000..3ee71ed --- /dev/null +++ b/models/admin/actions/Addon/add.inc @@ -0,0 +1,30 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: add.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/addons.php'; +$Addons = new EventManagementAdminAddons($this->dbh, $this->config); + +$r = $Addons->newAddon(); + +$this->page->addonDetail = $this->bindArrayToObject($r['fieldData']); +$this->page->fieldRequired = $this->bindArrayToObject($r['fieldRequired']); +$this->page->fieldFail = $this->bindArrayToObject($r['fieldFail']); + +$this->page->addingNewAddon = true; + +$this->templateFile = 'Addon/edit.html'; + +$this->addDebug("Addon/add.inc", 'Array: $r', print_r($r,1)); + +?> \ No newline at end of file diff --git a/models/admin/actions/Addon/confirmDelete.inc b/models/admin/actions/Addon/confirmDelete.inc new file mode 100644 index 0000000..6287d71 --- /dev/null +++ b/models/admin/actions/Addon/confirmDelete.inc @@ -0,0 +1,26 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: confirmDelete.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/addons.php'; +$Addons = new EventManagementAdminAddons($this->dbh, $this->config); + +$addonDetail = $Addons->addonDelete(true); +$this->page->addonDetail = $this->bindArrayToObject($addonDetail); + +$this->templateFile = 'Addon/detail.html'; + +$this->addDebug("Addon/confirmDelete.inc", 'Section Confirm Delete', print_r($addonDetail,1)); + +?> + diff --git a/models/admin/actions/Addon/delete.inc b/models/admin/actions/Addon/delete.inc new file mode 100644 index 0000000..591e1c2 --- /dev/null +++ b/models/admin/actions/Addon/delete.inc @@ -0,0 +1,26 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: delete.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/addons.php'; +$Addons = new EventManagementAdminAddons($this->dbh, $this->config); + +$addonDetail = $Addons->addonDelete(false); +$this->page->addonDetail = $this->bindArrayToObject($addonDetail); + +$this->templateFile = 'Addon/delete.html'; + +$this->addDebug("Addon/delete.inc", 'Array: $addonDetail', print_r($addonDetail,1)); + +?> + diff --git a/models/admin/actions/Addon/detail.inc b/models/admin/actions/Addon/detail.inc new file mode 100644 index 0000000..c7f2dab --- /dev/null +++ b/models/admin/actions/Addon/detail.inc @@ -0,0 +1,26 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: detail.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/addons.php'; +$Addons = new EventManagementAdminAddons($this->dbh, $this->config); + +// Get Add-on detail +$addonDetail = $Addons->getAddonDetail(); +$this->page->addonDetail = $this->bindArrayToObject($addonDetail); + +$this->templateFile = 'Addon/detail.html'; + +$this->addDebug("Addon/detail.inc", 'Array: $addonDetail', print_r($addonDetail,1)); + +?> \ No newline at end of file diff --git a/models/admin/actions/Addon/edit.inc b/models/admin/actions/Addon/edit.inc new file mode 100644 index 0000000..1a7a220 --- /dev/null +++ b/models/admin/actions/Addon/edit.inc @@ -0,0 +1,30 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: edit.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/addons.php'; +$Addons = new EventManagementAdminAddons($this->dbh, $this->config); + +$addonDetail = $Addons->editAddon(); +$this->page->addonDetail = $this->bindArrayToObject($addonDetail); + +// We need this to mimic stored detail for edit templates that show this on entry to edit +$this->page->storedDetail = $this->bindArrayToObject($addonDetail); + +$this->page->editingAddon = true; + +$this->templateFile = 'Addon/edit.html'; + +$this->addDebug("Addon/edit.inc", 'Array: $addonDetail', print_r($addonDetail,1)); + +?> \ No newline at end of file diff --git a/models/admin/actions/Addon/insert.inc b/models/admin/actions/Addon/insert.inc new file mode 100644 index 0000000..05197cf --- /dev/null +++ b/models/admin/actions/Addon/insert.inc @@ -0,0 +1,43 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: insert.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/addons.php'; +$Addons = new EventManagementAdminAddons($this->dbh, $this->config); + +// Process new record +$r = $Addons->insertAddon(); + +// Get success status, false = fail +$status = $r['status']; +$this->page->formFail = !$status; + +$this->page->addonDetail = $this->bindArrayToObject($r['fieldData']); +$this->page->fieldRequired = $this->bindArrayToObject($r['fieldRequired']); +$this->page->fieldFail = $this->bindArrayToObject($r['fieldFail']); + +// If invalid submission +if (!$status) { + $this->page->addingNewAddon = true; + $this->templateFile = 'Addon/edit.html'; +} else { + + $addonID = $r['fieldData']['id']; + + $this->templateFile = 'Addon/selected.html'; +} + +$this->addDebug("Addon/insert.inc", 'Array: $r', print_r($r,1)); + + +?> \ No newline at end of file diff --git a/models/admin/actions/Addon/list.inc b/models/admin/actions/Addon/list.inc new file mode 100644 index 0000000..00344fa --- /dev/null +++ b/models/admin/actions/Addon/list.inc @@ -0,0 +1,30 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: list.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/addons.php'; +$Addons = new EventManagementAdminAddons($this->dbh, $this->config); + +// Get Add-On stats +$addonStats = $Addons->getAddonsStats(); +$this->page->addonsStats = $this->bindArrayToObject($addonsStats); + +// Get Add-Ons list +$addons = $Addons->getAddonsList($id, false, false, $type); +$this->page->addons = $this->bindArrayToObject($addons); + +$this->templateFile = 'Addon/list.html'; + +$this->addDebug("Addon/list.inc", 'Array: $addons', print_r($addons,1)); + +?> \ No newline at end of file diff --git a/models/admin/actions/Addon/selected.inc b/models/admin/actions/Addon/selected.inc new file mode 100644 index 0000000..9ed2194 --- /dev/null +++ b/models/admin/actions/Addon/selected.inc @@ -0,0 +1,25 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: selected.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/addons.php'; +$Addons = new EventManagementAdminAddons($this->dbh, $this->config); + +$addonDetail = $Addons->getAddonDetail(); +$this->page->addonDetail = $this->bindArrayToObject($addonDetail); + +$this->templateFile = 'Addon/selected.html'; + +$this->addDebug("Addon/selected.inc", 'Addon Detail', print_r($addonDetail,1)); + +?> \ No newline at end of file diff --git a/models/admin/actions/Addon/update.inc b/models/admin/actions/Addon/update.inc new file mode 100644 index 0000000..c71cb20 --- /dev/null +++ b/models/admin/actions/Addon/update.inc @@ -0,0 +1,43 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: update.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/addons.php'; +$Addons = new EventManagementAdminAddons($this->dbh, $this->config); + +// Process new record +$r = $Addons->updateAddon(); + +// Get success status, false = fail +$status = $r['status']; +$this->page->formFail = !$status; + +$this->page->addonDetail = $this->bindArrayToObject($r['fieldData']); +$this->page->fieldRequired = $this->bindArrayToObject($r['fieldRequired']); +$this->page->fieldFail = $this->bindArrayToObject($r['fieldFail']); + +// Get currently stored data for fields that are display only +$addonDetail = $Addons->getAddonDetail(); +$this->page->storedDetail = $this->bindArrayToObject($addonDetail); + +// If invalid submission +if (!$status) { + $this->page->editingAddon = true; + $this->templateFile = 'Addon/edit.html'; +} else { + $this->templateFile = 'Addon/detail.html'; +} + +$this->addDebug("Addon/update.inc", 'Array: $r', print_r($r,1)); + +?> \ No newline at end of file diff --git a/models/admin/actions/Attendance/add.inc b/models/admin/actions/Attendance/add.inc new file mode 100755 index 0000000..931e2b1 --- /dev/null +++ b/models/admin/actions/Attendance/add.inc @@ -0,0 +1,36 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: attendance.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +// Get a list of members to select from +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/members.php'; +$Members = new EventManagementAdminMembers($this->dbh, $this->config); +$members = $Members->getMembersList('all'); + +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/attendance.php'; +$Attendance = new EventManagementAdminAttendance($this->dbh, $this->config); + +$r = $Attendance->newEntry(); + +$this->page->memberDetail = $this->bindArrayToObject($member); +$this->page->attendanceDetail = $this->bindArrayToObject($r['fieldData']); +$this->page->fieldRequired = $this->bindArrayToObject($r['fieldRequired']); +$this->page->fieldFail = $this->bindArrayToObject($r['fieldFail']); + +$this->page->addingNewAttendance = true; + +$this->templateFile = 'Attendance/edit.html'; + +$this->addDebug("Attendance/add.inc", 'Array: $r', print_r($r,1)); + +?> \ No newline at end of file diff --git a/models/admin/actions/Attendance/confirmDelete.inc b/models/admin/actions/Attendance/confirmDelete.inc new file mode 100755 index 0000000..5ff1e57 --- /dev/null +++ b/models/admin/actions/Attendance/confirmDelete.inc @@ -0,0 +1,26 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: confirmDelete.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/attendance.php'; +$Attendance = new EventManagementAdminAttendance($this->dbh, $this->config); + +$attendanceDetail = $Attendance->attendanceDelete(true); +$this->page->attendanceDetail = $this->bindArrayToObject($attendanceDetail); + +$this->templateFile = 'Attendance/detail.html'; + +$this->addDebug("Attendance/confirmDelete.inc", 'Section Confirm Delete', print_r($attendanceDetail,1)); + +?> + diff --git a/models/admin/actions/Attendance/delete.inc b/models/admin/actions/Attendance/delete.inc new file mode 100755 index 0000000..a23f36c --- /dev/null +++ b/models/admin/actions/Attendance/delete.inc @@ -0,0 +1,26 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: delete.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/attendance.php'; +$Attendance = new EventManagementAdminAttendance($this->dbh, $this->config); + +$attendanceDetail = $Attendances->attendanceDelete(false); +$this->page->attendanceDetail = $this->bindArrayToObject($attendanceDetail); + +$this->templateFile = 'Attendance/delete.html'; + +$this->addDebug("Attendance/delete.inc", 'Array: $attendanceDetail', print_r($attendanceDetail,1)); + +?> + diff --git a/models/admin/actions/Attendance/detail.inc b/models/admin/actions/Attendance/detail.inc new file mode 100644 index 0000000..29676d8 --- /dev/null +++ b/models/admin/actions/Attendance/detail.inc @@ -0,0 +1,26 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: detail.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/attendances.php'; +$Attendance = new EventManagementAdminAttendance($this->dbh, $this->config); + +// Get Attendance detail +$attendanceDetail = $Attendance->getAttendanceDetail(); +$this->page->attendanceDetail = $this->bindArrayToObject($attendanceDetail); + +$this->templateFile = 'Attendance/detail.html'; + +$this->addDebug("Attendance/detail.inc", 'Array: $attendanceDetail', print_r($attendanceDetail,1)); + +?> \ No newline at end of file diff --git a/models/admin/actions/Attendance/edit.inc b/models/admin/actions/Attendance/edit.inc new file mode 100755 index 0000000..a3c9656 --- /dev/null +++ b/models/admin/actions/Attendance/edit.inc @@ -0,0 +1,30 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: edit.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/attendance.php'; +$Attendance = new EventManagementAdminAttendance($this->dbh, $this->config); + +$attendanceDetail = $Attendance->editAttendance(); +$this->page->attendanceDetail = $this->bindArrayToObject($attendanceDetail); + +// We need this to mimic stored detail for edit templates that show this on entry to edit +$this->page->attendanceDetail = $this->bindArrayToObject($attendanceDetail); + +$this->page->editingAttendance = true; + +$this->templateFile = 'Attendance/edit.html'; + +$this->addDebug("Attendance/edit.inc", 'Array: $attendanceDetail', print_r($attendanceDetail,1)); + +?> \ No newline at end of file diff --git a/models/admin/actions/Attendance/insert.inc b/models/admin/actions/Attendance/insert.inc new file mode 100755 index 0000000..82270a1 --- /dev/null +++ b/models/admin/actions/Attendance/insert.inc @@ -0,0 +1,45 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: insert.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +var_dump($_REQUEST); + +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/attendance.php'; +$Attendance = new EventManagementAdminAttendance($this->dbh, $this->config); + +// Process new record +$r = $Attendance->insertEntry(); + +// Get success status, false = fail +$status = $r['status']; +$this->page->formFail = !$status; + +$this->page->attendanceDetail = $this->bindArrayToObject($r['fieldData']); +$this->page->fieldRequired = $this->bindArrayToObject($r['fieldRequired']); +$this->page->fieldFail = $this->bindArrayToObject($r['fieldFail']); + +// If invalid submission +if (!$status) { + $this->page->addingNewAttendance = true; + $this->templateFile = 'Attendance/edit.html'; +} else { + + $attendanceID = $r['fieldData']['id']; + + $this->templateFile = 'Attendance/selected.html'; +} + +$this->addDebug("Attendance/insert.inc", 'Array: $r', print_r($r,1)); + + +?> \ No newline at end of file diff --git a/models/admin/actions/Attendance/list.inc b/models/admin/actions/Attendance/list.inc new file mode 100755 index 0000000..21069f8 --- /dev/null +++ b/models/admin/actions/Attendance/list.inc @@ -0,0 +1,30 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: list.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/attendance.php'; +$Attendance = new EventManagementAdminAttendance($this->dbh, $this->config); + +// Get Attendance stats +$attendanceStats = $Attendance->getAttendanceStats(); +$this->page->attendanceStats = $this->bindArrayToObject($attendanceStats); + +// Get Attendance list +$attendanceList = $Attendance->getList(); +$this->page->attendance = $this->bindArrayToObject($attendanceList); + +$this->templateFile = 'Attendance/list.html'; + +$this->addDebug("Attendance/list.inc", 'Array: $attendanceList', print_r($attendanceList, 1)); + +?> \ No newline at end of file diff --git a/models/admin/actions/Attendance/selected.inc b/models/admin/actions/Attendance/selected.inc new file mode 100755 index 0000000..8b87cb9 --- /dev/null +++ b/models/admin/actions/Attendance/selected.inc @@ -0,0 +1,25 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: selected.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/attendance.php'; +$Attendance = new EventManagementAdminAttendance($this->dbh, $this->config); + +$attendanceDetail = $Attendance->getAttendanceDetail(); +$this->page->attendanceDetail = $this->bindArrayToObject($attendanceDetail); + +$this->templateFile = 'Attendance/selected.html'; + +$this->addDebug("Attendance/selected.inc", 'Attendance Detail', print_r($attendanceDetail,1)); + +?> \ No newline at end of file diff --git a/models/admin/actions/Attendance/update.inc b/models/admin/actions/Attendance/update.inc new file mode 100755 index 0000000..41d41a9 --- /dev/null +++ b/models/admin/actions/Attendance/update.inc @@ -0,0 +1,43 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: update.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/attendance.php'; +$Attendance = new EventManagementAdminAttendance($this->dbh, $this->config); + +// Process new record +$r = $Attendance->updateAttendance(); + +// Get success status, false = fail +$status = $r['status']; +$this->page->formFail = !$status; + +$this->page->attendanceDetail = $this->bindArrayToObject($r['fieldData']); +$this->page->fieldRequired = $this->bindArrayToObject($r['fieldRequired']); +$this->page->fieldFail = $this->bindArrayToObject($r['fieldFail']); + +// Get currently stored data for fields that are display only +$attendanceDetail = $Attendance->getAttendanceDetail(); +$this->page->storedDetail = $this->bindArrayToObject($AttendanceDetail); + +// If invalid submission +if (!$status) { + $this->page->editingAttendance = true; + $this->templateFile = 'Attendance/edit.html'; + $this->addDebug("Attendance/update.inc", 'Array: $r', print_r($r,1)); +} else { + // $this->templateFile = 'Attendance/detail.html'; + require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/actions/Attendance/detail.inc'; +} + +?> \ No newline at end of file diff --git a/models/admin/actions/Block/detail.inc b/models/admin/actions/Block/detail.inc new file mode 100644 index 0000000..60bf2d5 --- /dev/null +++ b/models/admin/actions/Block/detail.inc @@ -0,0 +1,27 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: event.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/blocks.php'; +$Blocks = new EventManagementAdminBlocks($this->dbh, $this->config); + + +// Get Room Blocks Detail for a selected Event and member (must have an event selected) +$detail = $Blocks->getBlocksDetail(); +$this->page->blocksDetail = $this->bindArrayToObject($detail); +$this->page->AND = '&&'; // a hack to get this into some javascript + +$this->templateFile = 'Block/BlocksDetail.html'; + +?> + diff --git a/models/admin/actions/Block/show.inc b/models/admin/actions/Block/show.inc new file mode 100644 index 0000000..66275ad --- /dev/null +++ b/models/admin/actions/Block/show.inc @@ -0,0 +1,30 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: event.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/blocks.php'; +$Blocks = new EventManagementAdminBlocks($this->dbh, $this->config); + + +$roomBlocks = $Blocks->getRoomBlocks(); + +if ($roomBlocks['blocks'] != false) { + $this->page->blocksList = $this->bindArrayToObject($roomBlocks['blocks']); +} +$this->page->statesList = $this->bindArrayToObject($roomBlocks['states']); + +// echo "
    ".print_r($roomBlocks,1)."
    "; +$this->templateFile = 'Block/BlocksList.html'; + +?> + diff --git a/models/admin/actions/Block/summary.inc b/models/admin/actions/Block/summary.inc new file mode 100644 index 0000000..1c961ed --- /dev/null +++ b/models/admin/actions/Block/summary.inc @@ -0,0 +1,26 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: event.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/blocks.php'; +$Blocks = new EventManagementAdminBlocks($this->dbh, $this->config); + + +// Get Room Blocks Summary for a selected Event (must have an event selected) +$summary = $Blocks->getBlocksSummary(); +$this->page->blocksSummary = $this->bindArrayToObject($summary); + +$this->templateFile = 'Block/BlocksSummary.html'; + +?> + diff --git a/models/admin/actions/Block/updateBlocks.inc b/models/admin/actions/Block/updateBlocks.inc new file mode 100644 index 0000000..13485c5 --- /dev/null +++ b/models/admin/actions/Block/updateBlocks.inc @@ -0,0 +1,24 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: event.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/blocks.php'; +$Blocks = new EventManagementAdminBlocks($this->dbh, $this->config); + + +$roomBlocks = $Blocks->saveRoomBlocks(); + +$this->templateFile = 'Block/UpdateBlocksAssignment.html'; + +?> + diff --git a/models/admin/actions/Block/updateDetail.inc b/models/admin/actions/Block/updateDetail.inc new file mode 100644 index 0000000..c0dafcd --- /dev/null +++ b/models/admin/actions/Block/updateDetail.inc @@ -0,0 +1,25 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: event.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/blocks.php'; +$Blocks = new EventManagementAdminBlocks($this->dbh, $this->config); + + +$r = $Blocks->updateBlocksDetail(); +$this->page->blocksStatus = $r; + +$this->templateFile = 'Block/UpdateBlocksDetail.html'; + +?> + diff --git a/models/admin/actions/Booking/add.inc b/models/admin/actions/Booking/add.inc new file mode 100644 index 0000000..f9c6982 --- /dev/null +++ b/models/admin/actions/Booking/add.inc @@ -0,0 +1,92 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: event.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/bookings.php'; +$Bookings = new EventManagementAdminBookings($this->dbh, $this->config); + + +if ($_SESSION[GLM_EVENT_SESSION]['Event'] != false) { + require '../classes/events.php'; + $Events = new EventManagementAdminEvents($this->dbh, $this->config); + $eventDetail = $Events->getEntry($_SESSION[GLM_EVENT_SESSION]['Event']); + $this->page->eventName = $eventDetail['name']; + $this->page->eventID = $eventDetail['id']; + $this->page->haveEvent = true; +} else { + $this->page->haveEvent = false; +} + +if ($_SESSION[GLM_EVENT_SESSION]['Team'] != false) { + require '../classes/teams.php'; + $Teams = new EventManagementAdminTeams($this->dbh, $this->config); + $teamDetail = $Teams->getEntry($_SESSION[GLM_EVENT_SESSION]['Team']); + $this->page->teamName = $teamDetail['name']; + $this->page->teamID = $teamDetail['id']; + $this->page->haveTeam = true; +} else { + $this->page->haveTeam = false; +} + +// If we have what we need - Get the list of members with inventory for the event +if ($this->page->haveEvent && $this->page->haveTeam) { + + // Get properties that have inventory for this event + $sql = " + SELECT id, name + FROM eventmgt.member + WHERE id IN + ( + SELECT DISTINCT member + FROM eventmgt.inventory + WHERE event_code = '".$eventDetail['event_code']."' + ) + ORDER BY name; + "; + $stmt = $this->dbh->prepare($sql); + $stmt->execute(); + $memberList = $stmt->fetchAll(PDO::FETCH_ASSOC); + + $this->page->memberList = $this->bindArrayToObject($memberList); + +} + +// Get list of bookings for an event + +// Check for Booking Delete +if (isset($_REQUEST['del'])) { + $del = ($_REQUEST['del'] - 0); + if ($del > 0) { + $sql = "DELETE + FROM eventmgt.team_property + WHERE id = $del + ;"; + + $stmt = $this->dbh->prepare($sql); + $stmt->execute(); + } +} + +// Get bookings stats +$bookingsStats = $Bookings->getBookingsStats(); +$this->page->bookingsStats = $this->bindArrayToObject($bookingsStats); + +// Get bookings list +$bookings = $Bookings->getBookingsList(); +$this->page->bookingsList = $this->bindArrayToObject($bookings); + +$this->templateFile = 'Booking/BookingsList.html'; + + + +?> \ No newline at end of file diff --git a/models/admin/actions/Booking/detail.inc b/models/admin/actions/Booking/detail.inc new file mode 100644 index 0000000..91c5b5d --- /dev/null +++ b/models/admin/actions/Booking/detail.inc @@ -0,0 +1,25 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: event.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/bookings.php'; +$Bookings = new EventManagementAdminBookings($this->dbh, $this->config); + + +$bookingDetail = $Bookings->getBookingDetail(); +$this->page->bookingDetail = $this->bindArrayToObject($bookingDetail); + +$this->templateFile = 'Booking/BookingDetail.html'; + + +?> \ No newline at end of file diff --git a/models/admin/actions/Booking/insert.inc b/models/admin/actions/Booking/insert.inc new file mode 100644 index 0000000..8ad281e --- /dev/null +++ b/models/admin/actions/Booking/insert.inc @@ -0,0 +1,146 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: event.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/bookings.php'; +$Bookings = new EventManagementAdminBookings($this->dbh, $this->config); + + +if ($_SESSION[GLM_EVENT_SESSION]['Event'] != false) { + require '../classes/events.php'; + $Events = new EventManagementAdminEvents($this->dbh, $this->config); + $eventDetail = $Events->getEntry($_SESSION[GLM_EVENT_SESSION]['Event']); + $this->page->eventName = $eventDetail['name']; + $this->page->eventID = $eventDetail['id']; + $this->page->haveEvent = true; +} else { + $this->page->haveEvent = false; +} + +if ($_SESSION[GLM_EVENT_SESSION]['Team'] != false) { + require '../classes/teams.php'; + $Teams = new EventManagementAdminTeams($this->dbh, $this->config); + $teamDetail = $Teams->getEntry($_SESSION[GLM_EVENT_SESSION]['Team']); + $this->page->teamName = $teamDetail['name']; + $this->page->teamID = $teamDetail['id']; + $this->page->haveTeam = true; +} else { + $this->page->haveTeam = false; +} + +// If we have what we need - Get the list of members with inventory for the event +if ($this->page->haveEvent && $this->page->haveTeam) { + + // Get properties that have inventory for this event + $sql = " + SELECT id, name + FROM eventmgt.member + WHERE id IN + ( + SELECT DISTINCT member + FROM eventmgt.inventory + WHERE event_code = '".$eventDetail['event_code']."' + ) + ORDER BY name; + "; + $stmt = $this->dbh->prepare($sql); + $stmt->execute(); + $memberList = $stmt->fetchAll(PDO::FETCH_ASSOC); + + $this->page->memberList = $this->bindArrayToObject($memberList); + +} + +// Insert a booking + +$insertSuccess = true; + +// Check for good Event, Team, and property data, must be id numbers +$eventID = ($_REQUEST['eventID'] - 0); +$teamID = ($_REQUEST['teamID'] - 0); +$propID = ($_REQUEST['propID'] - 0); + +if ($eventID == 0 || $teamID == 0 || $propID == 0) { + $insertSuccess = false; +} +// Check for good dates - Must between now and start of event +$startDate = strtotime($_REQUEST['startDate']); +$endDate = strtotime($_REQUEST['endDate']); + +if ($startDate < strtotime(date('m/d/Y'))) { + $this->page->startFail = true; + $insertSuccess = false; +} + +if ($endDate > strtotime($eventDetail['start_date'])) { + $this->page->endFail = true; + $insertSuccess = false; +} + +if ($startDate > $endDate) { + $this->page->datesFail = true; + $insertSuccess = false; +} + +// If we're Ok to this point, then try to add this booking to the database +if ($insertSuccess) { + $startDate = date('m/d/Y', $startDate); + $endDate = date('m/d/Y', $endDate); + + $sql = " + INSERT INTO eventmgt.team_property + (team, property, event, start, stop) + VALUES + ( + $teamID, $propID, $eventID, '$startDate', '$endDate' + ); + "; + $stmt = $this->dbh->prepare($sql); + $stmt->execute(); + // NEED TO TEST FOR SUCCESS HERE +} + + +// If it failed, then try again +if ($insertSuccess == false) { + $this->page->addingNewBooking = true; + $this->templateFile = 'Booking/EditBooking.html'; +} else { + + // Check for Booking Delete + if (isset($_REQUEST['del'])) { + $del = ($_REQUEST['del'] - 0); + if ($del > 0) { + $sql = "DELETE + FROM eventmgt.team_property + WHERE id = $del + ;"; + + $stmt = $this->dbh->prepare($sql); + $stmt->execute(); + } + } + + // Get bookings stats + $bookingsStats = $Bookings->getBookingsStats(); + $this->page->bookingsStats = $this->bindArrayToObject($bookingsStats); + + // Get bookings list + $bookings = $Bookings->getBookingsList(); + $this->page->bookingsList = $this->bindArrayToObject($bookings); + + $this->templateFile = 'Booking/BookingsList.html'; + +} + +?> \ No newline at end of file diff --git a/models/admin/actions/Booking/list.inc b/models/admin/actions/Booking/list.inc new file mode 100644 index 0000000..8042df2 --- /dev/null +++ b/models/admin/actions/Booking/list.inc @@ -0,0 +1,43 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: event.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/bookings.php'; +$Bookings = new EventManagementAdminBookings($this->dbh, $this->config); + + +// Check for Booking Delete +if (isset($_REQUEST['del'])) { + $del = ($_REQUEST['del'] - 0); + if ($del > 0) { + $sql = "DELETE + FROM eventmgt.team_property + WHERE id = $del + ;"; + + $stmt = $this->dbh->prepare($sql); + $stmt->execute(); + } +} + +// Get bookings stats +$bookingsStats = $Bookings->getBookingsStats(); +$this->page->bookingsStats = $this->bindArrayToObject($bookingsStats); + +// Get bookings list +$bookings = $Bookings->getBookingsList(); +$this->page->bookingsList = $this->bindArrayToObject($bookings); + +$this->templateFile = 'Booking/BookingsList.html'; + +?> \ No newline at end of file diff --git a/models/admin/actions/Contact/add.inc b/models/admin/actions/Contact/add.inc new file mode 100644 index 0000000..e11091a --- /dev/null +++ b/models/admin/actions/Contact/add.inc @@ -0,0 +1,31 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: event.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/contacts.php'; +$Contacts = new EventManagementAdminContacts($this->dbh, $this->config); + +// Get base data and fields +$r = $Contacts->newContact(); + +$this->page->contactDetail = $this->bindArrayToObject($r['fieldData']); +$this->page->fieldRequired = $this->bindArrayToObject($r['fieldRequired']); +$this->page->fieldFail = $this->bindArrayToObject($r['fieldFail']); +$this->page->addingNewContact = true; + +$this->templateFile = 'Contact/edit.html'; + +$this->addDebug("Contact/add.inc", 'Contact Add', print_r($r,1)); + +?> + diff --git a/models/admin/actions/Contact/confirmDelete.inc b/models/admin/actions/Contact/confirmDelete.inc new file mode 100644 index 0000000..46eb6e4 --- /dev/null +++ b/models/admin/actions/Contact/confirmDelete.inc @@ -0,0 +1,26 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: event.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/contacts.php'; +$Contacts = new EventManagementAdminContacts($this->dbh, $this->config); + +$contactDetail = $Contacts->contactDelete(true); +$this->page->contactDetail = $this->bindArrayToObject($contactDetail); + +$this->templateFile = 'Contact/detail.html'; + +$this->addDebug("Contact/confirmDelete.inc", 'Contact Confirm Delete', print_r($contactDetail,1)); + +?> + diff --git a/models/admin/actions/Contact/delete.inc b/models/admin/actions/Contact/delete.inc new file mode 100644 index 0000000..442a862 --- /dev/null +++ b/models/admin/actions/Contact/delete.inc @@ -0,0 +1,27 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: event.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/contacts.php'; +$Contacts = new EventManagementAdminContacts($this->dbh, $this->config); + + +$contactDetail = $Contacts->contactDelete(false); +$this->page->contactDetail = $this->bindArrayToObject($contactDetail); + +$this->templateFile = 'Contact/delete.html'; + +$this->addDebug("Contact/delete.inc", 'Contact Delete', print_r($contactDetail,1)); + +?> + diff --git a/models/admin/actions/Contact/detail.inc b/models/admin/actions/Contact/detail.inc new file mode 100644 index 0000000..b736e4d --- /dev/null +++ b/models/admin/actions/Contact/detail.inc @@ -0,0 +1,26 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: event.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/contacts.php'; +$Contacts = new EventManagementAdminContacts($this->dbh, $this->config); + +$contactDetail = $Contacts->getContactDetail(); +$this->page->contactDetail = $this->bindArrayToObject($contactDetail); + +$this->templateFile = 'Contact/detail.html'; + +$this->addDebug("Contact/detail.inc", 'Contact Detail', print_r($contactDetail,1)); + +?> + diff --git a/models/admin/actions/Contact/edit.inc b/models/admin/actions/Contact/edit.inc new file mode 100644 index 0000000..03d7252 --- /dev/null +++ b/models/admin/actions/Contact/edit.inc @@ -0,0 +1,30 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: event.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/contacts.php'; +$Contacts = new EventManagementAdminContacts($this->dbh, $this->config); + +$contactDetail = $Contacts->editContact(); +$this->page->contactDetail = $this->bindArrayToObject($contactDetail); + +// We need this to mimic stored detail for edit templates that show this on entry to edit +$this->page->storedDetail = $this->bindArrayToObject($contactDetail); + +$this->page->editingContact = true; +$this->templateFile = 'Contact/edit.html'; + +$this->addDebug("Contact/edit.inc", 'Contact Edit', print_r($contactDetail,1)); + +?> + diff --git a/models/admin/actions/Contact/insert.inc b/models/admin/actions/Contact/insert.inc new file mode 100644 index 0000000..799d8c2 --- /dev/null +++ b/models/admin/actions/Contact/insert.inc @@ -0,0 +1,40 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: event.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/contacts.php'; +$Contacts = new EventManagementAdminContacts($this->dbh, $this->config); + +// Process new record +$r = $Contacts->insertContact(); + +// Get success status, false = fail +$status = $r['status']; +$this->page->formFail = !$status; + +$this->page->contactDetail = $this->bindArrayToObject($r['fieldData']); +$this->page->fieldRequired = $this->bindArrayToObject($r['fieldRequired']); +$this->page->fieldFail = $this->bindArrayToObject($r['fieldFail']); + +// If invalid submission +if (!$status) { + $this->page->addingNewContact = true; + $this->templateFile = 'Contact/edit.html'; +} else { + $this->templateFile = 'Contact/detail.html'; +} + +$this->addDebug("Contact/insert.inc", 'Contact Insert', print_r($r,1)); + +?> + diff --git a/models/admin/actions/Contact/list.inc b/models/admin/actions/Contact/list.inc new file mode 100644 index 0000000..2f97688 --- /dev/null +++ b/models/admin/actions/Contact/list.inc @@ -0,0 +1,30 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: event.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/contacts.php'; +$Contacts = new EventManagementAdminContacts($this->dbh, $this->config); + +// Get contacts stats +$contactsStats = $Contacts->getContactsStats(); +$this->page->contactsStats = $this->bindArrayToObject($contactsStats); + +$contactList = $Contacts->getContacts(); +$this->page->contactList = $this->bindArrayToObject($contactList); + +$this->templateFile = 'Contact/list.html'; + +$this->addDebug("Contact/list.inc", 'Contact List', print_r($contactList,1)); + +?> + diff --git a/models/admin/actions/Contact/update.inc b/models/admin/actions/Contact/update.inc new file mode 100644 index 0000000..ea7ec3f --- /dev/null +++ b/models/admin/actions/Contact/update.inc @@ -0,0 +1,42 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: event.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/contacts.php'; +$Contacts = new EventManagementAdminContacts($this->dbh, $this->config); + + +// Process new record +$r = $Contacts->updateContact(); + +// Get success status, false = fail +$status = $r['status']; +$this->page->formFail = !$status; + +$this->page->contactDetail = $this->bindArrayToObject($r['fieldData']); +$this->page->fieldRequired = $this->bindArrayToObject($r['fieldRequired']); +$this->page->fieldFail = $this->bindArrayToObject($r['fieldFail']); + +// If invalid submission +if (!$status) { + $this->page->editingContact = true; + $this->templateFile = 'Contact/edit.html'; +} else { + // If valid + $this->templateFile = 'Contact/detail.html'; +} + +$this->addDebug("Contact/add.inc", 'Contact Add', print_r($r,1)); + +?> + diff --git a/models/admin/actions/Debug/start.inc b/models/admin/actions/Debug/start.inc new file mode 100644 index 0000000..d07c4fc --- /dev/null +++ b/models/admin/actions/Debug/start.inc @@ -0,0 +1,19 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: event.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +$this->page->debugStartupTime = date('m/d/Y H:i:s'); +$this->templateFile = 'Debug/index.html'; + +?> + diff --git a/models/admin/actions/Debug/update.inc b/models/admin/actions/Debug/update.inc new file mode 100644 index 0000000..6a7e9e6 --- /dev/null +++ b/models/admin/actions/Debug/update.inc @@ -0,0 +1,29 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: event.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +$this->page->debugUpdateTime = date('m/d/Y H:i:s'); + +// If there's nothing to send, then don't +if (!file_exists(DEBUG_DATA_FILENAME)) { + exit; +} + +// Otherwise, send the current debug data +$this->page->debugData = file_get_contents(DEBUG_DATA_FILENAME); +unlink(DEBUG_DATA_FILENAME); + +$this->templateFile = 'Debug/index.html'; + +?> + diff --git a/models/admin/actions/Division/add.inc b/models/admin/actions/Division/add.inc new file mode 100644 index 0000000..47f2f2d --- /dev/null +++ b/models/admin/actions/Division/add.inc @@ -0,0 +1,28 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: event.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/divisions.php'; +$Divisions = new EventManagementAdminDivisions($this->dbh, $this->config); + + +$r = $Divisions->newDivision(); + +$this->page->divisionDetail = $this->bindArrayToObject($r['fieldData']); +$this->page->fieldRequired = $this->bindArrayToObject($r['fieldRequired']); +$this->page->fieldFail = $this->bindArrayToObject($r['fieldFail']); +$this->page->addingNewDivision = true; + +$this->templateFile = 'Division/EditDivision.html'; + +?> \ No newline at end of file diff --git a/models/admin/actions/Division/detail.inc b/models/admin/actions/Division/detail.inc new file mode 100644 index 0000000..adfff7f --- /dev/null +++ b/models/admin/actions/Division/detail.inc @@ -0,0 +1,24 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: event.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/divisions.php'; +$Divisions = new EventManagementAdminDivisions($this->dbh, $this->config); + + +$divisionDetail = $Divisions->getDivisionDetail(); +$this->page->divisionDetail = $this->bindArrayToObject($divisionDetail); + +$this->templateFile = 'Division/DivisionDetail.html'; + +?> \ No newline at end of file diff --git a/models/admin/actions/Division/edit.inc b/models/admin/actions/Division/edit.inc new file mode 100644 index 0000000..e0d9ee0 --- /dev/null +++ b/models/admin/actions/Division/edit.inc @@ -0,0 +1,29 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: event.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/divisions.php'; +$Divisions = new EventManagementAdminDivisions($this->dbh, $this->config); + + +$divisionDetail = $Divisions->editDivision(); +$this->page->divisionDetail = $this->bindArrayToObject($divisionDetail); + +// We need this to mimic stored detail for edit templates that show this on entry to edit +$this->page->storedDetail = $this->bindArrayToObject($divisionDetail); + +$this->page->editingDivision = true; + +$this->templateFile = 'Division/EditDivision.html'; + +?> \ No newline at end of file diff --git a/models/admin/actions/Division/insert.inc b/models/admin/actions/Division/insert.inc new file mode 100644 index 0000000..0e095a1 --- /dev/null +++ b/models/admin/actions/Division/insert.inc @@ -0,0 +1,38 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: event.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/divisions.php'; +$Divisions = new EventManagementAdminDivisions($this->dbh, $this->config); + + +// Process new record +$r = $Divisions->insertDivision(); + +// Get success status, false = fail +$status = $r['status']; +$this->page->formFail = !$status; + +$this->page->divisionDetail = $this->bindArrayToObject($r['fieldData']); +$this->page->fieldRequired = $this->bindArrayToObject($r['fieldRequired']); +$this->page->fieldFail = $this->bindArrayToObject($r['fieldFail']); + +// If invalid submission +if (!$status) { + $this->page->addingNewDivision = true; + $this->templateFile = 'Division/EditDivision.html'; +} else { + $this->templateFile = 'Division/DivisionDetail.html'; +} + +?> \ No newline at end of file diff --git a/models/admin/actions/Division/list.inc b/models/admin/actions/Division/list.inc new file mode 100644 index 0000000..69d4558 --- /dev/null +++ b/models/admin/actions/Division/list.inc @@ -0,0 +1,29 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: event.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/divisions.php'; +$Divisions = new EventManagementAdminDivisions($this->dbh, $this->config); + + +// Get divisions stats +$divisionsStats = $Divisions->getDivisionsStats(); +$this->page->divisionsStats = $this->bindArrayToObject($divisionsStats); + +// Get divisions list +$divisions = $Divisions->getDivisionsList(); +$this->page->divisionsList = $this->bindArrayToObject($divisions); + +$this->templateFile = 'Division/DivisionsList.html'; + +?> \ No newline at end of file diff --git a/models/admin/actions/Division/update.inc b/models/admin/actions/Division/update.inc new file mode 100644 index 0000000..2b60b25 --- /dev/null +++ b/models/admin/actions/Division/update.inc @@ -0,0 +1,42 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: event.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/divisions.php'; +$Divisions = new EventManagementAdminDivisions($this->dbh, $this->config); + + +// Process new record +$r = $Divisions->updateDivision(); + +// Get success status, false = fail +$status = $r['status']; +$this->page->formFail = !$status; + +$this->page->divisionDetail = $this->bindArrayToObject($r['fieldData']); +$this->page->fieldRequired = $this->bindArrayToObject($r['fieldRequired']); +$this->page->fieldFail = $this->bindArrayToObject($r['fieldFail']); + +// Get currently stored data for fields that are display only +$divisionDetail = $Divisions->getDivisionDetail(); +$this->page->storedDetail = $this->bindArrayToObject($divisionDetail); + +// If invalid submission +if (!$status) { + $this->page->editingDivision = true; + $this->templateFile = 'Division/EditDivision.html'; +} else { + $this->templateFile = 'Division/DivisionDetail.html'; +} + +?> \ No newline at end of file diff --git a/models/admin/actions/Entrance/add.inc b/models/admin/actions/Entrance/add.inc new file mode 100644 index 0000000..2e9f2aa --- /dev/null +++ b/models/admin/actions/Entrance/add.inc @@ -0,0 +1,31 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: add.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/entrances.php'; +$Entrances = new EventManagementAdminEntrances($this->dbh, $this->config); + +// Get base data and fields +$r = $Entrances->newEntrance(); + +$this->page->entranceDetail = $this->bindArrayToObject($r['fieldData']); +$this->page->fieldRequired = $this->bindArrayToObject($r['fieldRequired']); +$this->page->fieldFail = $this->bindArrayToObject($r['fieldFail']); +$this->page->addingNewEntrance = true; + +$this->templateFile = 'Entrance/edit.html'; + +$this->addDebug("Entrance/add.inc", 'Entrance Add', print_r($r,1)); + +?> + diff --git a/models/admin/actions/Entrance/confirmDelete.inc b/models/admin/actions/Entrance/confirmDelete.inc new file mode 100644 index 0000000..0d03d4a --- /dev/null +++ b/models/admin/actions/Entrance/confirmDelete.inc @@ -0,0 +1,26 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: event.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/entrances.php'; +$Entrances = new EventManagementAdminEntrances($this->dbh, $this->config); + +$entranceDetail = $Entrances->entranceDelete(true); +$this->page->entranceDetail = $this->bindArrayToObject($entranceDetail); + +$this->templateFile = 'Entrance/detail.html'; + +$this->addDebug("Entrance/confirmDelete.inc", 'Entrance Confirm Delete', print_r($entranceDetail,1)); + +?> + diff --git a/models/admin/actions/Entrance/delete.inc b/models/admin/actions/Entrance/delete.inc new file mode 100644 index 0000000..6855bcc --- /dev/null +++ b/models/admin/actions/Entrance/delete.inc @@ -0,0 +1,27 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: entrance.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/entrances.php'; +$Entrances = new EventManagementAdminEntrances($this->dbh, $this->config); + + +$entranceDetail = $Entrances->entranceDelete(false); +$this->page->entranceDetail = $this->bindArrayToObject($entranceDetail); + +$this->templateFile = 'Entrance/delete.html'; + +$this->addDebug("Entrance/delete.inc", 'Entrance Delete', print_r($entranceDetail,1)); + +?> + diff --git a/models/admin/actions/Entrance/detail.inc b/models/admin/actions/Entrance/detail.inc new file mode 100644 index 0000000..bbba59b --- /dev/null +++ b/models/admin/actions/Entrance/detail.inc @@ -0,0 +1,26 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: event.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/entrances.php'; +$Entrances = new EventManagementAdminEntrances($this->dbh, $this->config); + +$entranceDetail = $Entrances->getEntranceDetail(); +$this->page->entranceDetail = $this->bindArrayToObject($entranceDetail); + +$this->templateFile = 'Entrance/detail.html'; + +$this->addDebug("Entrance/detail.inc", 'Entrance Detail', print_r($entranceDetail,1)); + +?> + diff --git a/models/admin/actions/Entrance/edit.inc b/models/admin/actions/Entrance/edit.inc new file mode 100644 index 0000000..c469fc9 --- /dev/null +++ b/models/admin/actions/Entrance/edit.inc @@ -0,0 +1,30 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: event.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/entrances.php'; +$Entrances = new EventManagementAdminEntrances($this->dbh, $this->config); + +$entranceDetail = $Entrances->editEntrance(); +$this->page->entranceDetail = $this->bindArrayToObject($entranceDetail); + +// We need this to mimic stored detail for edit templates that show this on entry to edit +$this->page->storedDetail = $this->bindArrayToObject($entranceDetail); + +$this->page->editingEntrance = true; +$this->templateFile = 'Entrance/edit.html'; + +$this->addDebug("Entrance/edit.inc", 'Entrance Edit', print_r($entranceDetail,1)); + +?> + diff --git a/models/admin/actions/Entrance/insert.inc b/models/admin/actions/Entrance/insert.inc new file mode 100644 index 0000000..e924552 --- /dev/null +++ b/models/admin/actions/Entrance/insert.inc @@ -0,0 +1,40 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: event.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/entrances.php'; +$Entrances = new EventManagementAdminEntrances($this->dbh, $this->config); + +// Process new record +$r = $Entrances->insertEntrance(); + +// Get success status, false = fail +$status = $r['status']; +$this->page->formFail = !$status; + +$this->page->entranceDetail = $this->bindArrayToObject($r['fieldData']); +$this->page->fieldRequired = $this->bindArrayToObject($r['fieldRequired']); +$this->page->fieldFail = $this->bindArrayToObject($r['fieldFail']); + +// If invalid submission +if (!$status) { + $this->page->addingNewEntrance = true; + $this->templateFile = 'Entrance/edit.html'; +} else { + $this->templateFile = 'Entrance/detail.html'; +} + +$this->addDebug("Entrance/insert.inc", 'Entrance Insert', print_r($r,1)); + +?> + diff --git a/models/admin/actions/Entrance/list.inc b/models/admin/actions/Entrance/list.inc new file mode 100644 index 0000000..80d9e0f --- /dev/null +++ b/models/admin/actions/Entrance/list.inc @@ -0,0 +1,27 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: event.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/entrances.php'; +$Entrances = new EventManagementAdminEntrances($this->dbh, $this->config); + +$entranceList = $Entrances->getEntrancesList(); + +$this->page->entranceList = $this->bindArrayToObject($entranceList); + +$this->templateFile = 'Entrance/list.html'; + +$this->addDebug("Entrance/list.inc", 'Entrance List', 'Array: $entranceList

    '.print_r($entranceList,1)); + +?> + diff --git a/models/admin/actions/Entrance/update.inc b/models/admin/actions/Entrance/update.inc new file mode 100644 index 0000000..a02a0ed --- /dev/null +++ b/models/admin/actions/Entrance/update.inc @@ -0,0 +1,42 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: event.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/entrances.php'; +$Entrances = new EventManagementAdminEntrances($this->dbh, $this->config); + + +// Process new record +$r = $Entrances->updateEntrance(); + +// Get success status, false = fail +$status = $r['status']; +$this->page->formFail = !$status; + +$this->page->entranceDetail = $this->bindArrayToObject($r['fieldData']); +$this->page->fieldRequired = $this->bindArrayToObject($r['fieldRequired']); +$this->page->fieldFail = $this->bindArrayToObject($r['fieldFail']); + +// If invalid submission +if (!$status) { + $this->page->editingEntrance = true; + $this->templateFile = 'Entrance/edit.html'; +} else { + // If valid + $this->templateFile = 'Entrance/detail.html'; +} + +$this->addDebug("Entrance/add.inc", 'Entrance Add', print_r($r,1)); + +?> + diff --git a/models/admin/actions/Event/add.inc b/models/admin/actions/Event/add.inc new file mode 100644 index 0000000..01cba62 --- /dev/null +++ b/models/admin/actions/Event/add.inc @@ -0,0 +1,30 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: event.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/events.php'; +$Events = new EventManagementAdminEvents($this->dbh, $this->config); + + +// Check Event Code +$r = $Events->newEntry(); + +$this->page->eventDetail = $this->bindArrayToObject($r['fieldData']); +$this->page->fieldRequired = $this->bindArrayToObject($r['fieldRequired']); +$this->page->fieldFail = $this->bindArrayToObject($r['fieldFail']); +$this->page->addingNewEvent = true; + +$this->templateFile = 'Event/EditEvent.html'; + +?> + diff --git a/models/admin/actions/Event/detail.inc b/models/admin/actions/Event/detail.inc new file mode 100644 index 0000000..f07d78e --- /dev/null +++ b/models/admin/actions/Event/detail.inc @@ -0,0 +1,32 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: event.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/events.php'; +$Events = new EventManagementAdminEvents($this->dbh, $this->config); + +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/contacts.php'; +$Contacts = new EventManagementAdminContacts($this->dbh, $this->config); + + +// Get detail for an event +$eventDetail = $Events->getEventDetail(); +$this->page->eventDetail = $this->bindArrayToObject($eventDetail); + +// Get contacts for this event +$eventContacts = $Contacts->getContacts('event'); +$this->page->contactsList = $this->bindArrayToObject($eventContacts['contact_list']); + +$this->templateFile = 'Event/EventDetail.html'; + +?> \ No newline at end of file diff --git a/models/admin/actions/Event/edit.inc b/models/admin/actions/Event/edit.inc new file mode 100644 index 0000000..825bce9 --- /dev/null +++ b/models/admin/actions/Event/edit.inc @@ -0,0 +1,32 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: event.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/events.php'; +$Events = new EventManagementAdminEvents($this->dbh, $this->config); + + +// Check Event Code +$eventDetail = $Events->editEvent(); +$this->page->eventDetail = $this->bindArrayToObject($eventDetail); + +// We need this to mimic stored detail for edit templates that show this on entry to edit +$this->page->storedDetail = $this->bindArrayToObject($eventDetail); + +$this->page->editingEvent = true; + +$this->templateFile = 'Event/EditEvent.html'; + + +?> + diff --git a/models/admin/actions/Event/insert.inc b/models/admin/actions/Event/insert.inc new file mode 100644 index 0000000..a2b04b4 --- /dev/null +++ b/models/admin/actions/Event/insert.inc @@ -0,0 +1,39 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: event.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/events.php'; +$Events = new EventManagementAdminEvents($this->dbh, $this->config); + + +// Process new record +$r = $Events->insertEvent(); + +// Get success status, false = fail +$status = $r['status']; +$this->page->formFail = !$status; + +$this->page->eventDetail = $this->bindArrayToObject($r['fieldData']); +$this->page->fieldRequired = $this->bindArrayToObject($r['fieldRequired']); +$this->page->fieldFail = $this->bindArrayToObject($r['fieldFail']); + +// If invalid submission +if (!$status) { + $this->page->addingNewEvent = true; + $this->templateFile = 'Event/EditEvent.html'; +} else { + $this->templateFile = 'Event/EventDetail.html'; +} + +?> + diff --git a/models/admin/actions/Event/list.inc b/models/admin/actions/Event/list.inc new file mode 100644 index 0000000..c392da9 --- /dev/null +++ b/models/admin/actions/Event/list.inc @@ -0,0 +1,30 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: event.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/events.php'; +$Events = new EventManagementAdminEvents($this->dbh, $this->config); + + +// Get events stats +$eventsStats = $Events->getEventsStats(); +$this->page->eventsStats = $this->bindArrayToObject($eventsStats); + +// Get list of events +$eventsList = $Events->getEventsList(); +$this->page->eventsList = $this->bindArrayToObject($eventsList); + +$this->templateFile = 'Event/EventsList.html'; + +?> + diff --git a/models/admin/actions/Event/stats.inc b/models/admin/actions/Event/stats.inc new file mode 100644 index 0000000..a58cf42 --- /dev/null +++ b/models/admin/actions/Event/stats.inc @@ -0,0 +1,26 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: event.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/events.php'; +$Events = new EventManagementAdminEvents($this->dbh, $this->config); + + +// Get events stats +$eventsStats = $Events->getEventsStats(); +$this->page->eventsStats = $this->bindArrayToObject($eventsStats); + +$this->templateFile = 'Event/stats.html'; + +?> + diff --git a/models/admin/actions/Event/update.inc b/models/admin/actions/Event/update.inc new file mode 100644 index 0000000..8cf0cc5 --- /dev/null +++ b/models/admin/actions/Event/update.inc @@ -0,0 +1,42 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: event.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/events.php'; +$Events = new EventManagementAdminEvents($this->dbh, $this->config); + +// Process new record +$r = $Events->updateEvent(); + +// Get success status, false = fail +$status = $r['status']; +$this->page->formFail = !$status; + +$this->page->eventDetail = $this->bindArrayToObject($r['fieldData']); +$this->page->fieldRequired = $this->bindArrayToObject($r['fieldRequired']); +$this->page->fieldFail = $this->bindArrayToObject($r['fieldFail']); + +// Get currently stored data for fields that are display only +$eventDetail = $Events->getEventDetail(); +$this->page->storedDetail = $this->bindArrayToObject($eventDetail); + +// If invalid submission +if (!$status) { + $this->page->editingEvent = true; + $this->templateFile = 'Event/EditEvent.html'; +} else { + $this->templateFile = 'Event/EventDetail.html'; +} + +?> + diff --git a/models/admin/actions/EventFee/add.inc b/models/admin/actions/EventFee/add.inc new file mode 100644 index 0000000..9d1a4ed --- /dev/null +++ b/models/admin/actions/EventFee/add.inc @@ -0,0 +1,28 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: eventFee.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/eventFees.php'; +$EventFees = new EventManagementAdminEventFees($this->dbh, $this->config); + + +$r = $EventFees->newFee(); + +$this->page->feeDetail = $this->bindArrayToObject($r['fieldData']); +$this->page->fieldRequired = $this->bindArrayToObject($r['fieldRequired']); +$this->page->fieldFail = $this->bindArrayToObject($r['fieldFail']); +$this->page->addingNewFee = true; + +$this->templateFile = 'EventFee/EditEventFee.html'; + +?> \ No newline at end of file diff --git a/models/admin/actions/EventFee/confirmDelete.inc b/models/admin/actions/EventFee/confirmDelete.inc new file mode 100644 index 0000000..5920e41 --- /dev/null +++ b/models/admin/actions/EventFee/confirmDelete.inc @@ -0,0 +1,24 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: eventFee.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/eventFees.php'; +$EventFees = new EventManagementAdminEventFees($this->dbh, $this->config); + + +$feeDetail = $EventFees->feeDelete(true); +$this->page->feeDetail = $this->bindArrayToObject($feeDetail); + +$this->templateFile = 'EventFee/EventFeeDetail.html'; + +?> \ No newline at end of file diff --git a/models/admin/actions/EventFee/delete.inc b/models/admin/actions/EventFee/delete.inc new file mode 100644 index 0000000..64198a0 --- /dev/null +++ b/models/admin/actions/EventFee/delete.inc @@ -0,0 +1,24 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: eventFee.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/eventFees.php'; +$EventFees = new EventManagementAdminEventFees($this->dbh, $this->config); + + +$feeDetail = $EventFees->feeDelete(false); +$this->page->feeDetail = $this->bindArrayToObject($feeDetail); + +$this->templateFile = 'EventFee/EventFeeDetail.html'; + +?> \ No newline at end of file diff --git a/models/admin/actions/EventFee/detail.inc b/models/admin/actions/EventFee/detail.inc new file mode 100644 index 0000000..49482e8 --- /dev/null +++ b/models/admin/actions/EventFee/detail.inc @@ -0,0 +1,26 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: eventFee.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/eventFees.php'; +$EventFees = new EventManagementAdminEventFees($this->dbh, $this->config); + + +$feeDetail = $EventFees->getFeeDetail(); +$this->page->feeDetail = $this->bindArrayToObject($feeDetail); + +$this->templateFile = 'EventFee/EventFeeDetail.html'; + +$this->addDebug("EventFee/detail.inc", 'Fee Detail', print_r($feeDetail,1)); + +?> \ No newline at end of file diff --git a/models/admin/actions/EventFee/edit.inc b/models/admin/actions/EventFee/edit.inc new file mode 100644 index 0000000..67d64dc --- /dev/null +++ b/models/admin/actions/EventFee/edit.inc @@ -0,0 +1,32 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: eventFee.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/eventFees.php'; +$EventFees = new EventManagementAdminEventFees($this->dbh, $this->config); + + +// Check Event Fee Code +$feeDetail = $EventFees->editFee(); +$this->page->feeDetail = $this->bindArrayToObject($feeDetail); + +// We need this to mimic stored detail for edit templates that show this on entry to edit +$this->page->storedDetail = $this->bindArrayToObject($feeDetail); + +$this->page->editingFee = true; + +$this->templateFile = 'EventFee/EditEventFee.html'; + +$this->addDebug("EventFee/edit.inc", 'Fee Detail', print_r($feeDetail,1)); + +?> \ No newline at end of file diff --git a/models/admin/actions/EventFee/insert.inc b/models/admin/actions/EventFee/insert.inc new file mode 100644 index 0000000..a139b0e --- /dev/null +++ b/models/admin/actions/EventFee/insert.inc @@ -0,0 +1,38 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: eventFee.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/eventFees.php'; +$EventFees = new EventManagementAdminEventFees($this->dbh, $this->config); + + +// Process new record +$r = $EventFees->insertFee(); + +// Get success status, false = fail +$status = $r['status']; +$this->page->formFail = !$status; + +$this->page->feeDetail = $this->bindArrayToObject($r['fieldData']); +$this->page->fieldRequired = $this->bindArrayToObject($r['fieldRequired']); +$this->page->fieldFail = $this->bindArrayToObject($r['fieldFail']); + +// If invalid submission +if (!$status) { + $this->page->addingNewFee = true; + $this->templateFile = 'EventFee/EditEventFee.html'; +} else { + $this->templateFile = 'EventFee/EventFeeDetail.html'; +} + +?> \ No newline at end of file diff --git a/models/admin/actions/EventFee/list.inc b/models/admin/actions/EventFee/list.inc new file mode 100644 index 0000000..486e2ef --- /dev/null +++ b/models/admin/actions/EventFee/list.inc @@ -0,0 +1,31 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: eventFee.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/eventFees.php'; +$EventFees = new EventManagementAdminEventFees($this->dbh, $this->config); + + +// Get event fees stats +$feesStats = $EventFees->getEventFeesStats(); +$this->page->feesStats = $this->bindArrayToObject($feesStats); + +// Get Event Fees list +$feesList = $EventFees->getFees('event'); +$this->page->feesList = $this->bindArrayToObject($feesList); + +$this->templateFile = 'EventFee/EventFeesList.html'; + +$this->addDebug("EventFee/list.inc", 'Event Fees List', print_r($feesStats,1).'

     

    '.print_r(feesList,1)); + +?> \ No newline at end of file diff --git a/models/admin/actions/EventFee/update.inc b/models/admin/actions/EventFee/update.inc new file mode 100644 index 0000000..1a23a37 --- /dev/null +++ b/models/admin/actions/EventFee/update.inc @@ -0,0 +1,42 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: eventFee.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/eventFees.php'; +$EventFees = new EventManagementAdminEventFees($this->dbh, $this->config); + + +// Process new record +$r = $EventFees->updateFee(); + +// Get success status, false = fail +$status = $r['status']; +$this->page->formFail = !$status; + +$this->page->feeDetail = $this->bindArrayToObject($r['fieldData']); +$this->page->fieldRequired = $this->bindArrayToObject($r['fieldRequired']); +$this->page->fieldFail = $this->bindArrayToObject($r['fieldFail']); + +// Get currently stored data for fields that are display only +$feeDetail = $EventFees->getFeeDetail(); +$this->page->storedDetail = $this->bindArrayToObject($feeDetail); + +// If invalid submission +if (!$status) { + $this->page->editingFee = true; + $this->templateFile = 'EventFee/EditEventFee.html'; +} else { + $this->templateFile = 'EventFee/EventFeeDetail.html'; +} + +?> \ No newline at end of file diff --git a/models/admin/actions/Help/index.inc b/models/admin/actions/Help/index.inc new file mode 100644 index 0000000..43f2fd1 --- /dev/null +++ b/models/admin/actions/Help/index.inc @@ -0,0 +1,18 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: index.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +$this->templateFile = "Help/index.html"; + +?> + diff --git a/models/admin/actions/Index/index.inc b/models/admin/actions/Index/index.inc new file mode 100644 index 0000000..09d2f62 --- /dev/null +++ b/models/admin/actions/Index/index.inc @@ -0,0 +1,27 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: event.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +// Reset Session +$this->startSession(true); + +// If user level is 20 or above, then start with ticket claims loaded. +$this->page->startWithClaims = 0; +if ($this->page->level >= 20) { + $this->page->startWithClaims = 1; +} + +$this->templateFile = "index.html"; + +?> + diff --git a/models/admin/actions/Index/welcome.inc b/models/admin/actions/Index/welcome.inc new file mode 100644 index 0000000..b99344b --- /dev/null +++ b/models/admin/actions/Index/welcome.inc @@ -0,0 +1,18 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: event.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +$this->templateFile = "Welcome/index.html"; + +?> + diff --git a/models/admin/actions/Member/add.inc b/models/admin/actions/Member/add.inc new file mode 100644 index 0000000..fc3e1bc --- /dev/null +++ b/models/admin/actions/Member/add.inc @@ -0,0 +1,30 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: event.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/members.php'; +$Members = new EventManagementAdminMembers($this->dbh, $this->config); + +// Check Member Code +$r = $Members->newEntry(); + +$this->page->memberDetail = $this->bindArrayToObject($r['fieldData']); +$this->page->fieldRequired = $this->bindArrayToObject($r['fieldRequired']); +$this->page->fieldFail = $this->bindArrayToObject($r['fieldFail']); +$this->page->addingNewMember = true; + +$this->templateFile = 'Member/edit.html'; + +$this->addDebug("Member/add.inc", 'Member Add', print_r($r,1)); + +?> \ No newline at end of file diff --git a/models/admin/actions/Member/confirmDelete.inc b/models/admin/actions/Member/confirmDelete.inc new file mode 100644 index 0000000..5ac4dbf --- /dev/null +++ b/models/admin/actions/Member/confirmDelete.inc @@ -0,0 +1,27 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: event.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/members.php'; +$Members = new EventManagementAdminMembers($this->dbh, $this->config); + +$memberDetail = $Members->memberDelete(true); +$this->page->memberDetail = $this->bindArrayToObject($memberDetail); + +$this->page->memberDeleted = true; + +$this->templateFile = 'Member/detail.html'; + +$this->addDebug("Member/delete.inc", 'Member Delete', print_r($memberDetail,1)); + +?> \ No newline at end of file diff --git a/models/admin/actions/Member/delete.inc b/models/admin/actions/Member/delete.inc new file mode 100644 index 0000000..a68027b --- /dev/null +++ b/models/admin/actions/Member/delete.inc @@ -0,0 +1,32 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: event.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/members.php'; +$Members = new EventManagementAdminMembers($this->dbh, $this->config); + +// Check Member Code +$memberDetail = $Members->getMemberDetail(); + +$this->page->memberDetail = $this->bindArrayToObject($memberDetail); + +// We need this to mimic stored detail for edit templates that show this on entry to edit +$this->page->storedDetail = $this->bindArrayToObject($memberDetail); + +$this->page->editingMember = true; + +$this->templateFile = 'Member/delete.html'; + +$this->addDebug("Member/delete.inc", 'Member Delete', print_r($memberDetail,1)); + +?> \ No newline at end of file diff --git a/models/admin/actions/Member/detail.inc b/models/admin/actions/Member/detail.inc new file mode 100644 index 0000000..ab9dcd6 --- /dev/null +++ b/models/admin/actions/Member/detail.inc @@ -0,0 +1,48 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: event.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/members.php'; +$Members = new EventManagementAdminMembers($this->dbh, $this->config); + +$memberDetail = $Members->getMemberDetail(); +$memberID = $memberDetail['id']; + +// Also get list of members this member scans for +require_once EVENT_MANAGEMENT_APP_BASE.'classes/data/dataMemberScansFor.php'; +$MemberScansFor = new EventManagementDataMemberScansFor($this->dbh, $this->config); +$memberScansFor = $MemberScansFor->getMemberScansForList($memberID); +if (is_array($memberScansFor) && count($memberScansFor) > 0) { + $this->page->haveMemberScansFor = true; + $this->page->memberScansFor = $this->bindArrayToObject($memberScansFor); +} else { + $this->page->haveMemberScansFor = false; +} + +if ($memberDetail != false) { + // Also need to add static amenity names + $amen_array = $this->config->memb_amen->toArray(); + while( list($key, $val) = each( $amen_array ) ) { + $memberDetail['amen_'.$key]['displayName'] = $val; + } + + $this->page->memberDetail = $this->bindArrayToObject($memberDetail); +} else { + $this->page->memberNotFound = true; +} + +$this->templateFile = 'Member/detail.html'; + +$this->addDebug("Member/detail.inc", 'Members Detail', print_r($memberDetail,1)); + +?> \ No newline at end of file diff --git a/models/admin/actions/Member/edit.inc b/models/admin/actions/Member/edit.inc new file mode 100644 index 0000000..0b6cbc8 --- /dev/null +++ b/models/admin/actions/Member/edit.inc @@ -0,0 +1,59 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: event.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/members.php'; +$Members = new EventManagementAdminMembers($this->dbh, $this->config); +/* +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/contacts.php'; +$Contacts = new EventManagementAdminContacts($this->dbh, $this->config); +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/accommodations.php'; +$Accoms = new EventManagementAdminAccoms($this->dbh, $this->config); +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/memberFees.php'; +$memberFees = new EventManagementAdminMemberFees($this->dbh, $this->config); +*/ + +// Check Member Code +$memberDetail = $Members->editMember(); +$memberID = $memberDetail['id']; + +// Also need to add static amenity names +$amen_array = $this->config->memb_amen->toArray(); +while( list($key, $val) = each( $amen_array ) ) { + $memberDetail['amen_'.$key]['displayName'] = $val; +} +$this->page->memberDetail = $this->bindArrayToObject($memberDetail); + +// Also get list of members this member scans for +require_once EVENT_MANAGEMENT_APP_BASE.'classes/data/dataMemberScansFor.php'; +$MemberScansFor = new EventManagementDataMemberScansFor($this->dbh, $this->config); +$memberScansFor = $MemberScansFor->getMemberScansForList($memberID); +$this->page->memberScansFor = $this->bindArrayToObject($memberScansFor); + +// And get full list of members (except this member) to use for Member Scans For select list +$sql = "SELECT id, name FROM eventmgt.member WHERE active AND id != $memberID;"; +$stmt = $this->dbh->prepare($sql); +$stmt->execute(); +$memberList = $stmt->fetchAll(PDO::FETCH_ASSOC); +$this->page->memberList = $this->bindArrayToObject($memberList); + +// We need this to mimic stored detail for edit templates that show this on entry to edit +//$this->page->storedDetail = $this->bindArrayToObject($memberDetail); + +$this->page->editingMember = true; + +$this->templateFile = 'Member/edit.html'; + +$this->addDebug("Member/edit.inc", 'Array: $memberDetail', print_r($memberDetail,1)); + +?> \ No newline at end of file diff --git a/models/admin/actions/Member/index.inc b/models/admin/actions/Member/index.inc new file mode 100644 index 0000000..08cc7b4 --- /dev/null +++ b/models/admin/actions/Member/index.inc @@ -0,0 +1,17 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: event.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +$this->templateFile = 'Member/index.html'; + +?> \ No newline at end of file diff --git a/models/admin/actions/Member/insert.inc b/models/admin/actions/Member/insert.inc new file mode 100644 index 0000000..db28550 --- /dev/null +++ b/models/admin/actions/Member/insert.inc @@ -0,0 +1,41 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: event.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/members.php'; +$Members = new EventManagementAdminMembers($this->dbh, $this->config); + +// Process new record +$r = $Members->insertMember(); + +// Get success status, false = fail +$status = $r['status']; +$this->page->formFail = !$status; + +$this->page->memberDetail = $this->bindArrayToObject($r['fieldData']); +$this->page->fieldRequired = $this->bindArrayToObject($r['fieldRequired']); +$this->page->fieldFail = $this->bindArrayToObject($r['fieldFail']); + +$_SESSION[GLM_EVENT_SESSION]['Member'] = $r['fieldData']['id']; + +// If invalid submission +if (!$status) { + $this->page->addingNewMember = true; + $this->templateFile = 'Member/edit.html'; +} else { + $this->templateFile = 'Member/selected.html'; +} + +$this->addDebug("Member/insert.inc", 'Members Insert', print_r($r,1)); + +?> \ No newline at end of file diff --git a/models/admin/actions/Member/list.inc b/models/admin/actions/Member/list.inc new file mode 100644 index 0000000..9f5370a --- /dev/null +++ b/models/admin/actions/Member/list.inc @@ -0,0 +1,35 @@ + + + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: event.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/members.php'; +$Members = new EventManagementAdminMembers($this->dbh, $this->config); + +// Get members list +$members = $Members->getMembersList('all'); + +$this->page->membersList = $this->bindArrayToObject($members); + +// Check if we also need to display a member detail (list redisplay on member update). +$this->page->displayMember = false; +if (isset($_REQUEST['memberID']) && ($_REQUEST['memberID']-0) > 0) { + $this->page->displayMember = ($_REQUEST['memberID']-0); +} + +$this->templateFile = 'Member/list.html'; + +$this->addDebug("Member/list.inc", 'Member List', print_r($members,1)); + +?> \ No newline at end of file diff --git a/models/admin/actions/Member/selected.inc b/models/admin/actions/Member/selected.inc new file mode 100644 index 0000000..0fc654a --- /dev/null +++ b/models/admin/actions/Member/selected.inc @@ -0,0 +1,100 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: event.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/members.php'; +$Members = new EventManagementAdminMembers($this->dbh, $this->config); +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/contacts.php'; +$Contacts = new EventManagementAdminContacts($this->dbh, $this->config); + +$memberDetail = $Members->getMemberDetail(); + +// Also need to add static amenity names +$amen_array = $this->config->memb_amen->toArray(); +while( list($key, $val) = each( $amen_array ) ) { + $memberDetail['amen_'.$key]['displayName'] = $val; +} +$this->page->memberDetail = $this->bindArrayToObject($memberDetail); + +$_SESSION[GLM_EVENT_SESSION]['Member'] = $memberDetail['id']; + +// Get other stats and clear all flags +$memberStats = array( + 'contact' => $Contacts->getMemberContactsStats(), + 'flags' => false, + 'flag' => false +); + +// Check contact status +if ($memberStats['contact'] == 0) { + $memberStats['flags']['noContacts'] = true; + $memberStats['flag'] = true; +} + +// Check accommodation status +if ($this->config->option->accommodations) { + + require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/accommodations.php'; + $Accoms = new EventManagementAdminAccoms($this->dbh, $this->config); + require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/inventory.php'; + $Inventory = new EventManagementAdminInventory($this->dbh, $this->config); + + $memberStats['accom'] = $Accoms->getMemberAccomsStats(); + $memberStats['inven'] = $Inventory->getMemberInvenStats(); + if ($memberStats['accom'] == 0) { + $memberStats['flags']['noAccoms'] = true; + $memberStats['flag'] = true; + } + if ($memberStats['inven'] == 0) { + $memberStats['flags']['noInven'] = true; + $memberStats['flag'] = true; + } +}; + +// Check ticket status +if ($this->config->option->tickets) { + + require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/sections.php'; + $Sections = new EventManagementAdminSections($this->dbh, $this->config); + require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/performances.php'; + $Performances = new EventManagementAdminPerformances($this->dbh, $this->config); + require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/tickets.php'; + $Tickets = new EventManagementAdminTickets($this->dbh, $this->config); + + $memberStats['section'] = $Sections->getMemberSectionsStats(); + $memberStats['performance'] = $Performances->getMemberPerformancesStats(); + $memberStats['ticket'] = $Tickets->getMemberTicketsStats(); + + if ($memberStats['section'] == 0) { + $memberStats['flags']['noSections'] = true; + $memberStats['flag'] = true; + } + if ($memberStats['performance'] == 0) { + $memberStats['flags']['noPerformances'] = true; + $memberStats['flag'] = true; + } + if ($memberStats['ticket'] == 0) { + $memberStats['flags']['noTickets'] = true; + $memberStats['flag'] = true; + } + +} + +$this->page->memberStats = $this->bindArrayToObject($memberStats); + +$this->templateFile = 'Member/selected.html'; + +$this->addDebug("Member/selected.inc", 'Member Detail', print_r($memberDetail,1)); +$this->addDebug("Member/selected.inc", 'Member Stats', print_r($memberStats,1)); + +?> \ No newline at end of file diff --git a/models/admin/actions/Member/stats.inc b/models/admin/actions/Member/stats.inc new file mode 100644 index 0000000..62f0d13 --- /dev/null +++ b/models/admin/actions/Member/stats.inc @@ -0,0 +1,32 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: event.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/members.php'; +$Members = new EventManagementAdminMembers($this->dbh, $this->config); + +// Check for new mebers whenever we get here - only called if integrated database +if ($this->config->option->member_db_integrated) { + $Members->checkNewMembers(); +} + +// Get members stats +$membersStats = $Members->getMembersStats(); + +$this->page->membersStats = $this->bindArrayToObject($membersStats); + +$this->templateFile = 'Member/stats.html'; + +$this->addDebug("Member/stats.inc", 'Array: $memberStats', print_r($membersStats,1)); + +?> \ No newline at end of file diff --git a/models/admin/actions/Member/update.inc b/models/admin/actions/Member/update.inc new file mode 100644 index 0000000..67b77f8 --- /dev/null +++ b/models/admin/actions/Member/update.inc @@ -0,0 +1,56 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: event.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/members.php'; +$Members = new EventManagementAdminMembers($this->dbh, $this->config); + +// Process new record +$r = $Members->updateMember(); + +// Also need to add static amenity names +$amen_array = $this->config->memb_amen->toArray(); +while( list($key, $val) = each( $amen_array ) ) { + $r['fieldData']['amen_'.$key]['displayName'] = $val; +} + +// Also update list of members this member scans for +require_once EVENT_MANAGEMENT_APP_BASE.'classes/data/dataMemberScansFor.php'; +$MemberScansFor = new EventManagementDataMemberScansFor($this->dbh, $this->config); +$memberScansFor = $MemberScansFor->updateMemberScansForList($r['fieldData']['id']); +$this->page->memberScansFor = $this->bindArrayToObject($memberScansFor); + +// Get success status, false = fail +$status = $r['status']; +$this->page->formFail = !$status; + +$this->page->memberDetail = $this->bindArrayToObject($r['fieldData']); +$this->page->fieldRequired = $this->bindArrayToObject($r['fieldRequired']); +$this->page->fieldFail = $this->bindArrayToObject($r['fieldFail']); + +// Get currently stored data for fields that are display only +$memberDetail = $Members->getMemberDetail(); +$this->page->storedDetail = $this->bindArrayToObject($memberDetail); + +// If invalid submission +if (!$status) { + $this->page->editingMember = true; + $this->templateFile = 'Member/edit.html'; +} else { + // $this->templateFile = 'Member/detail.html'; + $this->templateFile = 'Member/redisplayList.html'; +} + +$this->addDebug("Member/update.inc", 'Member Update', print_r($r,1)); + +?> \ No newline at end of file diff --git a/models/admin/actions/MemberAmenities/add.inc b/models/admin/actions/MemberAmenities/add.inc new file mode 100644 index 0000000..01fcd3d --- /dev/null +++ b/models/admin/actions/MemberAmenities/add.inc @@ -0,0 +1,28 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: event.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/memberAmenities.php'; +$MemberAmenities = new EventManagementAdminMemberAmenities($this->dbh, $this->config); + + +$r = $MemberAmenities->newAmenity(); + +$this->page->amenityDetail = $this->bindArrayToObject($r['fieldData']); +$this->page->fieldRequired = $this->bindArrayToObject($r['fieldRequired']); +$this->page->fieldFail = $this->bindArrayToObject($r['fieldFail']); +$this->page->addingNewAmenity = true; + +$this->templateFile = 'Amenity/EditMemberAmenity.html'; + +?> \ No newline at end of file diff --git a/models/admin/actions/MemberAmenities/detail.inc b/models/admin/actions/MemberAmenities/detail.inc new file mode 100644 index 0000000..0b23262 --- /dev/null +++ b/models/admin/actions/MemberAmenities/detail.inc @@ -0,0 +1,25 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: event.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/memberAmenities.php'; +$MemberAmenities = new EventManagementAdminMemberAmenities($this->dbh, $this->config); + + +$amenityDetail = $MemberAmenities->getAmenityDetail(); + +$this->page->amenityDetail = $this->bindArrayToObject($amenityDetail); + +$this->templateFile = 'Amenity/MemberAmenityDetail.html'; + +?> \ No newline at end of file diff --git a/models/admin/actions/MemberAmenities/edit.inc b/models/admin/actions/MemberAmenities/edit.inc new file mode 100644 index 0000000..1234c8b --- /dev/null +++ b/models/admin/actions/MemberAmenities/edit.inc @@ -0,0 +1,30 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: event.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/memberAmenities.php'; +$MemberAmenities = new EventManagementAdminMemberAmenities($this->dbh, $this->config); + + +// Check Member Amenity Code +$amenityDetail = $MemberAmenities->editAmenity(); +$this->page->amenityDetail = $this->bindArrayToObject($amenityDetail); + +// We need this to mimic stored detail for edit templates that show this on entry to edit +$this->page->storedDetail = $this->bindArrayToObject($memberAmenityDetail); + +$this->page->editingAmenity = true; + +$this->templateFile = 'Amenity/EditMemberAmenity.html'; + +?> \ No newline at end of file diff --git a/models/admin/actions/MemberAmenities/insert.inc b/models/admin/actions/MemberAmenities/insert.inc new file mode 100644 index 0000000..23d21fa --- /dev/null +++ b/models/admin/actions/MemberAmenities/insert.inc @@ -0,0 +1,38 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: event.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/memberAmenities.php'; +$MemberAmenities = new EventManagementAdminMemberAmenities($this->dbh, $this->config); + + +// Process new record +$r = $MemberAmenities->insertAmenity(); + +// Get success status, false = fail +$status = $r['status']; +$this->page->formFail = !$status; + +$this->page->amenityDetail = $this->bindArrayToObject($r['fieldData']); +$this->page->fieldRequired = $this->bindArrayToObject($r['fieldRequired']); +$this->page->fieldFail = $this->bindArrayToObject($r['fieldFail']); + +// If invalid submission +if (!$status) { + $this->page->addingNewAmenity = true; + $this->templateFile = 'Amenity/EditMemberAmenity.html'; +} else { + $this->templateFile = 'Amenity/MemberAmenityDetail.html'; +} + +?> \ No newline at end of file diff --git a/models/admin/actions/MemberAmenities/list.inc b/models/admin/actions/MemberAmenities/list.inc new file mode 100644 index 0000000..9c80b1c --- /dev/null +++ b/models/admin/actions/MemberAmenities/list.inc @@ -0,0 +1,29 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: event.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/memberAmenities.php'; +$MemberAmenities = new EventManagementAdminMemberAmenities($this->dbh, $this->config); + + +// Get member amenities stats +$amenitiesStats = $MemberAmenities->getMemberAmenitiesStats(); +$this->page->amenitiesStats = $this->bindArrayToObject($amenitiesStats); + +// Get Member Amenities list +$amenitiesList = $MemberAmenities->getAmenities('member'); +$this->page->amenitiesList = $this->bindArrayToObject($amenitiesList); + +$this->templateFile = 'Amenity/MemberAmenitiesList.html'; + +?> \ No newline at end of file diff --git a/models/admin/actions/MemberAmenities/update.inc b/models/admin/actions/MemberAmenities/update.inc new file mode 100644 index 0000000..20d7e04 --- /dev/null +++ b/models/admin/actions/MemberAmenities/update.inc @@ -0,0 +1,42 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: event.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/memberAmenities.php'; +$MemberAmenities = new EventManagementAdminMemberAmenities($this->dbh, $this->config); + + +// Process new record +$r = $MemberAmenities->updateAmenity(); + +// Get success status, false = fail +$status = $r['status']; +$this->page->formFail = !$status; + +$this->page->amenityDetail = $this->bindArrayToObject($r['fieldData']); +$this->page->fieldRequired = $this->bindArrayToObject($r['fieldRequired']); +$this->page->fieldFail = $this->bindArrayToObject($r['fieldFail']); + +// Get currently stored data for fields that are display only +$amenityDetail = $MemberAmenities->getAmenityDetail(); +$this->page->storedDetail = $this->bindArrayToObject($amenityDetail); + +// If invalid submission +if (!$status) { + $this->page->editingAmenity = true; + $this->templateFile = 'Amenity/EditMemberAmenity.html'; +} else { + $this->templateFile = 'Amenity/MemberAmenityDetail.html'; +} + +?> \ No newline at end of file diff --git a/models/admin/actions/MemberFee/add.inc b/models/admin/actions/MemberFee/add.inc new file mode 100644 index 0000000..16a9387 --- /dev/null +++ b/models/admin/actions/MemberFee/add.inc @@ -0,0 +1,34 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: event.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/memberFees.php'; +$MemberFees = new EventManagementAdminMemberFees($this->dbh, $this->config); + + +$r = $MemberFees->newFee(); + +// check for selected event to use for default for specific event +$e = $_SESSION[GLM_EVENT_SESSION]['Event']; +if ($e && isset($r['fieldData']['event']['pick_list'][$e])) { + $r['fieldData']['event']['pick_list'][$e]['default'] = true; +} + +$this->page->feeDetail = $this->bindArrayToObject($r['fieldData']); +$this->page->fieldRequired = $this->bindArrayToObject($r['fieldRequired']); +$this->page->fieldFail = $this->bindArrayToObject($r['fieldFail']); +$this->page->addingNewFee = true; + +$this->templateFile = 'MemberFee/EditMemberFee.html'; + +?> \ No newline at end of file diff --git a/models/admin/actions/MemberFee/confirmDelete.inc b/models/admin/actions/MemberFee/confirmDelete.inc new file mode 100644 index 0000000..18122a4 --- /dev/null +++ b/models/admin/actions/MemberFee/confirmDelete.inc @@ -0,0 +1,24 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: event.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/memberFees.php'; +$MemberFees = new EventManagementAdminMemberFees($this->dbh, $this->config); + + +$feeDetail = $MemberFees->feeDelete(true); +$this->page->feeDetail = $this->bindArrayToObject($feeDetail); + +$this->templateFile = 'MemberFee/MemberFeeDetail.html'; + +?> \ No newline at end of file diff --git a/models/admin/actions/MemberFee/delete.inc b/models/admin/actions/MemberFee/delete.inc new file mode 100644 index 0000000..bf2f2b4 --- /dev/null +++ b/models/admin/actions/MemberFee/delete.inc @@ -0,0 +1,24 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: event.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/memberFees.php'; +$MemberFees = new EventManagementAdminMemberFees($this->dbh, $this->config); + + +$feeDetail = $MemberFees->feeDelete(false); +$this->page->feeDetail = $this->bindArrayToObject($feeDetail); + +$this->templateFile = 'MemberFee/MemberFeeDetail.html'; + +?> \ No newline at end of file diff --git a/models/admin/actions/MemberFee/detail.inc b/models/admin/actions/MemberFee/detail.inc new file mode 100644 index 0000000..5c3b4b6 --- /dev/null +++ b/models/admin/actions/MemberFee/detail.inc @@ -0,0 +1,25 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: event.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/memberFees.php'; +$MemberFees = new EventManagementAdminMemberFees($this->dbh, $this->config); + + +$feeDetail = $MemberFees->getFeeDetail(); + +$this->page->feeDetail = $this->bindArrayToObject($feeDetail); + +$this->templateFile = 'MemberFee/MemberFeeDetail.html'; + +?> \ No newline at end of file diff --git a/models/admin/actions/MemberFee/edit.inc b/models/admin/actions/MemberFee/edit.inc new file mode 100644 index 0000000..ebe2a40 --- /dev/null +++ b/models/admin/actions/MemberFee/edit.inc @@ -0,0 +1,37 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: event.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/memberFees.php'; +$MemberFees = new EventManagementAdminMemberFees($this->dbh, $this->config); + + +// Check Member Fee Code +$feeDetail = $MemberFees->editFee(); + +// check for selected event to use for default for specific event +$e = $_SESSION[GLM_EVENT_SESSION]['Event']; +if ($e && isset($feeDetail['fieldData']['event']['pick_list'][$e])) { + $feeDetail['fieldData']['event']['pick_list'][$e]['default'] = true; +} + +$this->page->feeDetail = $this->bindArrayToObject($feeDetail); + +// We need this to mimic stored detail for edit templates that show this on entry to edit +$this->page->storedDetail = $this->bindArrayToObject($memberFeeDetail); + +$this->page->editingFee = true; + +$this->templateFile = 'MemberFee/EditMemberFee.html'; + +?> \ No newline at end of file diff --git a/models/admin/actions/MemberFee/insert.inc b/models/admin/actions/MemberFee/insert.inc new file mode 100644 index 0000000..486164d --- /dev/null +++ b/models/admin/actions/MemberFee/insert.inc @@ -0,0 +1,38 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: event.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/memberFees.php'; +$MemberFees = new EventManagementAdminMemberFees($this->dbh, $this->config); + + +// Process new record +$r = $MemberFees->insertFee(); + +// Get success status, false = fail +$status = $r['status']; +$this->page->formFail = !$status; + +$this->page->feeDetail = $this->bindArrayToObject($r['fieldData']); +$this->page->fieldRequired = $this->bindArrayToObject($r['fieldRequired']); +$this->page->fieldFail = $this->bindArrayToObject($r['fieldFail']); + +// If invalid submission +if (!$status) { + $this->page->addingNewFee = true; + $this->templateFile = 'MemberFee/EditMemberFee.html'; +} else { + $this->templateFile = 'MemberFee/MemberFeeDetail.html'; +} + +?> \ No newline at end of file diff --git a/models/admin/actions/MemberFee/list.inc b/models/admin/actions/MemberFee/list.inc new file mode 100644 index 0000000..e8d70a4 --- /dev/null +++ b/models/admin/actions/MemberFee/list.inc @@ -0,0 +1,29 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: event.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/memberFees.php'; +$MemberFees = new EventManagementAdminMemberFees($this->dbh, $this->config); + + +// Get member fees stats +$feesStats = $MemberFees->getMemberFeesStats(); +$this->page->feesStats = $this->bindArrayToObject($feesStats); + +// Get Member Fees list +$feesList = $MemberFees->getFees('member'); +$this->page->feesList = $this->bindArrayToObject($feesList); + +$this->templateFile = 'MemberFee/MemberFeesList.html'; + +?> \ No newline at end of file diff --git a/models/admin/actions/MemberFee/update.inc b/models/admin/actions/MemberFee/update.inc new file mode 100644 index 0000000..426266b --- /dev/null +++ b/models/admin/actions/MemberFee/update.inc @@ -0,0 +1,42 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: event.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/memberFees.php'; +$MemberFees = new EventManagementAdminMemberFees($this->dbh, $this->config); + + +// Process new record +$r = $MemberFees->updateFee(); + +// Get success status, false = fail +$status = $r['status']; +$this->page->formFail = !$status; + +$this->page->feeDetail = $this->bindArrayToObject($r['fieldData']); +$this->page->fieldRequired = $this->bindArrayToObject($r['fieldRequired']); +$this->page->fieldFail = $this->bindArrayToObject($r['fieldFail']); + +// Get currently stored data for fields that are display only +$feeDetail = $MemberFees->getFeeDetail(); +$this->page->storedDetail = $this->bindArrayToObject($feeDetail); + +// If invalid submission +if (!$status) { + $this->page->editingFee = true; + $this->templateFile = 'MemberFee/EditMemberFee.html'; +} else { + $this->templateFile = 'MemberFee/MemberFeeDetail.html'; +} + +?> \ No newline at end of file diff --git a/models/admin/actions/Misc/blank.inc b/models/admin/actions/Misc/blank.inc new file mode 100644 index 0000000..7c58511 --- /dev/null +++ b/models/admin/actions/Misc/blank.inc @@ -0,0 +1,18 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: index.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +$this->templateFile = 'Misc/blank.html'; + + +?> diff --git a/models/admin/actions/Misc/configDetail.inc b/models/admin/actions/Misc/configDetail.inc new file mode 100644 index 0000000..e1df266 --- /dev/null +++ b/models/admin/actions/Misc/configDetail.inc @@ -0,0 +1,28 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: event.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/misc.php'; +$Misc = new EventManagementAdminMisc($this->dbh, $this->config); + +$miscConfigDetail = $Misc->getEntry(1); + +$miscConfigDetail['no_payment_reasons'] = nl2br($miscConfigDetail['no_payment_reasons']); + +$this->page->miscConfigDetail = $this->bindArrayToObject($miscConfigDetail); + +$this->templateFile = 'Misc/configDetail.html'; + +$this->addDebug("Misc/configDetail.inc", 'Misc Config Detail', print_r($miscConfigDetail,1)); + +?> \ No newline at end of file diff --git a/models/admin/actions/Misc/configEdit.inc b/models/admin/actions/Misc/configEdit.inc new file mode 100644 index 0000000..e296159 --- /dev/null +++ b/models/admin/actions/Misc/configEdit.inc @@ -0,0 +1,25 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: configEdit.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/misc.php'; +$Misc = new EventManagementAdminMisc($this->dbh, $this->config); + +$miscConfigDetail = $Misc->editEntry(1); + +$this->page->miscConfigDetail = $this->bindArrayToObject($miscConfigDetail); +$this->templateFile = 'Misc/configEdit.html'; + +$this->addDebug("Misc/configEdit.inc", 'Array: $miscConfigDetail', print_r($miscConfigDetail,1)); + +?> \ No newline at end of file diff --git a/models/admin/actions/Misc/configUpdate.inc b/models/admin/actions/Misc/configUpdate.inc new file mode 100644 index 0000000..aaf7480 --- /dev/null +++ b/models/admin/actions/Misc/configUpdate.inc @@ -0,0 +1,40 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: configUpdate.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/misc.php'; +$Misc = new EventManagementAdminMisc($this->dbh, $this->config); + +// Process new record +$r = $Misc->updateEntry(1); + +// Get success status, false = fail +$status = $r['status']; +$this->page->formFail = !$status; + +// If invalid submission +if (!$status) { + $this->templateFile = 'Misc/configEdit.html'; +} else { + + $r['fieldData']['no_payment_reasons'] = nl2br($r['fieldData']['no_payment_reasons']); + $this->templateFile = 'Misc/configDetail.html'; +} + +$this->page->miscConfigDetail = $this->bindArrayToObject($r['fieldData']); +$this->page->fieldRequired = $this->bindArrayToObject($r['fieldRequired']); +$this->page->fieldFail = $this->bindArrayToObject($r['fieldFail']); + +$this->addDebug("Misc/configUpdate.inc", 'Misc Config Detail', print_r($r,1)); + +?> \ No newline at end of file diff --git a/models/admin/actions/Misc/index.inc b/models/admin/actions/Misc/index.inc new file mode 100644 index 0000000..9f62687 --- /dev/null +++ b/models/admin/actions/Misc/index.inc @@ -0,0 +1,18 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: index.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +$this->templateFile = 'Misc/index.html'; + + +?> diff --git a/models/admin/actions/Misc/upload.inc b/models/admin/actions/Misc/upload.inc new file mode 100644 index 0000000..0dbee19 --- /dev/null +++ b/models/admin/actions/Misc/upload.inc @@ -0,0 +1,26 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: upload.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +$filepath = EVENT_MANAGEMENT_APP_BASE.'web/custom/'.$this->config->custom_prefix.'/'; + +// Get last file upload times +$indexTime = filemtime($filepath.'index.html'); +$stylesTime = filemtime($filepath.'styles.css'); +$this->page->indexTime = date('m/d/Y h:i:s A', $indexTime); +$this->page->stylesTime = date('m/d/Y h:i:s A', $stylesTime); + +$this->templateFile = 'Misc/upload.html'; + + +?> diff --git a/models/admin/actions/Misc/uploadIndex.inc b/models/admin/actions/Misc/uploadIndex.inc new file mode 100644 index 0000000..6fee2e0 --- /dev/null +++ b/models/admin/actions/Misc/uploadIndex.inc @@ -0,0 +1,80 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: uploadIndex.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +$this->page->doingIndex = true; +$filepath = EVENT_MANAGEMENT_APP_BASE.'web/custom/'.$this->config->custom_prefix.'/'; + +if (isset($_REQUEST['RevertIndex'])) { + + // Try to copy the previous file back in as the active file. + if (!copy($filepath.'SavedOriginals/index.html', $filepath.'index.html')) { + $this->reason[] = 'Sorry, we were unable restore the previous file.'; + + // Otherwise it's a successful upload + } else { + + $this->page->indexFileRestored = true; + + } + + +} else { + + // Check that it's a text/html file + if (!isset($_FILES['index'])) { + $this->reason[] = 'You did not supply a file.'; + + // Check if it's the right type + } elseif ($_FILES['index']['type'] != 'text/html') { + $this->reason[] = 'The file you supplied is not of type "text/html".'; + + // Read the file into a parameter + } elseif (!($f = file_get_contents($_FILES['index']['tmp_name']))) { + $this->reason[] = 'Unable to read the file provided.'; + + // Make sure there's no flexy or PHP elements in the file + } elseif (preg_match('~reason[] = 'The file you provided has PHP or Flexy Template components that are not permitted.'; + + // Replace the {GLM} tag with a flexy include that will insert content + } elseif (($f = str_replace('{GLM}', '', $f)) == '') { + $this->reason[] = 'Unable to parse the supplied file to prepare it for use.'; + + // Save the file to the destination folder + } elseif (!file_put_contents($filepath.'index.html.NEW', $f)) { + $this->reason[] = 'Unable to store prepared file.'; + + // Try to save off a copy of the current file + } elseif (!copy($filepath.'index.html', $filepath.'SavedOriginals/index.html')) { + $this->reason[] = 'Sorry, we were unable to save the current file as a backup so are not going to put the new one in.'; + + // Try to unlink old file then rename NEW file to index.html + } elseif ( + !unlink($filepath.'index.html') || + !rename($filepath.'index.html.NEW', $filepath.'index.html') + ) { + $this->reason[] = 'There was a problem moving the supplied file into live use. Please check the site and call immediately if there is a problem.'; + + // Otherwise it's a successful upload + } else { + + $this->page->indexFileUploaded = true; + + } + +} + +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/actions/Misc/upload.inc'; + +?> diff --git a/models/admin/actions/Misc/uploadStylesheet.inc b/models/admin/actions/Misc/uploadStylesheet.inc new file mode 100644 index 0000000..e284661 --- /dev/null +++ b/models/admin/actions/Misc/uploadStylesheet.inc @@ -0,0 +1,69 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: uploadStylesheet.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +$this->page->doingStylesheet = true; +$filepath = EVENT_MANAGEMENT_APP_BASE.'web/custom/'.$this->config->custom_prefix.'/'; + +if (isset($_REQUEST['RevertStylesheet'])) { + + // Try to copy the previous file back in as the active file. + if (!copy($filepath.'SavedOriginals/styles.css', $filepath.'styles.css')) { + $this->reason[] = 'Sorry, we were unable restore the previous file.'; + + // Otherwise it's a successful upload + } else { + + $this->page->stylesheetFileRestored = true; + + } + + +} else { + + // Check that it's a text/html file + if (!isset($_FILES['stylesheet'])) { + $this->reason[] = 'You did not supply a file.'; + + // Check if it's the right type + } elseif ($_FILES['stylesheet']['type'] != 'text/css') { + $this->reason[] = 'The file you supplied is not of type "text/html".'; + + // check that the size is reasonable + } elseif ($_FILES['stylesheet']['size'] < 10) { + $this->reason[] = 'There doesn\'t seem to be much in this file.'; + + // Make sure the file gets copied to the destination folder + } elseif (!copy($_FILES['stylesheet']['tmp_name'], $filepath.'styles.css.NEW')) { + $this->reason[] = 'Sorry, we were unable to copy the file you supplied to the destination folder.'; + + // Try to save off a copy of the current file + } elseif (!copy($filepath.'styles.css', $filepath.'SavedOriginals/styles.css')) { + $this->reason[] = 'Sorry, we were unable to save the current file as a backup so are not going to put the new one in.'; + + // Try to unlink old file then rename NEW file to styles.css + } elseif (!unlink($filepath.'styles.css') || !rename($filepath.'styles.css.NEW', $filepath.'styles.css')) { + $this->reason[] = 'There was a problem moving the supplied file into live use. Please check the site and call immediately if there is a problem.'; + + // Otherwise it's a successful upload + } else { + + $this->page->stylesheetFileUploaded = true; + + } + +} + +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/actions/Misc/upload.inc'; + +?> diff --git a/models/admin/actions/Order/delete.inc b/models/admin/actions/Order/delete.inc new file mode 100644 index 0000000..ce24c7a --- /dev/null +++ b/models/admin/actions/Order/delete.inc @@ -0,0 +1,49 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: detail.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +// Call the delete order method in the AdminOrders class to delete the order +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/orders.php'; +$Orders = new EventManagementAdminOrders($this->dbh, $this->config); +$deleted = $Orders->orderDelete(true, 'abc'); + +// echo "Result =
    ".print_r($deleted,1)."
    "; + +if ($deleted === false) { + echo "

    Order NOT Deleted.

    "; + exit; +} + +echo "

    Order DELETED.

    "; + +exit; + + + +// If this is a member user then make sure they only list their own member performances +$type = false; +$id = false; +if ($_SESSION[GLM_EVENT_SESSION]['MemberUser'] && !$this->config->option->users_access_all_members) { + $type = 'member'; + $id = $this->page->userMemberID; +} + +// Get Order detail +$orderDetail = $Orders->getOrderDetail(false, $id); +$this->page->orderDetail = $this->bindArrayToObject($orderDetail); + +$this->templateFile = 'Order/detail.html'; + +$this->addDebug("Order/detail.inc", 'Array: $orderDetail', print_r($orderDetail,1)); + +?> \ No newline at end of file diff --git a/models/admin/actions/Order/detail.inc b/models/admin/actions/Order/detail.inc new file mode 100644 index 0000000..1f289ad --- /dev/null +++ b/models/admin/actions/Order/detail.inc @@ -0,0 +1,43 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: detail.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + + +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/orders.php'; +$Orders = new EventManagementAdminOrders($this->dbh, $this->config); + +// If this is a member user then make sure they only list their own member performances +$type = false; +$id = false; +if ($_SESSION[GLM_EVENT_SESSION]['MemberUser'] && !$this->config->option->users_access_all_members) { + $type = 'member'; + $id = $this->page->userMemberID; +} + +// Get Order detail +$orderDetail = $Orders->getOrderDetail(false, $id); + +// Check for delete request +if ($_REQUEST['Option'] == 'delete') { + $orderDetail['delete'] = true; +} + +$orderDetail['notes'] = nl2br($orderDetail['notes']); + +$this->page->orderDetail = $this->bindArrayToObject($orderDetail); + +$this->templateFile = 'Order/detail.html'; + +$this->addDebug("Order/detail.inc", 'Array: $orderDetail', print_r($orderDetail,1)); + +?> \ No newline at end of file diff --git a/models/admin/actions/Order/edit.inc b/models/admin/actions/Order/edit.inc new file mode 100644 index 0000000..01e78a6 --- /dev/null +++ b/models/admin/actions/Order/edit.inc @@ -0,0 +1,30 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: edit.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/orders.php'; +$Orders = new EventManagementAdminOrders($this->dbh, $this->config); + +$orderDetail = $Orders->editOrder(); +$this->page->orderDetail = $this->bindArrayToObject($orderDetail); + +// We need this to mimic stored detail for edit templates that show this on entry to edit +$this->page->storedDetail = $this->bindArrayToObject($orderDetail); + +$this->page->editingOrder = true; + +$this->templateFile = 'Order/edit.html'; + +$this->addDebug("Order/edit.inc", 'Array: $orderDetail', print_r($orderDetail,1)); + +?> \ No newline at end of file diff --git a/models/admin/actions/Order/list.inc b/models/admin/actions/Order/list.inc new file mode 100644 index 0000000..66e2379 --- /dev/null +++ b/models/admin/actions/Order/list.inc @@ -0,0 +1,35 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: list.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/orders.php'; +$Orders = new EventManagementAdminOrders($this->dbh, $this->config); + +// If this is a member user then make sure they only list their own member performances +$type = false; +$id = false; +if ($_SESSION[GLM_EVENT_SESSION]['MemberUser']) { + $type = 'member'; + $id = $this->page->userMemberID; +} + +$orderList = $Orders->getOrdersList($id, false, false, $type); + +$this->page->orderList = $this->bindArrayToObject($orderList); + +$this->templateFile = 'Order/list.html'; + +$this->addDebug("Order/list.inc", 'Order List', 'Array: $orderList

    '.print_r($orderList,1)); + +?> + diff --git a/models/admin/actions/Order/printVoucher.inc b/models/admin/actions/Order/printVoucher.inc new file mode 100644 index 0000000..e7d6a09 --- /dev/null +++ b/models/admin/actions/Order/printVoucher.inc @@ -0,0 +1,50 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: printVoucher.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +// Get Order Detail +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/orders.php'; +$Orders = new EventManagementAdminOrders($this->dbh, $this->config); +$orderDetail = $Orders->getOrderDetail(); + +// Get Ticket Sold (voucher) detail +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/sold.php'; +$Sold = new EventManagementAdminSold($this->dbh, $this->config); +$type = false; +$id = false; +/* +if ($_SESSION[GLM_EVENT_SESSION]['MemberUser']) { + $type = 'member'; + $id = $this->page->userMemberID; +} +*/ +$soldList = $Sold->getSoldList($orderDetail['id'], false); + +// Get Venue Detail +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/members.php'; +$Members = new EventManagementAdminMembers($this->dbh, $this->config); +$memberDetail = $Members->getMemberDetail($orderDetail['member']); + +// Load voucher design code as per the "voucher_design" config parameter in the site's config/applications/EventManagement.ini file +if (is_file(EVENT_MANAGEMENT_APP_BASE.'models/vouchers/'.$this->config->voucher_design.'/voucher.php')) { + require_once EVENT_MANAGEMENT_APP_BASE.'models/vouchers/'.$this->config->voucher_design.'/voucher.php'; + $pdf = new PdfVoucher($orderDetail, $soldList, $memberDetail, $this->dbh, $this->config); +} else { + echo "SYSTEM ERROR: Site is not configured with a valid voucher design file."; + exit; +} + +// There's nothing to do from here. Output should go direct to browser. +exit; + +?> \ No newline at end of file diff --git a/models/admin/actions/Order/printVoucherMobile.inc b/models/admin/actions/Order/printVoucherMobile.inc new file mode 100755 index 0000000..00543ed --- /dev/null +++ b/models/admin/actions/Order/printVoucherMobile.inc @@ -0,0 +1,48 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: printVoucher.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +// Get Order Detail +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/orders.php'; +$Orders = new EventManagementAdminOrders($this->dbh, $this->config); +$orderDetail = $Orders->getOrderDetail(); + +// Get Ticket Sold (voucher) detail +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/sold.php'; +$Sold = new EventManagementAdminSold($this->dbh, $this->config); +$type = false; +$id = false; +if ($_SESSION[GLM_EVENT_SESSION]['MemberUser']) { + $type = 'member'; + $id = $this->page->userMemberID; +} +$soldList = $Sold->getSoldList(false, $id); + +// Get Venue Detail +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/members.php'; +$Members = new EventManagementAdminMembers($this->dbh, $this->config); +$memberDetail = $Members->getMemberDetail($orderDetail['member']); + +// Load voucher design code as per the "voucher_design" config parameter in the site's config/applications/EventManagement.ini file +if (is_file(EVENT_MANAGEMENT_APP_BASE.'models/vouchers/'.$this->config->voucher_design.'/voucherMobile.php')) { + require_once EVENT_MANAGEMENT_APP_BASE.'models/vouchers/'.$this->config->voucher_design.'/voucherMobile.php'; + $pdf = new PdfVoucher($orderDetail, $soldList, $memberDetail, $this->dbh, $this->config); +} else { + echo "SYSTEM ERROR: Site is not configured with a valid voucher design file."; + exit; +} + +// There's nothing to do from here. Output should go direct to browser. +exit; + +?> \ No newline at end of file diff --git a/models/admin/actions/Order/selected.inc b/models/admin/actions/Order/selected.inc new file mode 100644 index 0000000..c79dd2d --- /dev/null +++ b/models/admin/actions/Order/selected.inc @@ -0,0 +1,25 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: selected.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/orders.php'; +$Orders = new EventManagementAdminOrders($this->dbh, $this->config); + +$orderDetail = $Orders->getOrderDetail(); +$this->page->orderDetail = $this->bindArrayToObject($orderDetail); + +$this->templateFile = 'Order/selected.html'; + +$this->addDebug("Order/selected.inc", 'Order Detail', print_r($orderDetail,1)); + +?> \ No newline at end of file diff --git a/models/admin/actions/Order/update.inc b/models/admin/actions/Order/update.inc new file mode 100644 index 0000000..d2dba66 --- /dev/null +++ b/models/admin/actions/Order/update.inc @@ -0,0 +1,46 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: update.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/orders.php'; +$Orders = new EventManagementAdminOrders($this->dbh, $this->config); + +// Process new record +$r = $Orders->updateOrder(); + +// Get success status, false = fail +$status = $r['status']; +$this->page->formFail = !$status; + + +// If invalid submission +if (!$status) { + $this->page->editingOrder = true; + $this->templateFile = 'Order/edit.html'; +} else { + $this->templateFile = 'Order/detail.html'; + $r['fieldData']['notes'] = nl2br($r['fieldData']['notes']); +} + + +$this->page->orderDetail = $this->bindArrayToObject($r['fieldData']); +$this->page->fieldRequired = $this->bindArrayToObject($r['fieldRequired']); +$this->page->fieldFail = $this->bindArrayToObject($r['fieldFail']); + +// Get currently stored data for fields that are display only +$orderDetail = $Orders->getOrderDetail(); +$this->page->storedDetail = $this->bindArrayToObject($orderDetail); + +$this->addDebug("Order/update.inc", 'Array: $r', print_r($r,1)); + +?> \ No newline at end of file diff --git a/models/admin/actions/Performance/add.inc b/models/admin/actions/Performance/add.inc new file mode 100644 index 0000000..eab9ba2 --- /dev/null +++ b/models/admin/actions/Performance/add.inc @@ -0,0 +1,31 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: add.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/performances.php'; +$Performances = new EventManagementAdminPerformances($this->dbh, $this->config); + +// Get base data and fields +$r = $Performances->newPerformance(); + +$this->page->performanceDetail = $this->bindArrayToObject($r['fieldData']); +$this->page->fieldRequired = $this->bindArrayToObject($r['fieldRequired']); +$this->page->fieldFail = $this->bindArrayToObject($r['fieldFail']); +$this->page->addingNewPerformance = true; + +$this->templateFile = 'Performance/edit.html'; + +$this->addDebug("Performance/add.inc", 'Performance Add', print_r($r,1)); + +?> + diff --git a/models/admin/actions/Performance/confirmDelete.inc b/models/admin/actions/Performance/confirmDelete.inc new file mode 100644 index 0000000..db150b1 --- /dev/null +++ b/models/admin/actions/Performance/confirmDelete.inc @@ -0,0 +1,26 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: confirmDelete.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/performances.php'; +$Performances = new EventManagementAdminPerformances($this->dbh, $this->config); + +$performanceDetail = $Performances->performanceDelete(true); +$this->page->performanceDetail = $this->bindArrayToObject($performanceDetail); + +$this->templateFile = 'Performance/detail.html'; + +$this->addDebug("Performance/confirmDelete.inc", 'Performance Confirm Delete', print_r($performanceDetail,1)); + +?> + diff --git a/models/admin/actions/Performance/delete.inc b/models/admin/actions/Performance/delete.inc new file mode 100644 index 0000000..18ad6e9 --- /dev/null +++ b/models/admin/actions/Performance/delete.inc @@ -0,0 +1,27 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: performance.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/performances.php'; +$Performances = new EventManagementAdminPerformances($this->dbh, $this->config); + + +$performanceDetail = $Performances->performanceDelete(false); +$this->page->performanceDetail = $this->bindArrayToObject($performanceDetail); + +$this->templateFile = 'Performance/delete.html'; + +$this->addDebug("Performance/delete.inc", 'Performance Delete', print_r($performanceDetail,1)); + +?> + diff --git a/models/admin/actions/Performance/detail.inc b/models/admin/actions/Performance/detail.inc new file mode 100644 index 0000000..4267af9 --- /dev/null +++ b/models/admin/actions/Performance/detail.inc @@ -0,0 +1,26 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: event.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/performances.php'; +$Performances = new EventManagementAdminPerformances($this->dbh, $this->config); + +$performanceDetail = $Performances->getPerformanceDetail(); +$this->page->performanceDetail = $this->bindArrayToObject($performanceDetail); + +$this->templateFile = 'Performance/detail.html'; + +$this->addDebug("Performance/detail.inc", 'Performance Detail', print_r($performanceDetail,1)); + +?> + diff --git a/models/admin/actions/Performance/edit.inc b/models/admin/actions/Performance/edit.inc new file mode 100644 index 0000000..f410e10 --- /dev/null +++ b/models/admin/actions/Performance/edit.inc @@ -0,0 +1,30 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: event.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/performances.php'; +$Performances = new EventManagementAdminPerformances($this->dbh, $this->config); + +$performanceDetail = $Performances->editPerformance(); +$this->page->performanceDetail = $this->bindArrayToObject($performanceDetail); + +// We need this to mimic stored detail for edit templates that show this on entry to edit +$this->page->storedDetail = $this->bindArrayToObject($performanceDetail); + +$this->page->editingPerformance = true; +$this->templateFile = 'Performance/edit.html'; + +$this->addDebug("Performance/edit.inc", 'Performance Edit', print_r($performanceDetail,1)); + +?> + diff --git a/models/admin/actions/Performance/insert.inc b/models/admin/actions/Performance/insert.inc new file mode 100644 index 0000000..59b3642 --- /dev/null +++ b/models/admin/actions/Performance/insert.inc @@ -0,0 +1,42 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: event.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/performances.php'; +$Performances = new EventManagementAdminPerformances($this->dbh, $this->config); + +// Process new record +$r = $Performances->insertPerformance(); + +// Get success status, false = fail +$status = $r['status']; +$this->page->formFail = !$status; + +$this->page->performanceDetail = $this->bindArrayToObject($r['fieldData']); +$this->page->fieldRequired = $this->bindArrayToObject($r['fieldRequired']); +$this->page->fieldFail = $this->bindArrayToObject($r['fieldFail']); + +$_SESSION[GLM_EVENT_SESSION]['Performance'] = $r['fieldData']['id']; + +// If invalid submission +if (!$status) { + $this->page->addingNewPerformance = true; + $this->templateFile = 'Performance/edit.html'; +} else { + $this->templateFile = 'Performance/selected.html'; +} + +$this->addDebug("Performance/insert.inc", 'Performance Insert', print_r($r,1)); + +?> + diff --git a/models/admin/actions/Performance/list.inc b/models/admin/actions/Performance/list.inc new file mode 100644 index 0000000..dddb4f8 --- /dev/null +++ b/models/admin/actions/Performance/list.inc @@ -0,0 +1,45 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: event.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/performances.php'; +$Performances = new EventManagementAdminPerformances($this->dbh, $this->config); + +// If this is a member user then make sure they only list their own member performances +$type = false; +$id = false; + +if ($_SESSION[GLM_EVENT_SESSION]['MemberUser']) { + $type = 'member'; + $id = $this->page->userMemberID; +} elseif ($_SESSION[GLM_EVENT_SESSION]['Member'] != false) { + $type = 'member'; + $id = $_SESSION[GLM_EVENT_SESSION]['Member']; +} + +$performanceList = $Performances->getPerformancesList($type, $id, true); + +$this->page->performanceList = $this->bindArrayToObject($performanceList); + +// Check if we also need to display a performance detail (list redisplay on performance update). +$this->page->displayPerformance = false; +if (isset($_REQUEST['performanceID']) && ($_REQUEST['performanceID']-0) > 0) { + $this->page->displayPerformance = ($_REQUEST['performanceID']-0); +} + +$this->templateFile = 'Performance/list.html'; + +$this->addDebug("Performance/list.inc", 'Performance List', 'Array: $performanceList

    '.print_r($performanceList,1)); + +?> + diff --git a/models/admin/actions/Performance/selected.inc b/models/admin/actions/Performance/selected.inc new file mode 100644 index 0000000..a9df432 --- /dev/null +++ b/models/admin/actions/Performance/selected.inc @@ -0,0 +1,26 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: event.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/performances.php'; +$Members = new EventManagementAdminPerformances($this->dbh, $this->config); + +$performanceDetail = $Members->getPerformanceDetail(); + +$this->page->performanceDetail = $this->bindArrayToObject($performanceDetail); + +$this->templateFile = 'Performance/selected.html'; + +$this->addDebug("Performance/selected.inc", 'Performance Detail', print_r($performanceDetail,1)); + +?> \ No newline at end of file diff --git a/models/admin/actions/Performance/summary.inc b/models/admin/actions/Performance/summary.inc new file mode 100644 index 0000000..c123c6b --- /dev/null +++ b/models/admin/actions/Performance/summary.inc @@ -0,0 +1,51 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: event.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/performances.php'; +$Performances = new EventManagementAdminPerformances($this->dbh, $this->config); + +if ($_REQUEST['performanceID']) { + $id = $this->page->performanceID; +} + +// Check for submitted year +$inventoryYear = ''; +if ($_REQUEST['inventoryYear'] && strlen($_REQUEST['inventoryYear']) == 4) { + $inventoryYear = $_REQUEST['inventoryYear']; +} else { + $inventoryYear = date('Y'); +} +$this->page->inventoryYear = $inventoryYear; + +$years = array(); +$thisYear = $inventoryYear; +for ($i = $thisYear-5; $i < $thisYear+5; $i++) { + + $years[$i] = array('year' => $i, 'selected' => ($i == $inventoryYear) ); +} +$this->page->years = $this->bindArrayToObject($years); + +$performanceSummary = $Performances->getPerformanceInventorySummary($id, $inventoryYear); +foreach ($performanceSummary as $k=>$v) { + $performanceSummary[$k]['netAvail'] = $v['avail'] - $v['held']; +} + +$this->page->performanceSummary = $this->bindArrayToObject($performanceSummary); + +$this->templateFile = 'Performance/summary.html'; + +$this->addDebug("Performance/summary.inc", 'Performance Summary', 'Array: $performanceSummary

    '.print_r($performanceSummary,1)); + +?> + diff --git a/models/admin/actions/Performance/update.inc b/models/admin/actions/Performance/update.inc new file mode 100644 index 0000000..98586c6 --- /dev/null +++ b/models/admin/actions/Performance/update.inc @@ -0,0 +1,41 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: event.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/performances.php'; +$Performances = new EventManagementAdminPerformances($this->dbh, $this->config); + +// Process new record +$r = $Performances->updatePerformance(); + +// Get success status, false = fail +$status = $r['status']; +$this->page->formFail = !$status; + +$this->page->performanceDetail = $this->bindArrayToObject($r['fieldData']); +$this->page->fieldRequired = $this->bindArrayToObject($r['fieldRequired']); +$this->page->fieldFail = $this->bindArrayToObject($r['fieldFail']); + +// If invalid submission +if (!$status) { + $this->page->editingPerformance = true; + $this->templateFile = 'Performance/edit.html'; +} else { +// $this->templateFile = 'Performance/detail.html'; + $this->templateFile = 'Performance/redisplayList.html'; +} + +$this->addDebug("Performance/add.inc", 'Performance Add', print_r($r,1)); + +?> + diff --git a/models/admin/actions/Promo/add.inc b/models/admin/actions/Promo/add.inc new file mode 100644 index 0000000..fe0a740 --- /dev/null +++ b/models/admin/actions/Promo/add.inc @@ -0,0 +1,30 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: add.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/promos.php'; +$Promos = new EventManagementAdminPromos($this->dbh, $this->config); + +$r = $Promos->newPromo(); + +$this->page->promoDetail = $this->bindArrayToObject($r['fieldData']); +$this->page->fieldRequired = $this->bindArrayToObject($r['fieldRequired']); +$this->page->fieldFail = $this->bindArrayToObject($r['fieldFail']); + +$this->page->addingNewPromo = true; + +$this->templateFile = 'Promo/edit.html'; + +$this->addDebug("Promo/add.inc", 'Array: $r', print_r($r,1)); + +?> \ No newline at end of file diff --git a/models/admin/actions/Promo/confirmDelete.inc b/models/admin/actions/Promo/confirmDelete.inc new file mode 100644 index 0000000..aaccd6b --- /dev/null +++ b/models/admin/actions/Promo/confirmDelete.inc @@ -0,0 +1,26 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: confirmDelete.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/promos.php'; +$Promos = new EventManagementAdminPromos($this->dbh, $this->config); + +$promoDetail = $Promos->promoDelete(true); +$this->page->promoDetail = $this->bindArrayToObject($promoDetail); + +$this->templateFile = 'Promo/detail.html'; + +$this->addDebug("Promo/confirmDelete.inc", 'Section Confirm Delete', print_r($promoDetail,1)); + +?> + diff --git a/models/admin/actions/Promo/delete.inc b/models/admin/actions/Promo/delete.inc new file mode 100644 index 0000000..8ed6cf0 --- /dev/null +++ b/models/admin/actions/Promo/delete.inc @@ -0,0 +1,26 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: delete.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/promos.php'; +$Promos = new EventManagementAdminPromos($this->dbh, $this->config); + +$promoDetail = $Promos->promoDelete(false); +$this->page->promoDetail = $this->bindArrayToObject($promoDetail); + +$this->templateFile = 'Promo/delete.html'; + +$this->addDebug("Promo/delete.inc", 'Array: $promoDetail', print_r($promoDetail,1)); + +?> + diff --git a/models/admin/actions/Promo/detail.inc b/models/admin/actions/Promo/detail.inc new file mode 100644 index 0000000..7275321 --- /dev/null +++ b/models/admin/actions/Promo/detail.inc @@ -0,0 +1,80 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: detail.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/promos.php'; +$Promos = new EventManagementAdminPromos($this->dbh, $this->config); + +// Get Promotions detail +$promoDetail = $Promos->getPromoDetail(); +$this->page->promoDetail = $this->bindArrayToObject($promoDetail); + +// Get list of tickets that can be used for adding a promotion ticket +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/tickets.php'; +$Tickets = new EventManagementAdminTickets($this->dbh, $this->config); +$where = "T.start_date < '".$promoDetail['end_date']['date']."' AND T.end_date > '".$promoDetail['start_date']['date']; +$tList = $Tickets->getTicketsList(false, false, false, false, false); +// Trim contents of ticketsList to just what's needed +$ticketsList = array(); +if (is_array($tList) && count($tList) > 0) { + foreach ($tList as $t) { + $ticketsList[$t['id']] = array( + 'id' => $t['id'], + 'name' => $t['name'], + 'performance' => $t['performance'] + ); + } + $this->page->ticketsList = $this->bindArrayToObject($ticketsList); +} + +// echo "

    ".print_r($ticketsList,1)."
    "; + +// Get list of Promotion Ticket Types +$pTTypes = $this->config->promo_ticket_type->toArray(); +$promoTicketTypes = array(); +while (list($k, $v) = each($pTTypes)) { + $promoTicketTypes[$k] = array( + 'id' => $k, + 'name' => $v + ); +} +$this->page->promoTicketTypes = $this->bindArrayToObject($promoTicketTypes); + +// Get Promotion Tickets for the currently selected promotion +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/promoTickets.php'; +$PromoTickets = new EventManagementAdminPromoTickets($this->dbh, $this->config); +$promoTicketsList = $PromoTickets->processPromoTicketsList($promoDetail['id']); +$this->page->promoTicketsList = $this->bindArrayToObject($promoTicketsList); + +// Total sales +$numbTotal = 0; +$valTotal = 0; +if ($promoTicketsList) { + foreach($promoTicketsList as $ptl) { + $numbTotal += $ptl['numberSold']; + $valTotal += $ptl['valueSold']; + } +} +$dollarsTotal = $this->money($valTotal); +$this->page->numberTotal = $numbTotal; +$this->page->valueTotal = $valTotal; +$this->page->dollarsTotal = $dollarsTotal; + +$this->templateFile = 'Promo/detail.html'; + +$this->addDebug("Promo/detail.inc", 'Array: $promoDetail', print_r($promoDetail,1)); +$this->addDebug("Promo/detail.inc", 'Array: $promoTicketsList', print_r($promoTicketsList,1)); +$this->addDebug("Promo/detail.inc", 'Array: $promoTicketTypes', print_r($promoTicketTypes,1)); +$this->addDebug("Promo/detail.inc", 'Array: $ticketsList', print_r($ticketsList,1)); + +?> \ No newline at end of file diff --git a/models/admin/actions/Promo/edit.inc b/models/admin/actions/Promo/edit.inc new file mode 100644 index 0000000..ece6bb5 --- /dev/null +++ b/models/admin/actions/Promo/edit.inc @@ -0,0 +1,30 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: edit.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/promos.php'; +$Promos = new EventManagementAdminPromos($this->dbh, $this->config); + +$promoDetail = $Promos->editPromo(); +$this->page->promoDetail = $this->bindArrayToObject($promoDetail); + +// We need this to mimic stored detail for edit templates that show this on entry to edit +$this->page->promoDetail = $this->bindArrayToObject($promoDetail); + +$this->page->editingPromo = true; + +$this->templateFile = 'Promo/edit.html'; + +$this->addDebug("Promo/edit.inc", 'Array: $promoDetail', print_r($promoDetail,1)); + +?> \ No newline at end of file diff --git a/models/admin/actions/Promo/insert.inc b/models/admin/actions/Promo/insert.inc new file mode 100644 index 0000000..f90b9d9 --- /dev/null +++ b/models/admin/actions/Promo/insert.inc @@ -0,0 +1,43 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: insert.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/promos.php'; +$Promos = new EventManagementAdminPromos($this->dbh, $this->config); + +// Process new record +$r = $Promos->insertPromo(); + +// Get success status, false = fail +$status = $r['status']; +$this->page->formFail = !$status; + +$this->page->promoDetail = $this->bindArrayToObject($r['fieldData']); +$this->page->fieldRequired = $this->bindArrayToObject($r['fieldRequired']); +$this->page->fieldFail = $this->bindArrayToObject($r['fieldFail']); + +// If invalid submission +if (!$status) { + $this->page->addingNewPromo = true; + $this->templateFile = 'Promo/edit.html'; +} else { + + $promoID = $r['fieldData']['id']; + + $this->templateFile = 'Promo/selected.html'; +} + +$this->addDebug("Promo/insert.inc", 'Array: $r', print_r($r,1)); + + +?> \ No newline at end of file diff --git a/models/admin/actions/Promo/list.inc b/models/admin/actions/Promo/list.inc new file mode 100644 index 0000000..ac2435a --- /dev/null +++ b/models/admin/actions/Promo/list.inc @@ -0,0 +1,30 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: list.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/promos.php'; +$Promos = new EventManagementAdminPromos($this->dbh, $this->config); + +// Get Promotions stats +$promoStats = $Promos->getPromosStats(); +$this->page->promosStats = $this->bindArrayToObject($promosStats); + +// Get Promotions list +$promosList = $Promos->getPromosList(); +$this->page->promos = $this->bindArrayToObject($promosList); + +$this->templateFile = 'Promo/list.html'; + +$this->addDebug("Promo/list.inc", 'Array: $promosList', print_r($promosList, 1)); + +?> \ No newline at end of file diff --git a/models/admin/actions/Promo/selected.inc b/models/admin/actions/Promo/selected.inc new file mode 100644 index 0000000..e705592 --- /dev/null +++ b/models/admin/actions/Promo/selected.inc @@ -0,0 +1,25 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: selected.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/promos.php'; +$Promos = new EventManagementAdminPromos($this->dbh, $this->config); + +$promoDetail = $Promos->getPromoDetail(); +$this->page->promoDetail = $this->bindArrayToObject($promoDetail); + +$this->templateFile = 'Promo/selected.html'; + +$this->addDebug("Promo/selected.inc", 'Promo Detail', print_r($promoDetail,1)); + +?> \ No newline at end of file diff --git a/models/admin/actions/Promo/update.inc b/models/admin/actions/Promo/update.inc new file mode 100644 index 0000000..a7e4e45 --- /dev/null +++ b/models/admin/actions/Promo/update.inc @@ -0,0 +1,43 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: update.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/promos.php'; +$Promos = new EventManagementAdminPromos($this->dbh, $this->config); + +// Process new record +$r = $Promos->updatePromo(); + +// Get success status, false = fail +$status = $r['status']; +$this->page->formFail = !$status; + +$this->page->promoDetail = $this->bindArrayToObject($r['fieldData']); +$this->page->fieldRequired = $this->bindArrayToObject($r['fieldRequired']); +$this->page->fieldFail = $this->bindArrayToObject($r['fieldFail']); + +// Get currently stored data for fields that are display only +$promoDetail = $Promos->getPromoDetail(); +$this->page->storedDetail = $this->bindArrayToObject($promoDetail); + +// If invalid submission +if (!$status) { + $this->page->editingPromo = true; + $this->templateFile = 'Promo/edit.html'; + $this->addDebug("Promo/update.inc", 'Array: $r', print_r($r,1)); +} else { + // $this->templateFile = 'Promo/detail.html'; + require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/actions/Promo/detail.inc'; +} + +?> \ No newline at end of file diff --git a/models/admin/actions/Report/custom.inc b/models/admin/actions/Report/custom.inc new file mode 100644 index 0000000..ffc9b7b --- /dev/null +++ b/models/admin/actions/Report/custom.inc @@ -0,0 +1,575 @@ + + * @release SVN: $Id: ticket.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +$this->optionIncludeSelectListData = false; + +// If this is an initial entry, display report selection form +if (!isset($_REQUEST['customReport'])) { + + // Get a list of members + require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/members.php'; + $Members = new EventManagementAdminMembers($this->dbh, $this->config); + $members = $Members->getMembersList('all'); + + $mList = array(); + + if (is_array($members) && count($members) > 0) { + + // Get a list of performances + require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/performances.php'; + $Performances = new EventManagementAdminPerformances($this->dbh, $this->config); + $performanceList = $Performances->getPerformancesList($type, $id); + + // Create simple list of members and their performances + reset($members); + while (list($k, $v) = each($members)) { + $mList[$v['id']] = array( + 'id' => $v['id'], + 'name' => $v['name'], + 'performance' => array() + ); + } + + reset($performanceList); + while (list($k, $v) = each($performanceList)) { + $mList[$v['member_id']]['performance'][$v['id']] = array( + 'id' => $v['id'], + 'name' => $v['name'] + ); + } + + } + + $this->page->mList = $this->bindArrayToObject($mList); + + // Setup min and max dates for date selection + $thisDate = date('m/d/Y'); + $minDate = date('m/d/Y', strtotime(date('m/d/Y').' -5 years')); + $maxDate = date('m/d/Y', strtotime(date('m/d/Y').' +5 years')); + $this->page->thisDate = $thisDate; + $this->page->minDate = $minDate; + $this->page->maxDate = $maxDate; + + $this->templateFile = 'Report/customReportSelection.html'; + + $this->addDebug("Report/customReportSelection.inc", 'Custom Reports', 'Array: $mList

    '.print_r($mList,1)); + +// Otherwise we have a report request +} else { + + // Build selection + $where = ''; + $reportNote = 'Report Selection: '; + $reportSpacer = ''; + + // Check report type - default to summary + $detailSelect = ''; + switch ($_REQUEST['reportType']) { + case 'claimsSummary': + $reportType = 'claimsSummary'; + $detailSelect = 'R.id AS order_id, R.fname, R.lname, R.addr1, R.addr2, R.city, R.state, R.zip, R.country, R.phone,'; + $templateFile = 'Report/customClaimed.html'; + $templateFileCSV = '/Report/customClaimedCSV.html'; + break; + case 'claimsDetail': + $reportType = 'claimsDetail'; + $detailSelect = 'R.id AS order_id, R.fname, R.lname, R.addr1, R.addr2, R.city, R.state, R.zip, R.country, R.phone,'; + $templateFile = 'Report/customClaimed.html'; + $templateFileCSV = '/Report/customClaimedCSV.html'; + break; + case 'manifest': + require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/actions/Report/customManifest.inc'; + return; + break; + } + + // Check for selected Venue + if ($_REQUEST['memberID'] > 0) { + $where .= ' AND S.member = '.$_REQUEST['memberID']; + $reportNote .= $reportSpacer.'Selected venue'; + $reportSpacer = ', '; + } + + // Check for selected Performance + if ($_REQUEST['performanceID'] > 0) { + $where .= ' AND S.performance = '.$_REQUEST['performanceID']; + $reportNote .= $reportSpacer.'Selected performance'; + $reportSpacer = ', '; + } + + // Check for inactive venues + if ($_REQUEST['inactive'] != 'on') { + $where .= ' AND M.active = true'; + $reportNote .= $reportSpacer.'Active venues only'; + $reportSpacer = ', '; + } else { + $reportNote .= $reportSpacer.'Including inactive venues'; + $reportSpacer = ', '; + } + + // Check Date Range + $dateFrom = $_REQUEST['start_date']; + $dateTo = $_REQUEST['end_date']; + $dateRange = "between $dateFrom and $dateTo"; + + if ($dateTo == '') { + $dateTo = $dateFrom; + $dateRange = "on $dateFrom"; + } + + $dateFrom .= " 00:00:00.0"; + $dateTo .= " 12:59:59.9999"; + + switch($_REQUEST['dateType']) { + case 'sold': + if ($dateFrom != '' && $dateTo != '') { + $where .= "\nAND R.purchase_date BETWEEN '$dateFrom' AND '$dateTo'"; + $reportNote .= $reportSpacer."Sold $dateRange"; + $reportSpacer = ', '; + } + break; + case 'ticket': + if ($dateFrom != '' && $dateTo != '') { + $where .= "\nAND S.ticket_date BETWEEN '$dateFrom' AND '$dateTo'"; + $reportNote .= $reportSpacer."Ticket dates $dateRange"; + $reportSpacer = ', '; + } + break; + case 'claimed': + if ($dateFrom != '' && $dateTo != '') { + $where .= " + AND ( + SELECT count(id) + FROM eventmgt.ticket_claim_tracking + WHERE ticket_sold = S.id + AND time_of_action BETWEEN '$dateFrom' AND '$dateTo' + ) > 0 + "; + $reportNote .= $reportSpacer."Claim dates $dateRange"; + $reportSpacer = ', '; + } + break; + case 'all': + default: + break; + } + + // Check for claimed only + if ($_REQUEST['claimed'] == 'on') { + $where .= " + AND ( + SELECT count(id) + FROM eventmgt.ticket_claim_tracking + WHERE ticket_sold = S.id + ) > 0 + "; + $reportNote .= $reportSpacer.'Claimed tickets only'; + $reportSpacer = ', '; + } + + // Check for claim detail - Leave enabled for these reports +// $inclClaimDetail = false; +// if ($_REQUEST['claimedDetail'] == 'on') { + $inclClaimDetail = true; +// } + + // Check for whether we should report only on package tickets + $packageWhere = " AND (S.ticket_package IS NULL OR S.ticket_package < 1)"; + $priceSelect = " S.price_paid"; + if ($reportOption == "packageTickets") { + $packageWhere = " AND S.ticket_package > 0"; + $priceSelect = " (SELECT price FROM eventmgt.ticket WHERE id = S.ticket) AS price_paid"; + $reportNote .= $reportSpacer.'Package Tickets Only'; + } + + // Gather Data + $sql = " + SELECT C.scan_name, + C.time_of_action, + S.id AS voucher_id, + S.ticket_order, + S.member_name, + S.performance_name, + S.section_name, + T.name AS ticket_name, + S.date_specific, + S.ticket_date, + S.ticket_time, + R.fname, + R.lname, + R.city, + R.state, + R.phone, + R.email + FROM eventmgt.ticket_claim_tracking C, + eventmgt.ticket_sold S, + eventmgt.ticket T, + eventmgt.member M, + eventmgt.ticket_order R + WHERE S.id = C.ticket_sold + AND T.id = S.ticket + AND M.id = S.member + AND R.id = S.ticket_order + $packageWhere + $where + ORDER BY scan_name, member_name, performance_name, section_name, ticket_name + ;"; +// echo "

    $sql
    "; + + $stmt = $this->dbh->prepare($sql); + $stmt->execute(); + $scanned = $stmt->fetchAll(PDO::FETCH_ASSOC); + +// echo "
    ".print_r($scanned,1)."
    "; + + if (count($scanned)-0 <= 0) { + echo "No Data Returned"; + exit; + } + + $a = array(); + $totalScans = 0; + $totalVouchers = 0; + + foreach ($scanned as $s) { + + $scannedBy = $s['scan_name']; + $member = $s['member_name']; + $performance = $s['performance_name']; + $section = $s['section_name']; + $ticket = $s['ticket_name']; + $dateSpecific = $s['date_specific'] == 't'; + $dateTime = ($dateSpecific ? $s['ticket_date'].' '.$s['ticket_time'] : 'All Dates'); + $voucher = $s['voucher_id']; + + // If scanned by contact hasn't been created + if (!isset($a[$scannedBy])) { + $a[$s['scan_name']] = array( + 'voucherCount' => 0, + 'scans' => 0, + 'members' => array() + ); + } + + // Add count to scanned by + $a[$scannedBy]['scans']++; + $totalScans++; + + // If member hasn't been created + if (!isset($a[$scannedBy]['members'][$member])) { + $a[$scannedBy]['members'][$member] = array( + 'voucherCount' => 0, + 'scans' => 0, + 'performances' => array() + ); + } + + // Add count to members + $a[$scannedBy]['members'][$member]['scans']++; + + // If Performance has not been created + if (!isset($a[$scannedBy]['members'][$member]['performances'][$performance])) { + $a[$scannedBy]['members'][$member]['performances'][$performance] = array( + 'voucherCount' => 0, + 'scans' => 0, + 'sections' => array() + ); + } + + // Add count to performances + $a[$scannedBy]['members'][$member]['performances'][$performance]['scans']++; + + // If Section has not been created + if (!isset($a[$scannedBy]['members'][$member]['performances'][$performance]['sections'][$section])) { + $a[$scannedBy]['members'][$member]['performances'][$performance]['sections'][$section] = array( + 'voucherCount' => 0, + 'scans' => 0, + 'tickets' => array() + ); + } + + // Add count to sections + $a[$scannedBy]['members'][$member]['performances'][$performance]['sections'][$section]['scans']++; + + // If Ticket has not been created + if (!isset($a[$scannedBy]['members'][$member]['performances'][$performance]['sections'][$section]['tickets'][$ticket])) { + $a[$scannedBy]['members'][$member]['performances'][$performance]['sections'][$section]['tickets'][$ticket] = array( + 'voucherCount' => 0, + 'scans' => 0, + 'dateSpecific' => $dateSpecific, + 'dateTimes' => array() + ); + } + + // Add count to tickets + $a[$scannedBy]['members'][$member]['performances'][$performance]['sections'][$section]['tickets'][$ticket]['scans']++; + + // If DateTime has not been created + if (!isset($a[$scannedBy]['members'][$member]['performances'][$performance]['sections'][$section]['tickets'][$ticket]['dateTimes'][$dateTime])) { + $a[$scannedBy]['members'][$member]['performances'][$performance]['sections'][$section]['tickets'][$ticket]['dateTimes'][$dateTime] = array( + 'voucherCount' => 0, + 'scans' => 0, + 'vouchers' => array() + ); + } + + // Add count to DateTimes + $a[$scannedBy]['members'][$member]['performances'][$performance]['sections'][$section]['tickets'][$ticket]['dateTimes'][$dateTime]['scans']++; + + // If Voucher has not been created + if (!isset($a[$scannedBy]['members'][$member]['performances'][$performance]['sections'][$section]['tickets'][$ticket]['dateTimes'][$dateTime]['vouchers'][$voucher])) { + + $a[$scannedBy]['members'][$member]['performances'][$performance]['sections'][$section]['tickets'][$ticket]['dateTimes'][$dateTime]['vouchers'][$voucher] = array( + 'scans' => 0, + 'voucherData' => array( + 'fname' => $s['fname'], + 'lname' => $s['lname'], + 'city' => $s['city'], + 'state' => $s['state'], + 'phone' => $s['phone'], + 'email' => $s['email'] + ) + ); + + // Add voucher counts to everything above + $totalVouchers++; + $a[$scannedBy]['voucherCount']++; + $a[$scannedBy]['members'][$member]['voucherCount']++; + $a[$scannedBy]['members'][$member]['performances'][$performance]['voucherCount']++; + $a[$scannedBy]['members'][$member]['performances'][$performance]['sections'][$section]['voucherCount']++; + $a[$scannedBy]['members'][$member]['performances'][$performance]['sections'][$section]['tickets'][$ticket]['voucherCount']++; + $a[$scannedBy]['members'][$member]['performances'][$performance]['sections'][$section]['tickets'][$ticket]['dateTimes'][$dateTime]['voucherCount']++; + + } + + // Add count to Vouchers + $a[$scannedBy]['members'][$member]['performances'][$performance]['sections'][$section]['tickets'][$ticket]['dateTimes'][$dateTime]['vouchers'][$voucher]['scans']++; + + } + +// echo "
    ".print_r($a,1)."
    Total Scans = $totalScans
    Total Vouchers = $totalVouchers"; + + $lines = array(); + + $lineBlank = array( + 'scannedBy' => '', + 'member' => '', + 'performance' => '', + 'section' => '', + 'ticket' => '', + 'dateTime' => '', + 'voucher' => '', + 'scans' => '', + 'fname' => '', + 'lname' => '', + 'city' => '', + 'state' => '', + 'phone' => '', + 'email' => '' + ); + + $detail = ($reportType == 'claimsDetail'); + + reset($a); + foreach ($a as $k=>$scannedBy) { + + $line = $lineBlank; + $line['scannedBy'] = $k; + $scannedByTitle = $k; + + if ($detail) { $lines[] = $line; } + + foreach ($scannedBy['members'] as $k=>$member) { + + $line = $lineBlank; + $line['member'] = $k; + $memberTitle = $k; + + if ($detail) { $lines[] = $line; } + + foreach ($member['performances'] as $k=>$performance) { + + $line = $lineBlank; + $line['performance'] = $k; + $performanceTitle = $k; + + if ($detail) { $lines[] = $line; } + + foreach ($performance['sections'] as $k=>$section) { + + $line = $lineBlank; + $line['section'] = $k; + $sectionTitle = $k; + + if ($detail) { $lines[] = $line; } + + foreach ($section['tickets'] as $k=>$ticket) { + + $line = $lineBlank; + $line['ticket'] = $k; + $ticketTitle = $k; + + if ($detail) { $lines[] = $line; } + + foreach ($ticket['dateTimes'] as $k=>$dateTime) { + + $line = $lineBlank; + $line['dateTime'] = $k; + $dateTimeTile = $k; + + if ($detail && $ticket['dateSpecific']) { + $lines[] = $line; + } + + foreach ($dateTime['vouchers'] as $k=>$voucher) { + + // Only output these lines if this is a detail report + if ($detail) { + + $line = $lineBlank; + + $v = $voucher['voucherData']; + + $line['dateTime'] = ''; + $line['voucher'] = $k; + $line['scans'] = $v['scans']; + $line['fname'] = $v['fname']; + $line['lname'] = $v['lname']; + $line['city'] = $v['city']; + $line['state'] = $v['state']; + $line['phone'] = $v['phone']; + $line['email'] = $v['email']; + + $line['scans'] = $voucher['scans']; + + $lines[] = $line; + + } + } + + if ($ticket['dateSpecific']) { + $line = $lineBlank; + if (!$detail) { + $line['scannedBy'] = $scannedByTitle; + $line['member'] = $memberTitle; + $line['performance'] = $performanceTitle; + $line['section'] = $sectionTitle; + $line['ticket'] = $ticketTitle; + } + $line['voucher'] = $dateTime['voucherCount']; + $line['scans'] = $dateTime['scans']; + $line['dateTime'] = $dateTimeTile.' Totals'; + $lines[] = $line; + } + + } + + $line = $lineBlank; + if (!$detail) { + $line['scannedBy'] = $scannedByTitle; + $line['member'] = $memberTitle; + $line['performance'] = $performanceTitle; + $line['section'] = $sectionTitle; + } + $line['voucher'] = $ticket['voucherCount']; + $line['scans'] = $ticket['scans']; + $line['ticket'] = $ticketTitle.' Totals'; + $lines[] = $line; + + } + + $line = $lineBlank; + if (!$detail) { + $line['scannedBy'] = $scannedByTitle; + $line['member'] = $memberTitle; + $line['performance'] = $performanceTitle; + } + $line['voucher'] = $section['voucherCount']; + $line['scans'] = $section['scans']; + $line['section'] = $sectionTitle.' Totals'; + $lines[] = $line; + + } + + $line = $lineBlank; + if (!$detail) { + $line['scannedBy'] = $scannedByTitle; + $line['member'] = $memberTitle; + } + $line['voucher'] = $performance['voucherCount']; + $line['scans'] = $performance['scans']; + $line['performance'] = $performanceTitle.' Totals'; + $lines[] = $line; + + } + + $line = $lineBlank; + if (!$detail) { + $line['scannedBy'] = $scannedByTitle; + } + $line['voucher'] = $member['voucherCount']; + $line['scans'] = $member['scans']; + $line['member'] = $memberTitle.' Totals'; + $lines[] = $line; + + } + + $line = $lineBlank; + $line['voucher'] = $scannedBy['voucherCount']; + $line['scans'] = $scannedBy['scans']; + $line['scannedBy'] = $scannedByTitle.' Totals'; + $lines[] = $line; + + } + +// echo "
    ".print_r($lines,1)."
    "; +// echo "Total Vouchers = $totalVouchers"; + + $this->page->reportData = $this->bindArrayToObject($lines); + $this->page->reportNote = $reportNote; + $this->page->reportDate = date('m/d/Y'); + $this->page->reportTime = date('h:m:s A'); + $this->page->dateFrom = $dateFrom; + $this->page->dateTo = $dateTo; + $this->page->totalVouchers = $totalVouchers; + $this->page->totalScans = $totalScans; + + $this->templateFile = $templateFile; + + // Check for output type + $this->page->printOutput = false; + switch ($_REQUEST['outputType']) { + case 'html': + break; + case 'print': + $this->page->printOutput = true; + break; + case 'csv': + $this->template->compile($this->interface.$templateFileCSV); + $csvOut = $this->template->bufferedOutputObject($this->page); + $len = strlen( $csvOut ); + header( "Content-type: application/octet-stream" ); + header( "Content-Length: $len" ); + header( "Content-Disposition: attachment; filename=report.csv" ); + echo $csvOut; + exit; + break; + } + + $this->addDebug("Report/sales.inc", 'Sales Report', 'Array: $a

    '.print_r($a,1)); + +} + + + +?> diff --git a/models/admin/actions/Report/customManifest.inc b/models/admin/actions/Report/customManifest.inc new file mode 100644 index 0000000..f10b2e4 --- /dev/null +++ b/models/admin/actions/Report/customManifest.inc @@ -0,0 +1,176 @@ + + * @release SVN: $Id: ticket.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +// Check for selected Venue +if ($_REQUEST['memberID'] > 0) { + $where .= ' AND S.member = '.$_REQUEST['memberID']; + $reportNote .= $reportSpacer.'Selected venue'; + $reportSpacer = ', '; +} + +// Check for selected Performance +if ($_REQUEST['performanceID'] > 0) { + $where .= ' AND S.performance = '.$_REQUEST['performanceID']; + $reportNote .= $reportSpacer.'Selected performance'; + $reportSpacer = ', '; +} + +// Check Date Range +$dateFrom = $_REQUEST['start_date']; +$dateTo = $_REQUEST['end_date']; +$dateRange = "between $dateFrom and $dateTo"; + +if ($dateTo == '') { + $dateTo = $dateFrom; + $dateRange = "on $dateFrom"; +} + +$dateFrom .= " 00:00:00"; +$dateTo .= " 23:59:59"; + +$where .= "\nAND S.ticket_date BETWEEN '$dateFrom' AND '$dateTo'"; +$reportNote .= $reportSpacer."Ticket dates $dateRange"; +$reportSpacer = ', '; + +/* + // Check for claimed only + if ($_REQUEST['claimed'] == 'on') { + $where .= " + AND ( + SELECT count(id) + FROM eventmgt.ticket_claim_tracking + WHERE ticket_sold = S.id + ) > 0 + "; + $reportNote .= $reportSpacer.'Claimed tickets only'; + $reportSpacer = ', '; + } +*/ + +$packageWhere = " AND (S.ticket_package IS NULL OR S.ticket_package < 1)"; + +// Gather Data +$sql = " + SELECT S.performance_name, + T.name AS ticket_name, + S.ticket_date, + S.ticket_time, + S.ticket_order, + S.id AS voucher, + R.lname, + R.fname, + R.phone, + R.notes + FROM eventmgt.ticket_sold S, + eventmgt.ticket T, + eventmgt.ticket_order R + WHERE T.id = S.ticket + AND R.id = S.ticket_order + $where + ORDER BY performance_name, ticket_name, ticket_date, ticket_time, ticket_order, voucher, lname, fname +;"; + +// echo "

    $sql
    "; + +$stmt = $this->dbh->prepare($sql); +$stmt->execute(); +$manifest = $stmt->fetchAll(PDO::FETCH_ASSOC); + +// echo "
    ".print_r($manifest,1)."
    "; + +if (count($manifest)-0 <= 0) { + echo "No Data Returned"; + exit; +} + +// Remove redundant field data +$perf_name = ''; +$ticket = ''; +$ticket_date = ''; +$ticket_time = ''; +$order = ''; +foreach ($manifest as $k=>$v) { + if ($v['performance_name'] != $perf_name) { + $perf_name = $v['performance_name']; + $ticket = $v['ticket_name']; + $ticket_date = $v['ticket_date']; + $ticket_time = $v['ticket_time']; + $order = $v['ticket_order']; + } else { + $manifest[$k]['performance_name'] = ''; + + if ($v['ticket_name'] != $ticket) { + $ticket = $v['ticket_name']; + $ticket_date = $v['ticket_date']; + $ticket_time = $v['ticket_time']; + $order = $v['ticket_order']; + } else { + $manifest[$k]['ticket_name'] = ''; + + if ($v['ticket_date'] != $ticket_date) { + $ticket_date = $v['ticket_date']; + $ticket_time = $v['ticket_time']; + $order = $v['ticket_order']; + } else { + $manifest[$k]['ticket_date'] = ''; + + if ($v['ticket_time'] != $ticket_time) { + $ticket_time = $v['ticket_time']; + $order = $v['ticket_order']; + } else { + $manifest[$k]['ticket_time'] = ''; + + if ($v['ticket_order'] != $order) { + $order = $v['ticket_order']; + } else { + $manifest[$k]['ticket_order'] = ''; + } + } + } + } + } + if ($_REQUEST['outputType'] != 'csv') { + $manifest[$k]['notes'] = nl2br(html_entity_decode($v['notes'])); + } +} + +$this->page->reportData = $this->bindArrayToObject($manifest); +$this->page->reportNote = $reportNote; +$this->page->reportDate = date('m/d/Y'); +$this->page->reportTime = date('h:m:s A'); +$this->page->dateFrom = $dateFrom; +$this->page->dateTo = $dateTo; + + $this->page->printOutput = false; + switch ($_REQUEST['outputType']) { + case 'html': + break; + case 'print': + $this->page->printOutput = true; + break; + case 'csv': + $this->template->compile($this->interface.'/Report/customManifestCSV.html'); + $csvOut = $this->template->bufferedOutputObject($this->page); + $len = strlen( $csvOut ); + header( "Content-type: application/octet-stream" ); + header( "Content-Length: $len" ); + header( "Content-Disposition: attachment; filename=report.csv" ); + echo $csvOut; + exit; + break; + } + + +$this->templateFile = 'Report/customManifest.html'; + + diff --git a/models/admin/actions/Report/index.inc b/models/admin/actions/Report/index.inc new file mode 100644 index 0000000..1100b0c --- /dev/null +++ b/models/admin/actions/Report/index.inc @@ -0,0 +1,18 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: report.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +$this->templateFile = 'Report/index.html'; + + +?> diff --git a/models/admin/actions/Report/member.inc b/models/admin/actions/Report/member.inc new file mode 100644 index 0000000..a6a07c6 --- /dev/null +++ b/models/admin/actions/Report/member.inc @@ -0,0 +1,176 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: member.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +$this->optionIncludeSelectListData = false; + +// If this is an initial entry, display report selection form +if (!isset($_REQUEST['memberReport'])) { + + // Get a list of members + require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/members.php'; + $Members = new EventManagementAdminMembers($this->dbh, $this->config); + $members = $Members->getMembersList('all'); + $this->page->membersList = $this->bindArrayToObject($members); + + // Setup min and max dates for date selection + $minDate = date('m/d/Y', strtotime(date('m/d/Y').' -5 years')); + $maxDate = date('m/d/Y', strtotime(date('m/d/Y').' +5 years')); + $this->page->minDate = $minDate; + $this->page->maxDate = $maxDate; + + $this->templateFile = 'Report/memberReportSelection.html'; + +// Otherwise we have a report request +} else { + + $reportNote = 'Report Selection: '; + $reportSpacer = ''; + + require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/members.php'; + $Members = new EventManagementAdminMembers($this->dbh, $this->config); + + // Check if inactive selected + if ($_REQUEST['inactive'] == 'on') { + $where = 'true'; + $reportNote .= $reportSpacer."Active and Inactive"; + $reportSpacer = ", "; + } else { + $where = 'active'; + $reportNote .= $reportSpacer."Active only"; + $reportSpacer = ", "; + } + + // Check for selected member/venue + if ($_REQUEST['memberID'] > 0 ) { + $where .= ' AND id = '.$_REQUEST['memberID']; + $reportNote .= $reportSpacer.'Specific Venues'; + $reportSpacer = ", "; + } + + // Create date range for ticket sales stats if specified + $dateWhere = ''; + switch ($_REQUEST['dateRange']) { + case 'thisMonth': + $start = date('m/1/Y', time()); + $end = date('m/d/Y', strtotime(date('m/1/Y', time()).' +1 month -1 day')); + $dateWhere = "AND I.ticket_date BETWEEN '$start' AND '$end'"; + $reportNote .= $reportSpacer."This month only"; + $reportSpacer = ", "; + break; + case 'lastMonth': + $start = date('m/1/Y', strtotime(date('m/1/Y', time()).' -1 month')); + $end = date('m/d/Y', strtotime(date('m/1/Y', time()).' -1 day')); + $dateWhere = "AND I.ticket_date BETWEEN '$start' AND '$end'"; + $reportNote .= $reportSpacer."Last month only"; + $reportSpacer = ", "; + break; + case 'thisYear': + $start = date('1/1/Y', time()); + $end = date('m/d/Y', strtotime(date('1/1/Y', time()).' +1 year -1 day')); + $dateWhere = "AND I.ticket_date BETWEEN '$start' AND '$end'"; + $reportNote .= $reportSpacer."This year only"; + $reportSpacer = ", "; + break; + case 'lastYear': + $start = date('1/1/Y', strtotime(date('1/1/Y', time()).' -1 year')); + $end = date('m/d/Y', strtotime(date('1/1/Y', time()).' -1 day')); + $dateWhere = "AND I.ticket_date BETWEEN '$start' AND '$end'"; + $reportNote .= $reportSpacer."Last year only"; + $reportSpacer = ", "; + break; + case 'specified': + if ($_REQUEST['start_date'] != '' && $_REQUEST['end_date'] != '') { + $dateWhere = " AND I.ticket_date BETWEEN '".$_REQUEST['start_date']."' AND '".$_REQUEST['end_date']."'"; + $reportNote .= $reportSpacer.'Between '.$_REQUEST['start_date'].' and '.$_REQUEST['end_date']; + $reportSpacer = ', '; + } + break; + case 'all': + default: + } + + $membersList = $Members->getList($where, 'name'); + + $totals = array( + 'sections' => 0, + 'events' => 0, + 'tickets' => 0, + 'inventory' => 0, + 'sold' => 0, + 'price' => 0 + ); + if (is_array($membersList) && count($membersList) > 0) { + + require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/sections.php'; + $Sections = new EventManagementAdminSections($this->dbh, $this->config); + require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/performances.php'; + $Performances = new EventManagementAdminPerformances($this->dbh, $this->config); + require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/tickets.php'; + $Tickets = new EventManagementAdminTickets($this->dbh, $this->config); + require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/ticketInventory.php'; + $Inventory = new EventManagementAdminTicketInventory($this->dbh, $this->config); + + // Get summary of member stats + reset($membersList); + while (list($k, $v) = each($membersList)) { + $membersList[$k]['sectionStats'] = $Sections->getMemberSectionsStats($v['id']); + $totals['sections'] += $membersList[$k]['sectionStats']; + $membersList[$k]['performanceStats'] = $Performances->getMemberPerformancesStats($v['id']); + $totals['events'] += $membersList[$k]['performanceStats']; + $membersList[$k]['ticketStats'] = $Tickets->getMemberTicketsStats($v['id']); + $totals['tickets'] += $membersList[$k]['ticketStats']; + $membersList[$k]['ticketSalesStats'] = $Inventory->getMemberTicketInventorySalesStats($v['id'], $dateWhere); + $totals['inventory'] += $membersList[$k]['ticketSalesStats']['totalquant']; + $totals['sold'] += $membersList[$k]['ticketSalesStats']['totalsold']; + $totals['price'] += $membersList[$k]['ticketSalesStats']['totalprice']; + $membersList[$k]['ticketSalesStats']['totalMoney'] = $this->money($membersList[$k]['ticketSalesStats']['totalprice']); + } + $totals['price'] = $this->money($totals['price']); + + } + + $this->page->membersList = $this->bindArrayToObject($membersList); + $this->page->totals = $this->bindArrayToObject($totals); + $this->page->reportNote = $reportNote; + $this->page->reportDate = date('m/d/Y'); + $this->page->reportTime = date('h:m:s A'); + + // Check for output type + $this->page->printOutput = false; + $this->templateFile = 'Report/member.html'; + switch ($_REQUEST['outputType']) { + case 'html': + break; + case 'print': + $this->page->printOutput = true; + break; + case 'csv': + $this->template->compile($this->interface.'/Report/memberCSV.html'); + $csvOut = $this->template->bufferedOutputObject($this->page); + $len = strlen( $csvOut ); + header( "Content-type: application/octet-stream" ); + header( "Content-Length: $len" ); + header( "Content-Disposition: attachment; filename=report.csv" ); + echo $csvOut; + exit; + break; + } + + $this->addDebug("Report/member.inc", 'Member List', print_r($membersList,1)); + +} + + + +?> diff --git a/models/admin/actions/Report/orders.inc b/models/admin/actions/Report/orders.inc new file mode 100644 index 0000000..109807b --- /dev/null +++ b/models/admin/actions/Report/orders.inc @@ -0,0 +1,280 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: orders.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +$this->optionIncludeSelectListData = false; +$this->page->users_access_all_members = $this->config->option->users_access_all_members; +$this->page->location_all_option = true; + +// If this is an initial entry, display report selection form +if (!isset($_REQUEST['ordersReport'])) { + + // Check if this is a log-in user to determine what access they have - Need at least "Ticket Orders & Claims" + $where = 'true'; + if ($_SESSION[GLM_EVENT_SESSION]['MemberUser'] && $_SESSION[GLM_EVENT_SESSION]['MemberUserLevel'] <= $this->config->permissions_numb->orders_and_claims) { + + // Setup where clause starting with the user member + $m = $_SESSION[GLM_EVENT_SESSION]['Member']; + $where = "id IN ($m"; + + // Get list of any members this user can scan for + require_once EVENT_MANAGEMENT_APP_BASE.'classes/data/dataMemberScansFor.php'; + $MemberScansFor = new EventManagementDataMemberScansFor($this->dbh, $this->config); + $scansFor = $MemberScansFor->getMemberScansForList($m); + + if ($scansFor && count($scansFor) > 0) { + foreach($scansFor as $s) { + $where .= ','.$s['scans_for']; + } + } + + $where .= ')'; + + $this->page->location_all_option = false; + + } + + // Get a list of members + require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/members.php'; + $Members = new EventManagementAdminMembers($this->dbh, $this->config); + $members = $Members->getMembersList('all', $where); + + $mList = array(); + if (is_array($members) && count($members) > 0) { + + // Get a list of performances + require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/performances.php'; + $Performances = new EventManagementAdminPerformances($this->dbh, $this->config); + // If access is permitted to all members by users in this site + if ($this->config->option->users_access_all_members) { + $performanceList = $Performances->getPerformancesList($type, false); + } else { + $performanceList = $Performances->getPerformancesList($type, $id); + } + + // Create simple list of members and their performances + reset($members); + while (list($k, $v) = each($members)) { + $mList[$v['id']] = array( + 'id' => $v['id'], + 'name' => $v['name'], + 'performance' => array() + ); + } + + } + + $this->page->mList = $this->bindArrayToObject($mList); + + // Setup min and max dates for date selection + $minDate = date('m/d/Y', strtotime(date('m/d/Y').' -5 years')); + $maxDate = date('m/d/Y', strtotime(date('m/d/Y').' +5 years')); + $this->page->minDate = $minDate; + $this->page->maxDate = $maxDate; + + $this->templateFile = 'Report/ordersReportSelection.html'; + + $this->addDebug("Report/ordersReportSelection.inc", 'Member & Property List', 'Array: $mList

    '.print_r($mList,1)); + +// Otherwise we have a report request +} else { + + $where = 'true'; + $reportNote = 'Report Selection: '; + $reportSpacer = ''; + + require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/orders.php'; + $Orders = new EventManagementAdminOrders($this->dbh, $this->config); + + // Check for selected Venue + if ($_REQUEST['memberID'] > 0) { + $where .= ' AND member = '.$_REQUEST['memberID']; + $reportNote .= $reportSpacer.'Selected venue'; + $reportSpacer = ', '; + } + + // Check for inactive venues + if ($_REQUEST['inactive'] != 'on') { + $where .= ' AND member in (SELECT id FROM eventmgt.member WHERE active)'; + $reportNote .= $reportSpacer.'Active venues only'; + $reportSpacer = ', '; + } else { + $reportNote .= $reportSpacer.'Including inactive venues'; + $reportSpacer = ', '; + } + + // Check Purchase Date Range + switch($_REQUEST['dateType']) { + case 'sold': + if ($_REQUEST['start_date'] != '' && $_REQUEST['end_date'] != '') { + $where .= " AND purchase_date BETWEEN '".$_REQUEST['start_date']."' AND '".$_REQUEST['end_date']."'"; + $reportNote .= $reportSpacer.'Sold between '.$_REQUEST['start_date'].' and '.$_REQUEST['end_date']; + $reportSpacer = ', '; + } elseif ($_REQUEST['start_date'] != '' && $_REQUEST['end_date'] == '') { + $where .= " AND purchase_date = '".$_REQUEST['start_date']."'"; + $reportNote .= $reportSpacer.'Sold on '.$_REQUEST['start_date']; + $reportSpacer = ', '; + } + break; + case 'all': + default: + break; + } + + // Check Ticket or Likely Date Range + switch($_REQUEST['ticketDateType']) { + +// select count(id) from ticket_sold where (date_specific and ticket_date > '1/1/2014') OR (not date_specific and likely_date > '1/1/2015'); + case 'ticketDate': + if ($_REQUEST['outputType'] == 'csv') { + $sDate = filter_input(INPUT_GET, 'ticket_start_date', FILTER_SANITIZE_STRING); + $eDate = filter_input(INPUT_GET, 'ticket_end_date', FILTER_SANITIZE_STRING); + } else { + $sDate = filter_input(INPUT_POST, 'ticket_start_date', FILTER_SANITIZE_STRING); + $eDate = filter_input(INPUT_POST, 'ticket_end_date', FILTER_SANITIZE_STRING); + } + + if (trim($eDate) == '') { + $eDate = $sDate; + } + if ($sDate != '') { + $where .= " AND ( + SELECT count(id) FROM eventmgt.ticket_sold WHERE ticket_order = T.id + AND ( + (date_specific AND ticket_date BETWEEN '$sDate' AND '$eDate') + OR (NOT date_specific AND likely_date BETWEEN '$sDate' AND '$eDate') + ) + ) > 0"; + $reportNote .= $reportSpacer.'Ticket Date or Likely Date between '.$sDate.' and '.$eDate; + $reportSpacer = ', '; + } + break; + case 'all': + default: + break; + } + + // Check if only doing E-Mail OK on + if ($_REQUEST['emailOK'] == 'on') { + $where .= ' AND email_ok'; + } + + // Check for other fields + $orderID = $_REQUEST['orderID'] - 0; + if ($orderID) { + $where .= " AND id = $orderID"; + } + $lname = filter_input(INPUT_POST, 'lname', FILTER_SANITIZE_STRING); + if ($lname != '') { + $where .= " AND lname ILIKE '$lname%'"; + } + $fname = filter_input(INPUT_POST, 'fname', FILTER_SANITIZE_STRING); + if ($fname != '') { + $where .= " AND fname ILIKE '$fname%'"; + } + $city = filter_input(INPUT_POST, 'city', FILTER_SANITIZE_STRING); + if ($city != '') { + $where .= " AND city ILIKE '$city%'"; + } + $state = filter_input(INPUT_POST, 'state', FILTER_SANITIZE_STRING); + if ($state != '') { + $where .= " AND state = '$state'"; + } + $zip = filter_input(INPUT_POST, 'zip', FILTER_SANITIZE_STRING); + if ($zip != '') { + $where .= " AND zip = '$zip'"; + } + $phone = filter_input(INPUT_POST, 'phone', FILTER_SANITIZE_STRING); + if ($phone != '') { + $where .= " AND phone ILIKE '$phone%'"; + } + + // Order By + $orderBy = ''; + switch($_REQUEST['sortType']) { + case 'id': + $orderBy = 'id'; + break; + case 'date': + $orderBy = 'purchase_date, lname, fname'; + break; + case 'name': + $orderBy = 'lname, fname'; + break; + case 'location': + $orderBy = 'country, state, city, lname, fname'; + break; + case 'venue_date': + $orderBy = 'member_name, purchase_date, lname, fname'; + break; + case 'venue_name': + $orderBy = 'member_name, lname, fname'; + break; + } + + // Get list of selected orders + $ordersList = $Orders->getList($where, $orderBy); + + // Build totals + if ($ordersList != false && count($ordersList) > 0) { + reset($ordersList); + $orders = 0; + $total = 0; + foreach ($ordersList as &$ord) { + $orders++; + $total += $ord['charge_numb']; + } + } + +//var_dump($ordersList);exit; + + $this->page->ordersList = $this->bindArrayToObject($ordersList); + $this->page->reportNote = $reportNote; + $this->page->reportDate = date('m/d/Y'); + $this->page->reportTime = date('h:m:s A'); + + $this->page->numbOrders = $orders; + $this->page->totalCharges = $total; + $this->page->averageOrder = $this->money(($orders > 0 ? $total/$orders : 0)); + $this->page->totalChargesMoney = $this->money($total); + + // Check for output type + $this->page->printOutput = false; + switch ($_REQUEST['outputType']) { + case 'html': + break; + case 'print': + $this->page->printOutput = true; + break; + case 'csv': + $this->template->compile($this->interface.'/Report/ordersCSV.html'); + $csvOut = $this->template->bufferedOutputObject($this->page); + $len = strlen( $csvOut ); + header( "Content-type: application/octet-stream" ); + header( "Content-Length: $len" ); + header( "Content-Disposition: attachment; filename=report.csv" ); + echo $csvOut; + exit; + break; + } + + $this->templateFile = 'Report/orders.html'; + + $this->addDebug("Report/orders.inc", 'Orders List', print_r($ordersList,1)); + + +} + + + +?> diff --git a/models/admin/actions/Report/promo.inc b/models/admin/actions/Report/promo.inc new file mode 100644 index 0000000..c1f7b20 --- /dev/null +++ b/models/admin/actions/Report/promo.inc @@ -0,0 +1,293 @@ + + * @release SVN: $Id: ticket.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +$this->optionIncludeSelectListData = false; +$errorMsg = ''; + +// If this is an initial entry, display report selection form +if (!isset($_REQUEST['promoReport'])) { + + // Get a list of Promo Codes + require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/promos.php'; + $Promos = new EventManagementAdminPromos($this->dbh, $this->config); + $promos = $Promos->getPromosList('all'); + $this->page->promos = $this->bindArrayToObject($promos); + + $this->templateFile = 'Report/promoReportSelection.html'; + + $this->addDebug("Report/promoReportSelection.inc", 'Promo Code Lists', 'Array: $mList

    '.print_r($promos,1)); + +// Otherwise we have a report request +} else { + + // Build selection + $where = ''; + $reportNote = ''; + $reportSpacer = ''; + $from = ''; + + // Check for selected Promo + if ($_REQUEST['promoID'] > 0) { + $where .= ' AND S.promo = '.$_REQUEST['promoID']; + $reportNote .= $reportSpacer.'Specified Promotion'; + $reportSpacer = ', '; + $selectionProblem = false; + } + + // Check Date Range + $dateFrom = $_REQUEST['start_date']; + $dateTo = $_REQUEST['end_date']; + $dateRange = "between $dateFrom and $dateTo"; + if ($dateTo == '') { + $dateTo = $dateFrom; + $dateRange = "on $dateFrom"; + } + switch($_REQUEST['dateType']) { + case 'sold': + if ($dateFrom != '' && $dateTo != '') { + $where .= "\nAND K.purchase_date BETWEEN '$dateFrom' AND '$dateTo'"; + $reportNote .= $reportSpacer."Sold $dateRange"; + $reportSpacer = ', '; + } + break; + case 'ticket': + if ($dateFrom != '' && $dateTo != '') { + $where .= "\nAND S.ticket_date BETWEEN '$dateFrom' AND '$dateTo'"; + $reportNote .= $reportSpacer."Ticket dates $dateRange"; + $reportSpacer = ', '; + } + break; + case 'claimed': + if ($dateFrom != '' && $dateTo != '') { + $where .= " + AND ( + SELECT count(id) + FROM eventmgt.ticket_claim_tracking + WHERE ticket_sold = S.id + AND time_of_action BETWEEN '$dateFrom' AND '$dateTo' + ) > 0 + "; + $reportNote .= $reportSpacer."Ticket dates $dateRange"; + $reportSpacer = ', '; + } + break; + case 'all': + default: + break; + } + + // Check for valid report type + $reportType = $_REQUEST['reportType']; + if ($reportType == 'detail' && $_REQUEST['promoID'] == 0) { + $errorMsg .= "Detail reports are only available when selecting a specific promo code.
    "; + } else { + + // Check report type - default to summary + $detailSelect = ''; + switch ($_REQUEST['reportType']) { + + case 'detail': + + // Get Data + $sql = "SELECT S.promo, COUNT(S.amount), SUM(S.amount), T.performance_name, T.ticket_name, + S.promo_name, S.amount, C.long_name, K.fname, K.lname, K.city, K.purchase_date + FROM eventmgt.promo_sold S, eventmgt.promo_code C, eventmgt.ticket_sold T, eventmgt.ticket_order K + WHERE T.id = S.ticket_sold + AND K.id = S.ticket_order + AND C.id = S.promo + $where + GROUP BY C.long_name, S.promo, S.amount, S.promo_name, T.performance_name, T.ticket_name, S.amount, + K.fname, K.lname, K.city, K.purchase_date + ORDER BY C.long_name, T.performance_name, T.ticket_name + ;"; + + $this->templateFile = 'Report/promoSummary.html'; + break; + + default: + case 'summary': + + // Get Data + $sql = "SELECT S.promo, COUNT(S.amount), SUM(S.amount), T.performance_name, T.ticket_name, + S.promo_name, S.amount, C.long_name + FROM eventmgt.promo_sold S, eventmgt.promo_code C, eventmgt.ticket_sold T + WHERE T.id = S.ticket_sold + AND C.id = S.promo + $where + GROUP BY C.long_name, S.promo, S.amount, S.promo_name, T.performance_name, T.ticket_name, S.amount + ORDER BY C.long_name, T.performance_name, T.ticket_name + ;"; + + $this->templateFile = 'Report/promoSummary.html'; + break; + } + + $stmt = $this->dbh->prepare($sql); + $stmt->execute(); + $promos = $stmt->fetchAll(PDO::FETCH_ASSOC); + + $totalEntries = 0; + $totalCount = 0; + $totalDiscount = 0; + $currentPromo = false; + $currentPerformance = false; + $currentItem = false; + + // Build totals and process fields + if ( is_array($promos) ) { + + while (list ($key, $val) = each ($promos)) { + + // Change all discount values to positive + $promos[$key]['amountMoney'] = number_format($val['amount']*-1,2); + $promos[$key]['sumMoney'] = number_format($val['sum']*-1,2); + + // Add this promo to the grand totals + $totalEntries++; + $totalCount += $promos[$key]['count']; + $totalDiscount += abs($promos[$key]['sum']); + + // If this is the same promo, don't display promo names again + if ($currentPromo == $val['promo_name']) { + $promos[$key]['promo_name'] = ''; + $promos[$key]['long_name'] = ''; + } else { + $currentPromo = $val['promo_name']; + $currentPerformance = false; + $currentItem = false; + } + + // If this is the same Performance + if ($currentPerformance == $val['performance_name']) { + $promos[$key]['performance_name'] = ''; + } else { + $currentPerformance = $val['performance_name']; + $currentItem = false; + } + + // If this is the same Item + if ($currentItem == $val['ticket_name']) { + $promos[$key]['ticket_name'] = ''; + } else { + $currentItem = $val['ticket_name']; + } + + } + + // Provide totals and detail to template + $this->page->totalEntries = $totalEntries; + $this->page->totalCount = $totalCount; + $this->page->totalDiscount = number_format($totalDiscount,2); + $this->page->havePromoList = true; + $this->page->promoList = $this->bindArrayToObject($promos); + + } + + + } // valid request + +// echo "

    ".print_r($promos,1)."
    "; + +/* + // Get data + $sql = " + SELECT S.id, S.member, S.member_name, S.performance, S.performance_name, S.section, S.section_name, + S.ticket_order, S.ticket, S.ticket_date, S.ticket_time, S.price_paid, S.time_claimed, + T.unlimited_quant, T.quant, T.name AS ticket_name, + M.active, + R.purchase_date, + $detailSelect + ( + SELECT sum(quant) + FROM eventmgt.ticket_claim_tracking + WHERE ticket_sold = S.id + ) as claimed + FROM eventmgt.ticket_sold S, eventmgt.ticket T, eventmgt.member M, eventmgt.ticket_order R + WHERE T.id = S.ticket + AND M.id = S.member + AND R.id = S.ticket_order + $where + ORDER BY member_name, performance_name, section_name, ticket_name + ;"; + $stmt = $this->dbh->prepare($sql); + $stmt->execute(); + $sales = $stmt->fetchAll(PDO::FETCH_ASSOC); +*/ + +/* + $this->page->salesList = $this->bindArrayToObject($out); + $this->page->totalQuant = $totalQuant; + $this->page->totalSold = $totalSold; + if ($totalQuant > 0) { + $this->page->percentSold = number_format(($totalSold/$totalQuant)*100,2); + } else { + $this->page->percentSold = '0'; + } + $this->page->totalClaimed = $totalClaimed; + if ($totalSold > 0) { + $this->page->percentClaimed = number_format(($totalClaimed/$totalSold)*100,2); + } else { + $this->page->percentClaimed = '0'; + } + $this->page->totalPromos = $totalPromos; + $this->page->totalPromosMoney = $this->money($totalPromos); + $this->page->totalPrice = $totalPrice; + $this->page->totalMoney = $this->money($totalPrice); +*/ + + if ($reportNote != '') { + $reportNote = 'Report Selection: '.$reportNote; + } else { + $reportNote = false; + } + $this->page->reportNote = $reportNote; + $this->page->reportDate = date('m/d/Y'); + $this->page->reportTime = date('h:m:s A'); + + // Get Output type + $outputType = $_REQUEST['outputType']; + + $this->page->errorMsg = $errorMsg; + if ($errorMsg != '') { + $outputType = 'error'; + } + + // Check for output type + $this->page->printOutput = false; + switch ($outputType) { + case 'error'; + $this->templateFile = 'Report/error.html'; + case 'html': + break; + case 'print': + $this->page->printOutput = true; + break; + case 'csv': + $this->template->compile($this->interface.$templateFileCSV); + $csvOut = $this->template->bufferedOutputObject($this->page); + $len = strlen( $csvOut ); + header( "Content-type: application/octet-stream" ); + header( "Content-Length: $len" ); + header( "Content-Disposition: attachment; filename=report.csv" ); + echo $csvOut; + exit; + break; + } + + $this->addDebug("Report/sales.inc", 'Sales Report', 'Array: $a

    '.print_r($a,1)); + +} + + + +?> diff --git a/models/admin/actions/Report/sales.inc b/models/admin/actions/Report/sales.inc new file mode 100644 index 0000000..26244c1 --- /dev/null +++ b/models/admin/actions/Report/sales.inc @@ -0,0 +1,791 @@ + + * @release SVN: $Id: ticket.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +$this->optionIncludeSelectListData = false; + +// If this is an initial entry, display report selection form +if (!isset($_REQUEST['salesReport'])) { + + // Get a list of members + require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/members.php'; + $Members = new EventManagementAdminMembers($this->dbh, $this->config); + $members = $Members->getMembersList('all'); + + $mList = array(); + + if (is_array($members) && count($members) > 0) { + + // Get a list of performances + require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/performances.php'; + $Performances = new EventManagementAdminPerformances($this->dbh, $this->config); + $performanceList = $Performances->getPerformancesList($type, $id, true); + + // Create simple list of members and their performances + reset($members); + while (list($k, $v) = each($members)) { + $mList[$v['id']] = array( + 'id' => $v['id'], + 'name' => $v['name'], + 'performance' => array() + ); + } + + reset($performanceList); + while (list($k, $v) = each($performanceList)) { + $mList[$v['member_id']]['performance'][$v['id']] = array( + 'id' => $v['id'], + 'name' => $v['name'], + 'active' => $v['active']['value'] + ); + } + + } + + $this->page->mList = $this->bindArrayToObject($mList); + + // Setup min and max dates for date selection + $minDate = date('m/d/Y', strtotime(date('m/d/Y').' -5 years')); + $maxDate = date('m/d/Y', strtotime(date('m/d/Y').' +5 years')); + $this->page->minDate = $minDate; + $this->page->maxDate = $maxDate; + + $this->templateFile = 'Report/salesReportSelection.html'; + + $this->addDebug("Report/salesReportSelection.inc", 'Member & Property List', 'Array: $mList

    '.print_r($mList,1)); + +// Otherwise we have a report request +} else { + + // Build selection + $where = ''; + $reportNote = 'Report Selection: '; + $reportSpacer = ''; + + // Check report type - default to summary + $detailSelect = ''; + switch ($_REQUEST['reportType']) { + case 'detail': + $reportType = 'detail'; + $detailSelect = 'R.id AS order_id, R.fname, R.lname, R.addr1, R.addr2, R.city, R.state, R.zip, R.country, R.email, R.phone,'; + $templateFile = 'Report/salesDetail.html'; + $templateFileCSV = '/Report/salesDetailCSV.html'; + break; + case 'packageTicket': + $reportType = 'summary'; + $reportOption = 'packageTickets'; + $templateFile = 'Report/salesPackageTickets.html'; + $templateFileCSV = '/Report/salesPackageTicketsCSV.html'; + break; + default: + case 'summary': + $reportType = 'summary'; + $templateFile = 'Report/sales.html'; + $templateFileCSV = '/Report/salesCSV.html'; + break; + } + + // Check for selected Venue + if ($_REQUEST['memberID'] > 0) { + $where .= ' AND S.member = '.$_REQUEST['memberID']; + $reportNote .= $reportSpacer.'Selected venue'; + $reportSpacer = ', '; + } + + // Check for selected Performance + if (isset($_REQUEST['performanceID']) && count($_REQUEST['performanceID']) > 0) { + + $pIds = ''; + $sep = ''; + foreach($_REQUEST['performanceID'] as $p) { + $pIds .= $sep.$p; + $sep = ', '; + } + $where .= ' AND S.performance in ('.$pIds.')'; + $reportNote .= $reportSpacer.'Selected performance'; + $reportSpacer = ', '; + } + + // Check for inactive venues + if ($_REQUEST['inactive'] != 'on') { + $where .= ' AND M.active = true'; + $reportNote .= $reportSpacer.'Active venues only'; + $reportSpacer = ', '; + } else { + $reportNote .= $reportSpacer.'Including inactive venues'; + $reportSpacer = ', '; + } + + // Check Date Range + $dateFrom = $_REQUEST['start_date']; + $dateTo = $_REQUEST['end_date']; + $dateRange = "between $dateFrom and $dateTo"; + if ($dateTo == '') { + $dateTo = $dateFrom; + $dateRange = "on $dateFrom"; + } + switch($_REQUEST['dateType']) { + case 'sold': + if ($dateFrom != '' && $dateTo != '') { + $where .= "\nAND R.purchase_date BETWEEN '$dateFrom' AND '$dateTo'"; + $reportNote .= $reportSpacer."Sold $dateRange"; + $reportSpacer = ', '; + } + break; + case 'ticket': + if ($dateFrom != '' && $dateTo != '') { + $where .= "\nAND S.ticket_date BETWEEN '$dateFrom' AND '$dateTo'"; + $reportNote .= $reportSpacer."Ticket dates $dateRange"; + $reportSpacer = ', '; + } + break; + case 'claimed': + if ($dateFrom != '' && $dateTo != '') { + $where .= " + AND ( + SELECT count(id) + FROM eventmgt.ticket_claim_tracking + WHERE ticket_sold = S.id + AND time_of_action BETWEEN '$dateFrom' AND '$dateTo' + ) > 0 + "; + $reportNote .= $reportSpacer."Ticket dates $dateRange"; + $reportSpacer = ', '; + } + break; + case 'all': + default: + break; + } + + // Check for claimed only + if ($_REQUEST['claimed'] == 'on') { + $where .= " + AND ( + SELECT count(id) + FROM eventmgt.ticket_claim_tracking + WHERE ticket_sold = S.id + ) > 0 + "; + $reportNote .= $reportSpacer.'Claimed tickets only'; + $reportSpacer = ', '; + } + + // Check for claim detail + $inclClaimDetail = false; + if ($_REQUEST['claimedDetail'] == 'on') { + $inclClaimDetail = true; + } + + // Check for whether we should report only on package tickets + $packageWhere = " AND (S.ticket_package IS NULL OR S.ticket_package < 1)"; + $priceSelect = " S.price_paid"; + if ($reportOption == "packageTickets") { + $packageWhere = " AND S.ticket_package > 0"; + $priceSelect = " (SELECT price FROM eventmgt.ticket WHERE id = S.ticket) AS price_paid"; + $reportNote .= $reportSpacer.'Package Tickets Only'; + } + + + // Fix Promo_Sold amount data ******************* REMOVE ONCE STORING OF PROMO_SOLD AMOUNT IS FIXED ***************************** +/* + $sql = " + UPDATE eventmgt.promo_sold + SET amount = eventmgt.promo_ticket.amount * -1 + FROM eventmgt.promo_ticket, eventmgt.ticket_sold + WHERE eventmgt.ticket_sold.id = eventmgt.promo_sold.ticket_sold + AND eventmgt.promo_ticket.ticket = eventmgt.ticket_sold.ticket + AND eventmgt.promo_ticket.promo = eventmgt.promo_sold.promo + ;"; + $stmt = $this->dbh->prepare($sql); + $stmt->execute(); +*/ + + // Get data - Note that tickets sold as part of a package have a ticket_package ID but don't have $s sold values. These are excluded from the results. + $sql = " + SELECT S.id, S.member, S.member_name, S.performance, S.performance_name, S.section, S.section_name, + S.ticket_order, S.ticket, S.ticket_date, S.ticket_time, $priceSelect, S.time_claimed, + T.unlimited_quant, T.quant, T.name AS ticket_name, I.quant AS inv_quant, + M.active, + R.purchase_date, + $detailSelect + ( + SELECT sum(quant) + FROM eventmgt.ticket_claim_tracking + WHERE ticket_sold = S.id + ) as claimed + FROM eventmgt.ticket_sold S, eventmgt.ticket T, eventmgt.member M, eventmgt.ticket_order R, eventmgt.ticket_inventory I + WHERE T.id = S.ticket + AND M.id = S.member + AND R.id = S.ticket_order + $packageWhere + $where + AND T.id = I.ticket + AND ( + NOT S.date_specific + OR + (S.ticket_date = I.ticket_date AND S.ticket_time = I.ticket_time) + ) + ORDER BY member_name, performance_name, section_name, ticket_name + ;"; +//echo "

    ".print_r($sql,1)."
    "; + + $stmt = $this->dbh->prepare($sql); + $stmt->execute(); + $sales = $stmt->fetchAll(PDO::FETCH_ASSOC); + + // Compile output array and totals + $totalQuant = 0; + $totalSold = 0; + $totalClaimed = 0; + $totalPromos = 0; + $totalPrice = 0; + $a = array(); + + // Array used for quantity control + $ticDate = array(); + + // Values to check if we're still on the same entity + $membLast = false; + $perfLast = false; + $sectLast = false; + $tickLast = false; + $dateLast = false; + + // Scan results and build interim report array + reset($sales); + + foreach ($sales as &$s) { + + // Need to determine if we're doing blank rather than number for unlimited quant + $q = ''; + if (!$s['unlimited_quant']) { + $q = 0; + } + + // If member hasn't been created + if (!isset($a[$s['member']])) { + $a[$s['member']] = array( + 'id' => $s['member'], + 'name' => $s['member_name'], + 'quant' => $q, + 'sold' => 0, + 'claimed' => 0, + 'price' => 0, + 'money' => 0, + 'performance' => array() + ); + } + $memb = &$a[$s['member']]; + + // If performance hasn't been created + if (!isset($memb['performance'][$s['performance']])) { + $memb['performance'][$s['performance']] = array( + 'id' => $s['performance'], + 'name' => $s['performance_name'], + 'quant' => $q, + 'sold' => 0, + 'claimed' => 0, + 'price' => 0, + 'money' => 0, + 'section' => array() + ); + } + $perf = &$memb['performance'][$s['performance']]; + + // If section hasn't been created + if (!isset($perf['section'][$s['section']])) { + $perf['section'][$s['section']] = array( + 'id' => $s['section'], + 'name' => $s['section_name'], + 'quant' => $q, + 'sold' => 0, + 'claimed' => 0, + 'price' => 0, + 'money' => 0, + 'ticket' => array() + ); + } + $sect = &$perf['section'][$s['section']]; + + // If ticket hasn't been created + if (!isset($sect['ticket'][$s['ticket']])) { + $sect['ticket'][$s['ticket']] = array( + 'id' => $s['ticket'], + 'name' => $s['ticket_name'], + 'quant' => $q, + 'sold' => 0, + 'claimed' => 0, + 'price' => 0, + 'money' => 0, + 'add_on' => array(), + 'date' => array() + ); + } + $tick = &$sect['ticket'][$s['ticket']]; + + // If date hasn't been created + if (!isset($tick['date'][$s['ticket_date']])) { + $tick['date'][$s['ticket_date']] = array( + 'date' => $s['ticket_date'], + 'quant' => $q, + 'sold' => 0, + 'claimed' => 0, + 'price' => 0, + 'money' => 0, + 'time' => array() + ); + } + $date = &$tick['date'][$s['ticket_date']]; + + // If time hasn't been created + if (!isset($date['time'][$s['ticket_time']])) { + + if ($s['ticket_time'] == '12:00:00') { + $timeString = ''; + } else { + $t = explode(':', $s['ticket_time']); + $ampm = 'AM'; + $hour = ($t[0] - 0); + if ($hour > 11) { + $ampm = 'PM'; + } else { + } + if ($hour > 12) { + $hour -= 12; + } + $timeString = sprintf('%2d:%02d %s', $hour, $min, $ampm); + } + + $date['time'][$s['ticket_time']] = array( + 'time' => $timeString, + 'quant' => $q, + 'sold' => 0, + 'claimed' => 0, + 'promo' => 0, + 'promo_money' => 0, + 'price' => 0, + 'money' => 0, + 'detail' => array() + ); + + } + $time = &$date['time'][$s['ticket_time']]; + + // Check for Add-ons for this tickets + $sql = " + SELECT add_on_name, add_on_type, add_on_type_name, unit_price, quant, price_paid + FROM eventmgt.add_on_sold + WHERE ticket_sold = ".$s['id']." + ORDER BY add_on_name + ;"; + $stmt = $this->dbh->prepare($sql); + $stmt->execute(); + $addOns = $stmt->fetchAll(PDO::FETCH_ASSOC); + if (count($addOns) > 0) { + foreach ($addOns as $addOn) { + + // *** NEED TO MOVE THIS TO USING Add-On ID rather than name when that's added to the record. + if (!isset($tick['add_on'][$addOn['add_on_name']])) { + $tick['add_on'][$addOn['add_on_name']] = array( + 'name' => $addOn['add_on_name'], + 'type' => $addOn['add_on_type'], + 'quant' => $addOn['quant'], + 'price' => $addOn['price_paid'], + 'money' => $this->money($addOn['price_paid']) + ); + } else { + $tick['add_on'][$addOn['add_on_name']]['quant'] += $addOn['quant']; + $tick['add_on'][$addOn['add_on_name']]['price'] += $addOn['price_paid']; + $tick['add_on'][$addOn['add_on_name']]['money'] = $this->money($tick['add_on'][$addOn['add_on_name']]['price']); + } + + // Add to total price + $totalPrice += $addOn['price_paid']; + + } + } + + // Check for any promotion + $sql = " + SELECT amount + FROM eventmgt.promo_sold + WHERE ticket_sold = ".$s['id']." + ;"; + $stmt = $this->dbh->prepare($sql); + $stmt->execute(); + $promos = $stmt->fetchAll(PDO::FETCH_ASSOC); + $promoAmount = 0; + if (count($promos) > 0) { + foreach ($promos as $promo) { + $promoAmount += $promo['amount']; + } + } + + // Determine if unlimited quantity available and don't display quant if so. + if (!$s['unlimited_quant']) { + + // Only add to quantity if this date for this ticket hasn't been added yet + $ticDateTime = $s['ticket'].'-'.$s['ticket_date'].'-'.$s['ticket_time']; + if (!isset( $ticDate[$ticDateTime])) { + + // Mark that we've already added quants for this date and time + $ticDate[$ticDateTime] = true; + + // Check config for whether we should use quantity from the item or inventory for the reports + if ($this->config->option->reports->quant_from_inventory) { + $q = $s['inv_quant']; + } else { + $q = $s['quant']; + } + + // Add quantities for this date and time only for this occurrance + $memb['quant'] += $q; + $perf['quant'] += $q; + $sect['quant'] += $q; + $tick['quant'] += $q; + $date['quant'] += $q; + $time['quant'] += $q; + $totalQuant += $q; + + } + + } + + // Add this ticket sold + $memb['sold']++; + $perf['sold']++; + $perf['price'] += $s['price_paid']; + $sect['sold']++; + $sect['price'] += $s['price_paid']; + $tick['sold']++; + $tick['price'] += $s['price_paid']; + $date['sold']++; + $date['price'] += $s['price_paid']; + $time['sold']++; + $time['price'] += $s['price_paid'] + $promoAmount; + $time['promo'] += $promoAmount; + $totalSold++; + $totalPromos += $promoAmount; + $totalPrice += $s['price_paid'] + $promoAmount; + + if ($s['claimed'] != '') { + $memb['memb_claimed'] += $s['claimed']; + $perf['perf_claimed'] += $s['claimed']; + $sect['sect_claimed'] += $s['claimed']; + $tick['tick_claimed'] += $s['claimed']; + $date['date_claimed'] += $s['claimed']; + $time['time_claimed'] += $s['claimed']; + $totalClaimed++; + } + + // Check if we're doing a detail report + if ($reportType == 'detail') { + + // If Claimed Detail is requested + $claimDetail = ''; + if ($inclClaimDetail) { + + // Look for claims for this voucher + $sql = " + SELECT time_of_action, scan_name + FROM eventmgt.ticket_claim_tracking + WHERE ticket_sold = ".$s['id']." + ;"; + $stmt = $this->dbh->prepare($sql); + $stmt->execute(); + $scans = $stmt->fetchAll(PDO::FETCH_ASSOC); + + // If there's any, list them + if (count($scans) > 0) { + + $sep = ''; + + // Only do a max of 3 + $maxScCount = 3; + $scCount = 0; + foreach ($scans as $sc) { + $claimDetail .= $sep.$sc['scan_name']; + $sep = ':'; + if (++$scCount >= $maxScCount) { + $claimDetail .= "$sep ..."; + break; + } + } + } + + } + + $time['detail'][] = array( + 'order_id' => $s['order_id'], + 'voucher_id' => $s['id'], + 'voucher_claims' => $claimDetail, + 'fname' => $s['fname'], + 'lname' => $s['lname'], + 'addr1' => $s['addr1'], + 'addr2' => $s['addr2'], + 'city' => $s['city'], + 'state' => $s['state'], + 'zip' => $s['zip'], + 'country' => $s['country'], + 'email' => $s['email'], + 'phone' => $s['phone'] + ); + + } + + } + + // Convert report array to individual lines + $out = array(); + reset($a); + foreach ($a as &$m) { + $line = array( + 'memb_id' => $m['id'], + 'memb_name' => $m['name'], + 'memb_quant' => $m['quant'], + 'memb_sold' => $m['sold'], + 'memb_claimed' => $m['memb_claimed'], + 'memb_price' => $m['price'], + 'memb_money' => $this->money($m['price']) + ); + foreach ($m['performance'] as &$p ) { + $line = array_merge($line, array( + 'perf_id' => $p['id'], + 'perf_name' => $p['name'], + 'perf_quant' => $p['quant'], + 'perf_sold' => $p['sold'], + 'perf_claimed' => $p['perf_claimed'], + 'perf_price' => $p['price'], + 'perf_money' => $this->money($p['price']) + )); + foreach ($p['section'] as &$s) { + $line = array_merge($line, array( + 'sect_id' => $s['id'], + 'sect_name' => $s['name'], + 'sect_quant' => $s['quant'], + 'sect_sold' => $s['sold'], + 'sect_claimed' => $s['sect_claimed'], + 'sect_price' => $s['price'], + 'sect_money' => $this->money($s['price']) + )); + foreach ($s['ticket'] as &$t) { + $line = array_merge($line, array( + 'tick_id' => $t['id'], + 'tick_name' => $t['name'], + 'tick_quant' => $t['quant'], + 'tick_sold' => $t['sold'], + 'tick_claimed' => $t['tick_claimed'], + 'tick_price' => $t['price'], + 'tick_money' => $this->money($t['price']) + )); + + // Sort dates + usort($t['date'], function($a, $b) { + return strcmp(strtotime($a['date']), strtotime($b['date'])); + }); + + foreach ($t['date'] as &$d) { + $line = array_merge($line, array( + 'date_date' => $d['date'], + 'date_quant' => $d['quant'], + 'date_sold' => $d['sold'], + 'date_claimed' => $d['date_claimed'], + 'date_price' => $d['price'], + 'date_money' => $this->money($d['price']) + )); + + // Sort times + usort($d['time'], function($a, $b) { + return strcmp($a['time'], $b['time']); + }); + + foreach ($d['time'] as &$i) { + $line = array_merge($line, array( + 'time_time' => $i['time'], + 'time_quant' => $i['quant'], + 'time_sold' => $i['sold'], + 'time_claimed' => $i['time_claimed'], + 'time_price' => $i['price'], + 'time_money' => ($i['price']!=0 ? $this->money($i['price']) : ''), + 'time_promo' => $i['promo'], + 'time_promo_money' => ($i['promo']!=0 ? $this->money($i['promo']) : '') + )); + + $out[] = $line; + + + // Initialize line data + $line = array( + 'memb_id' => '', + 'memb_name' => '', + 'memb_quant' => '', + 'memb_sold' => '', + 'memb_claimed' => '', + 'memb_price' => '', + 'memb_money' => '', + 'perf_id' => '', + 'perf_name' => '', + 'perf_quant' => '', + 'perf_sold' => '', + 'perf_claimed' => '', + 'perf_price' => '', + 'perf_money' => '', + 'sect_id' => '', + 'sect_name' => '', + 'sect_quant' => '', + 'sect_sold' => '', + 'sect_claimed' => '', + 'sect_price' => '', + 'sect_money' => '', + 'tick_id' => '', + 'tick_name' => '', + 'tick_quant' => '', + 'tick_sold' => '', + 'tick_claimed' => '', + 'tick_price' => '', + 'tick_money' => '', + 'addon_name' => '', + 'addon_quant' => '', + 'addon_sold' => '', + 'addon_claimed' => '', + 'addon_price' => '', + 'addon_money' => '', + 'date_id' => '', + 'date_name' => '', + 'date_quant' => '', + 'date_sold' => '', + 'date_claimed' => '', + 'date_price' => '', + 'date_money' => '', + 'order_id' => '', + 'order_fname' => '', + 'order_lname' => '', + 'order_addr1' => '', + 'order_addr2' => '', + 'order_city' => '', + 'order_state' => '', + 'order_zip' => '', + 'order_country' => '', + 'order_email' => '', + 'order_phone' => '' + ); + + + // If Detail report then output individual ticket customer data + if ($reportType == 'detail') { + + $orderID = ''; + foreach ($i['detail'] as $detail) { + + // Don't replicate order ID if it's the same for multiple lines +/* for now replicate the order IDs + if ($orderID == $detail['order_id']) { + $detail['order_id'] = ''; + } else { +*/ + $orderID = $detail['order_id']; +// } + + $out[] = array_merge($line, array( + 'order_id' => $detail['order_id'], + 'order_voucher_id' => $detail['voucher_id'], + 'order_claims' => $detail['voucher_claims'], + 'order_fname' => $detail['fname'], + 'order_lname' => $detail['lname'], + 'order_addr1' => $detail['addr1'], + 'order_addr2' => $detail['addr2'], + 'order_city' => $detail['city'], + 'order_state' => $detail['state'], + 'order_zip' => $detail['zip'], + 'order_country' => $detail['country'], + 'order_email' => $detail['email'], + 'order_phone' => $detail['phone'] + )); + + } + + } + + } + } + + foreach ($t['add_on'] as $addOn) { + $line = array( + 'addon_id' => 0, // Not using yet + 'addon_name' => $addOn['name'], + 'addon_sold' => $addOn['quant'], + 'time_claimed' => '', + 'time_price' => $addOn['price'], + 'time_money' => $addOn['money'] + ); + $out[] = $line; + } + + + } + } + } + } + + $this->page->salesList = $this->bindArrayToObject($out); + $this->page->totalQuant = $totalQuant; + $this->page->totalSold = $totalSold; + if ($totalQuant > 0) { + $this->page->percentSold = number_format(($totalSold/$totalQuant)*100,2); + } else { + $this->page->percentSold = '0'; + } + $this->page->totalClaimed = $totalClaimed; + if ($totalSold > 0) { + $this->page->percentClaimed = number_format(($totalClaimed/$totalSold)*100,2); + } else { + $this->page->percentClaimed = '0'; + } + $this->page->totalPromos = $totalPromos; + $this->page->totalPromosMoney = $this->money($totalPromos); + $this->page->totalPrice = $totalPrice; + $this->page->totalMoney = $this->money($totalPrice); + $this->page->reportNote = $reportNote; + $this->page->reportDate = date('m/d/Y'); + $this->page->reportTime = date('h:m:s A'); + $this->page->inclClaimDetail = $inclClaimDetail; + + $this->templateFile = $templateFile; + + // Check for output type + $this->page->printOutput = false; + switch ($_REQUEST['outputType']) { + case 'html': + break; + case 'print': + $this->page->printOutput = true; + break; + case 'csv': + $this->template->compile($this->interface.$templateFileCSV); + $csvOut = $this->template->bufferedOutputObject($this->page); + $len = strlen( $csvOut ); + header( "Content-type: application/octet-stream" ); + header( "Content-Length: $len" ); + header( "Content-Disposition: attachment; filename=report.csv" ); + echo $csvOut; + exit; + break; + } + + $this->addDebug("Report/sales.inc", 'Sales Report', 'Array: $a

    '.print_r($a,1)); + +} + + + +?> diff --git a/models/admin/actions/Reservation/detail.inc b/models/admin/actions/Reservation/detail.inc new file mode 100644 index 0000000..51244c5 --- /dev/null +++ b/models/admin/actions/Reservation/detail.inc @@ -0,0 +1,24 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: event.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/reservations.php'; +$Reservations = new EventManagementAdminReservations($this->dbh, $this->config); + + +$resDetail = $Reservations->getReservationDetail(); + +$this->page->resDetail = $this->bindArrayToObject($resDetail); +$this->templateFile = 'Reservation/ReservationDetail.html'; + +?> \ No newline at end of file diff --git a/models/admin/actions/Reservation/edit.inc b/models/admin/actions/Reservation/edit.inc new file mode 100644 index 0000000..2f4f6e0 --- /dev/null +++ b/models/admin/actions/Reservation/edit.inc @@ -0,0 +1,20 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: event.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/reservations.php'; +$Reservations = new EventManagementAdminReservations($this->dbh, $this->config); + +// Nothing here yet + +?> \ No newline at end of file diff --git a/models/admin/actions/Reservation/list.inc b/models/admin/actions/Reservation/list.inc new file mode 100644 index 0000000..e8884a7 --- /dev/null +++ b/models/admin/actions/Reservation/list.inc @@ -0,0 +1,53 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: event.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/reservations.php'; +$Reservations = new EventManagementAdminReservations($this->dbh, $this->config); + + +// Get reservations stats +$resStats = $Reservations->getReservationsStats(); +$this->page->resStats = $this->bindArrayToObject($resStats); + +// Use a more limited list of fields for this, not enough memory for large list. +$fields = array( + $Reservations->fields['id'], + $Reservations->fields['fname'], + $Reservations->fields['lname'], + $Reservations->fields['org'], + $Reservations->fields['conv'], + $Reservations->fields['event'], + $Reservations->fields['team'], + $Reservations->fields['state_rep'], + $Reservations->fields['state_rep_code'], + $Reservations->fields['member'], + $Reservations->fields['member_id'], + $Reservations->fields['city'], + $Reservations->fields['state'], + $Reservations->fields['country'], + $Reservations->fields['date_entered'], + $Reservations->fields['rooms'], + $Reservations->fields['grand_total'], + $Reservations->fields['confirmed'], + $Reservations->fields['declined'] +); +$Reservations->fields = $fields; + +// Get reserations list +$res = $Reservations->getReservationsList(); +$this->page->resList = $this->bindArrayToObject($res); + +$this->templateFile = 'Reservation/ReservationsList.html'; + +?> \ No newline at end of file diff --git a/models/admin/actions/Reservation/update.inc b/models/admin/actions/Reservation/update.inc new file mode 100644 index 0000000..0318836 --- /dev/null +++ b/models/admin/actions/Reservation/update.inc @@ -0,0 +1,20 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: event.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/reservations.php'; +$Reservations = new EventManagementAdminReservations($this->dbh, $this->config); + +// Nothing here yet + +?> \ No newline at end of file diff --git a/models/admin/actions/Section/add.inc b/models/admin/actions/Section/add.inc new file mode 100644 index 0000000..f5c4282 --- /dev/null +++ b/models/admin/actions/Section/add.inc @@ -0,0 +1,31 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: add.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/sections.php'; +$Sections = new EventManagementAdminSections($this->dbh, $this->config); + +// Get base data and fields +$r = $Sections->newSection(); + +$this->page->sectionDetail = $this->bindArrayToObject($r['fieldData']); +$this->page->fieldRequired = $this->bindArrayToObject($r['fieldRequired']); +$this->page->fieldFail = $this->bindArrayToObject($r['fieldFail']); +$this->page->addingNewSection = true; + +$this->templateFile = 'Section/edit.html'; + +$this->addDebug("Section/add.inc", 'Section Add', print_r($r,1)); + +?> + diff --git a/models/admin/actions/Section/confirmDelete.inc b/models/admin/actions/Section/confirmDelete.inc new file mode 100644 index 0000000..a3db0e2 --- /dev/null +++ b/models/admin/actions/Section/confirmDelete.inc @@ -0,0 +1,26 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: event.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/sections.php'; +$Sections = new EventManagementAdminSections($this->dbh, $this->config); + +$sectionDetail = $Sections->sectionDelete(true); +$this->page->sectionDetail = $this->bindArrayToObject($sectionDetail); + +$this->templateFile = 'Section/detail.html'; + +$this->addDebug("Section/confirmDelete.inc", 'Section Confirm Delete', print_r($sectionDetail,1)); + +?> + diff --git a/models/admin/actions/Section/delete.inc b/models/admin/actions/Section/delete.inc new file mode 100644 index 0000000..6db2a67 --- /dev/null +++ b/models/admin/actions/Section/delete.inc @@ -0,0 +1,27 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: section.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/sections.php'; +$Sections = new EventManagementAdminSections($this->dbh, $this->config); + + +$sectionDetail = $Sections->sectionDelete(false); +$this->page->sectionDetail = $this->bindArrayToObject($sectionDetail); + +$this->templateFile = 'Section/delete.html'; + +$this->addDebug("Section/delete.inc", 'Section Delete', print_r($sectionDetail,1)); + +?> + diff --git a/models/admin/actions/Section/detail.inc b/models/admin/actions/Section/detail.inc new file mode 100644 index 0000000..9c62904 --- /dev/null +++ b/models/admin/actions/Section/detail.inc @@ -0,0 +1,26 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: event.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/sections.php'; +$Sections = new EventManagementAdminSections($this->dbh, $this->config); + +$sectionDetail = $Sections->getSectionDetail(); +$this->page->sectionDetail = $this->bindArrayToObject($sectionDetail); + +$this->templateFile = 'Section/detail.html'; + +$this->addDebug("Section/detail.inc", 'Section Detail', print_r($sectionDetail,1)); + +?> + diff --git a/models/admin/actions/Section/edit.inc b/models/admin/actions/Section/edit.inc new file mode 100644 index 0000000..8c4934a --- /dev/null +++ b/models/admin/actions/Section/edit.inc @@ -0,0 +1,30 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: event.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/sections.php'; +$Sections = new EventManagementAdminSections($this->dbh, $this->config); + +$sectionDetail = $Sections->editSection(); +$this->page->sectionDetail = $this->bindArrayToObject($sectionDetail); + +// We need this to mimic stored detail for edit templates that show this on entry to edit +$this->page->storedDetail = $this->bindArrayToObject($sectionDetail); + +$this->page->editingSection = true; +$this->templateFile = 'Section/edit.html'; + +$this->addDebug("Section/edit.inc", 'Section Edit', print_r($sectionDetail,1)); + +?> + diff --git a/models/admin/actions/Section/insert.inc b/models/admin/actions/Section/insert.inc new file mode 100644 index 0000000..a14c442 --- /dev/null +++ b/models/admin/actions/Section/insert.inc @@ -0,0 +1,40 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: event.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/sections.php'; +$Sections = new EventManagementAdminSections($this->dbh, $this->config); + +// Process new record +$r = $Sections->insertSection(); + +// Get success status, false = fail +$status = $r['status']; +$this->page->formFail = !$status; + +$this->page->sectionDetail = $this->bindArrayToObject($r['fieldData']); +$this->page->fieldRequired = $this->bindArrayToObject($r['fieldRequired']); +$this->page->fieldFail = $this->bindArrayToObject($r['fieldFail']); + +// If invalid submission +if (!$status) { + $this->page->addingNewSection = true; + $this->templateFile = 'Section/edit.html'; +} else { + $this->templateFile = 'Section/detail.html'; +} + +$this->addDebug("Section/insert.inc", 'Section Insert', print_r($r,1)); + +?> + diff --git a/models/admin/actions/Section/list.inc b/models/admin/actions/Section/list.inc new file mode 100644 index 0000000..0dbc9fd --- /dev/null +++ b/models/admin/actions/Section/list.inc @@ -0,0 +1,27 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: event.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/sections.php'; +$Sections = new EventManagementAdminSections($this->dbh, $this->config); + +$sectionList = $Sections->getSectionsList(); + +$this->page->sectionList = $this->bindArrayToObject($sectionList); + +$this->templateFile = 'Section/list.html'; + +$this->addDebug("Section/list.inc", 'Section List', 'Array: $sectionList

    '.print_r($sectionList,1)); + +?> + diff --git a/models/admin/actions/Section/update.inc b/models/admin/actions/Section/update.inc new file mode 100644 index 0000000..426636a --- /dev/null +++ b/models/admin/actions/Section/update.inc @@ -0,0 +1,42 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: event.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/sections.php'; +$Sections = new EventManagementAdminSections($this->dbh, $this->config); + + +// Process new record +$r = $Sections->updateSection(); + +// Get success status, false = fail +$status = $r['status']; +$this->page->formFail = !$status; + +$this->page->sectionDetail = $this->bindArrayToObject($r['fieldData']); +$this->page->fieldRequired = $this->bindArrayToObject($r['fieldRequired']); +$this->page->fieldFail = $this->bindArrayToObject($r['fieldFail']); + +// If invalid submission +if (!$status) { + $this->page->editingSection = true; + $this->templateFile = 'Section/edit.html'; +} else { + // If valid + $this->templateFile = 'Section/detail.html'; +} + +$this->addDebug("Section/add.inc", 'Section Add', print_r($r,1)); + +?> + diff --git a/models/admin/actions/Sold/claim.inc b/models/admin/actions/Sold/claim.inc new file mode 100644 index 0000000..f7451b4 --- /dev/null +++ b/models/admin/actions/Sold/claim.inc @@ -0,0 +1,24 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: detail.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +// Check if we got an orderID here +$this->page->orderID = 0; +if (isset($_REQUEST['orderID'])) { + $orderID = ($_REQUEST['orderID'] -0); + $this->page->orderID = $orderID; +} + +$this->templateFile = 'Sold/claim.html'; + +?> \ No newline at end of file diff --git a/models/admin/actions/Sold/claimVoucher.inc b/models/admin/actions/Sold/claimVoucher.inc new file mode 100644 index 0000000..26d5faa --- /dev/null +++ b/models/admin/actions/Sold/claimVoucher.inc @@ -0,0 +1,44 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: claimVoucher.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +// Get ticket inventory ID and desired status +$voucherID = ($_REQUEST['VoucherID'] - 0); + +// Do sanity check on ID +if ($voucherID > 0) { + + // Get current claims information, if there is one + $sql = "SELECT time_claimed FROM eventmgt.ticket_sold WHERE id = $voucherID;"; + $stmt = $this->dbh->prepare($sql); + $stmt->execute(); + $voucher = $stmt->fetch(PDO::FETCH_ASSOC); + + if (!$voucher) { + + // Voucher Not Found + + } else { + + // Has not been claimed, so mark it and return time only + $sql = "UPDATE eventmgt.ticket_sold SET numb_claimed = numb_uses WHERE id = $voucherID OR package_sold_id = (SELECT package_sold_id FROM eventmgt.ticket_sold where id = $voucherID);"; + $stmt = $this->dbh->prepare($sql); + $stmt->execute(); + + } + +} + +include EVENT_MANAGEMENT_APP_BASE.'models/admin/actions/Sold/detail.inc'; + +?> \ No newline at end of file diff --git a/models/admin/actions/Sold/detail.inc b/models/admin/actions/Sold/detail.inc new file mode 100644 index 0000000..086d513 --- /dev/null +++ b/models/admin/actions/Sold/detail.inc @@ -0,0 +1,315 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: detail.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +$this->page->markedAsClaimed = false; +$this->page->alreadyClaimedAlert = false; +$packageClaimOK = true; +$problem = array(); + +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/sold.php'; +$Sold = new EventManagementAdminSold($this->dbh, $this->config); + +// If this is a member user then make sure they only list their own member performances +$userType = false; +$userID = false; +$scanName = 'Admin'; +$userMemberID = false; +if ($_SESSION[GLM_EVENT_SESSION]['MemberUser']) { + $userType = 'member'; + $userID = $_SESSION[GLM_EVENT_SESSION]['MemberUser']; + $userMemberID = $_SESSION[GLM_EVENT_SESSION]['Member']; // This is the ID of the member!!! +} + +// If we have a logged in user, then check if the user's member also scans for other members +$scansFor = false; +if ($userMemberID != false) { + + // Get the user information + require_once EVENT_MANAGEMENT_APP_BASE.'classes/data/dataContacts.php'; + $Contact = new EventManagementDataContacts($this->dbh, $this->config); + $userInfo = $Contact->getContactDetail($userID); + + $scanName = ''; + if ($userInfo['org'] != '') { + $scanName = $userInfo['org'].': '; + } + $scanName .= $userInfo['lname'].', '.$userInfo['fname']; + + // Also get list of members this member scans for + require_once EVENT_MANAGEMENT_APP_BASE.'classes/data/dataMemberScansFor.php'; + $MemberScansFor = new EventManagementDataMemberScansFor($this->dbh, $this->config); + $msf = $MemberScansFor->getMemberScansForList($userMemberID); + + // If member scans for others, build a simple array of those member IDs + if (is_array($msf) && count($msf) > 0) { + $scansFor = array(); + foreach ($msf as $m) { + $scansFor[] = $m['scans_for']; + } + } +} + +// Get sold ticket detail +$soldDetail = $Sold->getSoldDetail(); + +// If we don't have ticket detail +if (!$soldDetail) { + + $packageTickets = false; + $soldDetail = false; + $problem[] = 'Not found!'; + +// We have ticket detail +} else { + + // Check if a package voucher has been scanned + $this->page->isPackage = false; + if ($soldDetail['is_package']['value']) { + + $this->page->isPackage = true; + + // Check if this is an admin (not logged in) user - Not permitted to scan packages + if (!$userID && $_REQUEST['doClaim'] == 'true') { + + $packageTickets = false; + $soldDetail = false; + $problem[] = 'Admin users may not scan a package ticket voucher.
    + Package ticket vouchers may only be scanned by a valid logged-in user (contact).
    + Use "Order #:" entry to retrieve voucher status.'; + + // The user is a valid logged in user + } else { + + if ($userID) { + // Build member WHERE clause + $memberWhere = " AND member = $userMemberID"; + if ($scansFor != false) { + + // User member scans for other members (locations), so add them into the WHERE clause. + $memberWhere = "AND (member = $userMemberID"; + + foreach($scansFor as $sf) { + $memberWhere .= " OR member = $sf"; + } + + $memberWhere .= ')'; + } + } + + // Get list of tickets in the package for this location - Hopefully only 1 + $sql = " + SELECT * + FROM eventmgt.ticket_sold + WHERE package_sold_id = '".$soldDetail['package_sold_id']."' + AND id != ".$soldDetail['id']." + $memberWhere + ;"; + $stmt = $this->dbh->prepare($sql); + $stmt->execute(); + $packageTickets = $stmt->fetchAll(PDO::FETCH_ASSOC); + + // If we have package tickets for this location + if (is_array($packageTickets) && count($packageTickets) > 0) { + + // If we're trying to claim this ticket use + if ($_REQUEST['doClaim'] == 'true') { + + // Check if there's more than one ticket - should not be the case + if (count($packageTickets) > 1) { + + $problem[] = 'More than one package item for this location was found for the scanned voucher.
    + There may only be one item per location contained in a package. Please check the + package configuration.'; + + // Only one ticket for this location in the package - OK to claim + } else { + + // For each ticket in the package at this location + foreach ($packageTickets as $pt) { + + // Check if it's not unlimited and already been claimed the max times + if (!$pt['unlimited_use'] && ($pt['numb_uses'] - $pt['numb_claimed']) <= 0 ) { + $packageClaimOK = false; + $this->page->alreadyClaimedAlert = true; + } + + } + + // If we can claim these tickets + if ($packageClaimOK) { + + reset($packageTickets); + while (list($key, $val) = each($packageTickets)) { + + // Update ticket_sold to indicate one claim of voucher + $sql = " + UPDATE eventmgt.ticket_sold + SET numb_claimed = ( numb_claimed + 1 ) + WHERE id = ".$val['id']."; + "; + $stmt = $this->dbh->prepare($sql); + $stmt->execute(); + + // Also update our local copy + $packageTickets[$key]['numb_claimed'] += 1; + + // Store claim tracking + $sql = " + INSERT INTO eventmgt.ticket_claim_tracking + ( ticket_order, ticket_sold, time_of_action, action_type, quant, scan_user, scan_name ) + VALUES + ( + ".$val['ticket_order'].", + ".$val['id'].", + 'now', + ".$this->config->claim_tracking_types_numb->claim.", + 1, + $userID, + '".addslashes($scanName)."' + ); + "; + $stmt = $this->dbh->prepare($sql); + $stmt->execute(); + + } + + $this->page->markedAsClaimed = true; + + } // OK to claim ticket + + } // Only one ticket for this location in the package - OK to claim + + } // Claiming package ticket at this time + + } // Have package tickets for this location + + } // Have a valid logged in user + + // Otherwise not scanning a package + } else { + + /* + * Check if user can scan this ticket, must be one of ... + * 1) No user logged in - admins can scan for any non-package + * 2) User logged in belongs to the ticket member + * 3) User logged in belongs to the member that scans for the ticket member + */ + if ( $userMemberID == false || + $soldDetail['member'] == $userMemberID || + (is_array($scansFor) && (in_array($soldDetail['member'], $scansFor) || in_array($soldDetail['assigned_from'], $scansFor))) ) { + + // If we're not trying to claim this ticket use + if ($_REQUEST['doClaim'] != 'true') { + + // Do nothing here. We're just going to display the voucher data + + // Check if the ticket is not unlimited and has already been claimed the max times + } elseif (!$soldDetail['unlimited_use']['value'] && ($soldDetail['numb_uses'] - $soldDetail['numb_claimed']) <= 0 ) { + + // Ticket has already been claimed. + $this->page->alreadyClaimedAlert = true; + + // Otherwise add a claim for this voucher + } else { + + // Update ticket_sold to indicate one claim of voucher + $sql = " + + UPDATE eventmgt.ticket_sold + SET numb_claimed = ( numb_claimed + 1 ) + WHERE id = ".$soldDetail['id']."; + "; + $stmt = $this->dbh->prepare($sql); + $stmt->execute(); + + // Store claim tracking + $sql = " + INSERT INTO eventmgt.ticket_claim_tracking + ( ticket_order, ticket_sold, time_of_action, action_type, quant, scan_user, scan_name ) + VALUES + ( + ".$soldDetail['ticket_order'].", + ".$soldDetail['id'].", + 'now', + ".$this->config->claim_tracking_types_numb->claim.", + 1, + ".($userID?$userID:'null').", + '".addslashes($scanName)."' + ); + "; + $stmt = $this->dbh->prepare($sql); + $stmt->execute(); + + // Reload voucher data + $soldDetail = $Sold->getSoldDetail(false, $id); + + $this->page->markedAsClaimed = true; + + } + + + // User is not permitted to scan the ticket + } else { + $packageTickets = false; + $soldDetail = false; + $problem[] = 'The scanned ticket may not be used at the current location.'; + } + + + } + +} // have ticket detail + +// And one last thing. To add some data to package tickets +if (is_array($packageTickets) && count($packageTickets) > 0) { + + reset($packageTickets); + + // For each ticket in the package at this location + while (list($key, $val) = each($packageTickets)) { + + $packageTickets[$key]['fullyClaimedAlert'] = false; + $remaining = ($val['numb_uses'] - $val['numb_claimed']); + $packageTickets[$key]['remaining'] = $remaining; + + if (!$val['unlimited_use'] && $remaining <= 0 ) { + $packageTickets[$key]['fullyClaimedAlert'] = true; + } + + } + + $this->page->packageDetail = $this->bindArrayToObject($packageTickets); + +} + +// Check for main sold detail number of claimes expired +$remaining = ($soldDetail['numb_uses'] - $soldDetail['numb_claimed']); +if (is_array($soldDetail) && $soldDetail['unlimited_use']['value'] == '' && $remaining <= 0 ) { + $soldDetail['fullyClaimedAlert'] = true; +} + +$this->page->soldDetail = $this->bindArrayToObject($soldDetail); +$this->templateFile = 'Sold/detail.html'; + +if (count($problem) > 0) { + $this->page->problem = $this->bindArrayToObject($problem); + $this->page->haveProblem = true; +} else { + $this->page->problem = false; + $this->page->haveProblem = false; +} + +$this->addDebug("Sold/detail.inc", 'Array: $soldDetail', print_r($soldDetail,1)); + +?> \ No newline at end of file diff --git a/models/admin/actions/Sold/fixPackages.inc b/models/admin/actions/Sold/fixPackages.inc new file mode 100755 index 0000000..24ed05e --- /dev/null +++ b/models/admin/actions/Sold/fixPackages.inc @@ -0,0 +1,170 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: fixPackages.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + + +/* + * This method is build to add the missing package detail for + * package tickets sold that did not have the ticket_sold records + * added for each of the package destinations. This is not + * for normal use. + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'classes/data/dataTicketPackages.php'; +$TicketPackages = new EventManagementDataTicketPackages($this->dbh, $this->config); + +// Get all sold packages that do not have ticket_sold entries for the individual destinations +$sql = " + SELECT ticket_sold.* + FROM eventmgt.ticket_sold, eventmgt.ticket + WHERE ticket.id = ticket_sold.ticket + AND ticket.ticket_type = 20 + AND package_sold_id IS null + ORDER BY ticket_sold.id + LIMIT 100 +;"; +$stmt = $this->dbh->prepare($sql); +$stmt->execute(); +$soldList = $stmt->fetchAll(PDO::FETCH_ASSOC); + +echo "

    Loaded ".count($soldList)." package sales that need to be fixed.

    "; + +// For each package ticket sold that needs to be fixed +foreach ($soldList as $s) { + + $pSale = $s['id']; + $p = $s['ticket']; + + // get the package contents + require_once EVENT_MANAGEMENT_APP_BASE.'classes/data/dataTicketPackages.php'; + $TicketPackages = new EventManagementDataTicketPackages($this->dbh, $this->config); + $packageData = $TicketPackages->getPackageList("package = ".$s['ticket']); + + echo "Processing package sale # $pSale - Session ID = ".$s['session_id']."
    "; + + // for each item in the package + reset ($packageData); + foreach ($packageData as $t) { + + // Get information on this package ticket + require_once EVENT_MANAGEMENT_APP_BASE.'classes/data/dataTickets.php'; + $Tickets = new EventManagementDataTickets($this->dbh, $this->config); + $pt = $Tickets->getTicketDetail($t['ticket']); + + require_once EVENT_MANAGEMENT_APP_BASE.'classes/data/dataSections.php'; + $Sections = new EventManagementDataSections($this->dbh, $this->config); + $ps = $Sections->getSectionDetail($pt['section_id']); + + // Get Entrance information for this ticket's section + require_once EVENT_MANAGEMENT_APP_BASE.'classes/data/dataEntrances.php'; + $Entrances = new EventManagementDataEntrances($this->dbh, $this->config); + $pe = $Entrances->getEntranceDetail($ps['entrance']); + + $sql = " + INSERT INTO eventmgt.ticket_sold + ( + ticket_order, + member, + member_name, + assigned, + assigned_from, + assigned_from_name, + performance, + performance_name, + entrance, + entrance_name, + entrance_color, + section, + section_name, + ticket, + ticket_name, + is_package, + package_sold_id, + ticket_package, + package_name, + date_specific, + ticket_date, + time_specific, + ticket_time, + start_date, + end_date, + likely_date, + price_paid, + voucher_type, + voucher_text, + policies, + unlimited_use, + numb_uses, + numb_claimed, + time_claimed, + session_id + ) + VALUES + ( + ".$s['ticket_order'].", + ".$pt['member'].", + '".$pt['member_name']."', + false, + NULL, + '', + ".$pt['performance_id'].", + '".$pt['performance']."', + ".(!empty($pt['section_id']) ? $pt['section_id'] : 'NULL').", + '".$pe['name']."', + '".$pe['color']['name']."', + ".$ps['id'].", + '".$ps['name']."', + ".$pt['id'].", + '".$pt['title']."', + false, + '".$s['session_id']."-$pSale', + ".$s['ticket'].", + '".$packageData['title']."', + false, + NULL, + false, + '".$pt['ticket_timestamp']."', + ".(!empty($pt['start_date']['date']) ? "'".$pt['start_date']['date']."'" : 'NULL').", + ".(!empty($pt['end_date']['date']) ? "'".$pt['end_date']['date']."'" : 'NULL').", + NULL, + 0, + ".$pt['voucher_type']['value'].", + '".$pt['voucher_text']."', + '', + ".($pt['unlimited_use']['value'] ? 'true' : 'false').", + ".$pt['uses'].", + 0, + null, + '".$s['session_id']."' + ); + "; + $stmt = $this->dbh->prepare($sql); + $stmt->execute(); + + } + + // Now update the package ticket entry + $sql = " + UPDATE eventmgt.ticket_sold + SET package_sold_id = '".$s['session_id']."-$pSale', + is_package = true + WHERE id = $pSale + ;"; + $stmt = $this->dbh->prepare($sql); + $stmt->execute(); + +} +exit; + + +?> \ No newline at end of file diff --git a/models/admin/actions/Sold/list.inc b/models/admin/actions/Sold/list.inc new file mode 100644 index 0000000..f2d8cc6 --- /dev/null +++ b/models/admin/actions/Sold/list.inc @@ -0,0 +1,35 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: list.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/sold.php'; +$Sold = new EventManagementAdminSold($this->dbh, $this->config); + +// If this is a member user then make sure they only list their own member performances +$type = false; +$id = false; +if ($_SESSION[GLM_EVENT_SESSION]['MemberUser'] && !$this->config->option->users_access_all_members) { + $type = 'member'; + $id = $this->page->userMemberID; +} + +$soldList = $Sold->getSoldList(false, $id); + +$this->page->soldList = $this->bindArrayToObject($soldList); + +$this->templateFile = 'Sold/list.html'; + +$this->addDebug("Sold/list.inc", 'Sold List', 'Array: $soldList

    '.print_r($soldList,1)); + +?> + diff --git a/models/admin/actions/Sold/resetVoucher.inc b/models/admin/actions/Sold/resetVoucher.inc new file mode 100644 index 0000000..af7512c --- /dev/null +++ b/models/admin/actions/Sold/resetVoucher.inc @@ -0,0 +1,45 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: resetVoucher.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +// Get ticket inventory ID and desired status +$voucherID = ($_REQUEST['VoucherID'] - 0); + +// Do sanity check on ID +if ($voucherID > 0) { + + // Get current claim time, if there is one + $sql = "SELECT time_claimed FROM eventmgt.ticket_sold WHERE id = $voucherID;"; + $stmt = $this->dbh->prepare($sql); + $stmt->execute(); + $voucher = $stmt->fetch(PDO::FETCH_ASSOC); + + if (!$voucher) { + + // Voucher Not Found + + } else { + + // Has not been claimed, so clear it + $sql = "UPDATE eventmgt.ticket_sold SET numb_claimed = 0 WHERE id = $voucherID OR package_sold_id = (SELECT package_sold_id FROM eventmgt.ticket_sold where id = $voucherID);"; + $stmt = $this->dbh->prepare($sql); + $stmt->execute(); + + } + +} + +include EVENT_MANAGEMENT_APP_BASE.'models/admin/actions/Sold/detail.inc'; + + +?> \ No newline at end of file diff --git a/models/admin/actions/Sold/selected.inc b/models/admin/actions/Sold/selected.inc new file mode 100644 index 0000000..b44de8c --- /dev/null +++ b/models/admin/actions/Sold/selected.inc @@ -0,0 +1,25 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: selected.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/sold.php'; +$Sold = new EventManagementAdminSold($this->dbh, $this->config); + +$soldDetail = $Sold->getSoldDetail(); +$this->page->soldDetail = $this->bindArrayToObject($soldDetail); + +$this->templateFile = 'Sold/selected.html'; + +$this->addDebug("Sold/selected.inc", 'Sold Ticket Detail', print_r($soldDetail,1)); + +?> \ No newline at end of file diff --git a/models/admin/actions/State/add.inc b/models/admin/actions/State/add.inc new file mode 100644 index 0000000..27e826a --- /dev/null +++ b/models/admin/actions/State/add.inc @@ -0,0 +1,36 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: event.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/states.php'; +$States = new EventManagementAdminStates($this->dbh, $this->config); +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/contacts.php'; +$Contacts = new EventManagementAdminContacts($this->dbh, $this->config); + + +// Generate a random access code for the new team +require '../classes/EasyPassword.php'; +$ep = new EasyPassword(); +$passwd = $ep->generateEasyPassword(); + +$r = $States->newState(); +$r['fieldData']['password'] = $code; + +$this->page->stateDetail = $this->bindArrayToObject($r['fieldData']); +$this->page->fieldRequired = $this->bindArrayToObject($r['fieldRequired']); +$this->page->fieldFail = $this->bindArrayToObject($r['fieldFail']); +$this->page->addingNewState = true; + +$this->templateFile = 'State/EditState.html'; + +?> \ No newline at end of file diff --git a/models/admin/actions/State/detail.inc b/models/admin/actions/State/detail.inc new file mode 100644 index 0000000..df70e19 --- /dev/null +++ b/models/admin/actions/State/detail.inc @@ -0,0 +1,36 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: event.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/states.php'; +$States = new EventManagementAdminStates($this->dbh, $this->config); +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/contacts.php'; +$Contacts = new EventManagementAdminContacts($this->dbh, $this->config); + + +$stateDetail = $States->getStateDetail(); +$this->page->stateDetail = $this->bindArrayToObject($stateDetail); + +// Get contacts for this event +$eventContacts = $Contacts->getContacts('state'); +$this->page->contactsList = $this->bindArrayToObject($eventContacts['contact_list']); + +// Get room blocks and teams for this state rep +require '../classes/blocks.php'; +$Blocks = new EventManagementAdminBlocks($this->dbh, $this->config); +$roomBlocks = $Blocks->getRoomBlocks(false, true, true, $stateDetail['id']); +$this->page->roomBlocks = $this->bindArrayToObject($roomBlocks); + +$this->templateFile = 'State/StateDetail.html'; + +?> \ No newline at end of file diff --git a/models/admin/actions/State/edit.inc b/models/admin/actions/State/edit.inc new file mode 100644 index 0000000..7c714a8 --- /dev/null +++ b/models/admin/actions/State/edit.inc @@ -0,0 +1,44 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: event.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/states.php'; +$States = new EventManagementAdminStates($this->dbh, $this->config); +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/contacts.php'; +$Contacts = new EventManagementAdminContacts($this->dbh, $this->config); + + +// Check State Code +$stateDetail = $States->editState(); + +// If no password has been set, then suggest one +if (trim($stateDetail['password']) == '') { + + // Generate a random access code for the new team + require '../classes/EasyPassword.php'; + $ep = new EasyPassword(); + $passwd = $ep->generateEasyPassword(); + $stateDetail['password'] = $passwd; + +} + +$this->page->stateDetail = $this->bindArrayToObject($stateDetail); + +// We need this to mimic stored detail for edit templates that show this on entry to edit +$this->page->storedDetail = $this->bindArrayToObject($stateDetail); + +$this->page->editingState = true; + +$this->templateFile = 'State/EditState.html'; + +?> \ No newline at end of file diff --git a/models/admin/actions/State/insert.inc b/models/admin/actions/State/insert.inc new file mode 100644 index 0000000..a3ac97c --- /dev/null +++ b/models/admin/actions/State/insert.inc @@ -0,0 +1,40 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: event.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/states.php'; +$States = new EventManagementAdminStates($this->dbh, $this->config); +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/contacts.php'; +$Contacts = new EventManagementAdminContacts($this->dbh, $this->config); + + +// Process new record +$r = $States->insertState(); + +// Get success status, false = fail +$status = $r['status']; +$this->page->formFail = !$status; + +$this->page->stateDetail = $this->bindArrayToObject($r['fieldData']); +$this->page->fieldRequired = $this->bindArrayToObject($r['fieldRequired']); +$this->page->fieldFail = $this->bindArrayToObject($r['fieldFail']); + +// If invalid submission +if (!$status) { + $this->page->addingNewState = true; + $this->templateFile = 'State/EditState.html'; +} else { + $this->templateFile = 'State/StateDetail.html'; +} + +?> \ No newline at end of file diff --git a/models/admin/actions/State/list.inc b/models/admin/actions/State/list.inc new file mode 100644 index 0000000..d9704bd --- /dev/null +++ b/models/admin/actions/State/list.inc @@ -0,0 +1,31 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: event.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/states.php'; +$States = new EventManagementAdminStates($this->dbh, $this->config); +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/contacts.php'; +$Contacts = new EventManagementAdminContacts($this->dbh, $this->config); + + +// Get state reps stats +$statesStats = $States->getStatesStats(); +$this->page->statesStats = $this->bindArrayToObject($statesStats); + +// Get state reps list +$states = $States->getStatesList(); +$this->page->statesList = $this->bindArrayToObject($states); + +$this->templateFile = 'State/StatesList.html'; + +?> \ No newline at end of file diff --git a/models/admin/actions/State/update.inc b/models/admin/actions/State/update.inc new file mode 100644 index 0000000..435a243 --- /dev/null +++ b/models/admin/actions/State/update.inc @@ -0,0 +1,44 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: event.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/states.php'; +$States = new EventManagementAdminStates($this->dbh, $this->config); +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/contacts.php'; +$Contacts = new EventManagementAdminContacts($this->dbh, $this->config); + + +// Process new record +$r = $States->updateState(); + +// Get success status, false = fail +$status = $r['status']; +$this->page->formFail = !$status; + +$this->page->stateDetail = $this->bindArrayToObject($r['fieldData']); +$this->page->fieldRequired = $this->bindArrayToObject($r['fieldRequired']); +$this->page->fieldFail = $this->bindArrayToObject($r['fieldFail']); + +// Get currently stored data for fields that are display only +$stateDetail = $States->getStateDetail(); +$this->page->storedDetail = $this->bindArrayToObject($stateDetail); + +// If invalid submission +if (!$status) { + $this->page->editingState = true; + $this->templateFile = 'State/EditState.html'; +} else { + $this->templateFile = 'State/StateDetail.html'; +} + +?> \ No newline at end of file diff --git a/models/admin/actions/Team/add.inc b/models/admin/actions/Team/add.inc new file mode 100644 index 0000000..914be17 --- /dev/null +++ b/models/admin/actions/Team/add.inc @@ -0,0 +1,35 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: event.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/teams.php'; +$Teams = new EventManagementAdminTeams($this->dbh, $this->config); +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/contacts.php'; +$Contacts = new EventManagementAdminContacts($this->dbh, $this->config); + +// Generate a random access code for the new team +require GLM_APP_BASE.'Common/'.$this->config->applicationVersion.'/classes/EasyPassword.php'; +$ep = new EasyPassword(); +$code = $ep->generateEasyPassword(); + +$r = $Teams->newTeam(); +$r['fieldData']['team_code'] = $code; + +$this->page->teamDetail = $this->bindArrayToObject($r['fieldData']); +$this->page->fieldRequired = $this->bindArrayToObject($r['fieldRequired']); +$this->page->fieldFail = $this->bindArrayToObject($r['fieldFail']); +$this->page->addingNewTeam = true; + +$this->templateFile = 'Team/EditTeam.html'; + +?> \ No newline at end of file diff --git a/models/admin/actions/Team/detail.inc b/models/admin/actions/Team/detail.inc new file mode 100644 index 0000000..f32ae07 --- /dev/null +++ b/models/admin/actions/Team/detail.inc @@ -0,0 +1,31 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: event.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/teams.php'; +$Teams = new EventManagementAdminTeams($this->dbh, $this->config); +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/contacts.php'; +$Contacts = new EventManagementAdminContacts($this->dbh, $this->config); + + +$r = $Teams->getTeamDetail(); +$this->page->teamDetail = $this->bindArrayToObject($r['teamDetail']); +$this->page->teamRoster = $this->bindArrayToObject($r['teamRoster']); + +// Get contacts for this event +$eventContacts = $Contacts->getContacts('team'); +$this->page->contactsList = $this->bindArrayToObject($eventContacts['contact_list']); + +$this->templateFile = 'Team/TeamDetail.html'; + +?> \ No newline at end of file diff --git a/models/admin/actions/Team/edit.inc b/models/admin/actions/Team/edit.inc new file mode 100644 index 0000000..6a35d48 --- /dev/null +++ b/models/admin/actions/Team/edit.inc @@ -0,0 +1,31 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: event.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/teams.php'; +$Teams = new EventManagementAdminTeams($this->dbh, $this->config); +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/contacts.php'; +$Contacts = new EventManagementAdminContacts($this->dbh, $this->config); + + +$teamDetail = $Teams->editTeam(); +$this->page->teamDetail = $this->bindArrayToObject($teamDetail); + +// We need this to mimic stored detail for edit templates that show this on entry to edit +$this->page->storedDetail = $this->bindArrayToObject($teamDetail); + +$this->page->editingTeam = true; + +$this->templateFile = 'Team/EditTeam.html'; + +?> \ No newline at end of file diff --git a/models/admin/actions/Team/editRoster.inc b/models/admin/actions/Team/editRoster.inc new file mode 100644 index 0000000..7a436ca --- /dev/null +++ b/models/admin/actions/Team/editRoster.inc @@ -0,0 +1,26 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: event.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/teams.php'; +$Teams = new EventManagementAdminTeams($this->dbh, $this->config); + + +$r = $Teams->editTeamRoster(); + +$this->page->teamDetail = $this->bindArrayToObject($r['teamDetail']); +$this->page->teamRoster = $this->bindArrayToObject($r['teamRoster']); + +$this->templateFile = 'Team/EditTeamRoster.html'; + +?> \ No newline at end of file diff --git a/models/admin/actions/Team/insert.inc b/models/admin/actions/Team/insert.inc new file mode 100644 index 0000000..431c94b --- /dev/null +++ b/models/admin/actions/Team/insert.inc @@ -0,0 +1,40 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: event.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/teams.php'; +$Teams = new EventManagementAdminTeams($this->dbh, $this->config); +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/contacts.php'; +$Contacts = new EventManagementAdminContacts($this->dbh, $this->config); + + +// Process new record +$r = $Teams->insertTeam(); + +// Get success status, false = fail +$status = $r['status']; +$this->page->formFail = !$status; + +$this->page->teamDetail = $this->bindArrayToObject($r['fieldData']); +$this->page->fieldRequired = $this->bindArrayToObject($r['fieldRequired']); +$this->page->fieldFail = $this->bindArrayToObject($r['fieldFail']); + +// If invalid submission +if (!$status) { + $this->page->addingNewTeam = true; + $this->templateFile = 'Team/EditTeam.html'; +} else { + $this->templateFile = 'Team/TeamDetail.html'; +} + +?> \ No newline at end of file diff --git a/models/admin/actions/Team/list.inc b/models/admin/actions/Team/list.inc new file mode 100644 index 0000000..fdd88b4 --- /dev/null +++ b/models/admin/actions/Team/list.inc @@ -0,0 +1,54 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: event.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/teams.php'; +$Teams = new EventManagementAdminTeams($this->dbh, $this->config); +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/contacts.php'; +$Contacts = new EventManagementAdminContacts($this->dbh, $this->config); + + +// Check for teams that don't have access codes and assign one to them +require GLM_APP_BASE.'CommonApps/'.$this->config->applicationVersion.'/classes/EasyPassword.php'; +$ep = new EasyPassword(); + +$sql = " + SELECT id + FROM eventmgt.team + WHERE team_code IS NULL + OR team_code = ''; + "; +$stmt = $this->dbh->prepare($sql); +$stmt->execute(); +$teams = $stmt->fetchAll(PDO::FETCH_ASSOC); +$sql = ''; +if (count($teams) > 0) { + foreach ($teams as $t) { + $code = $ep->generateEasyPassword(); + $sql = "UPDATE team SET team_code = '$code' WHERE id = ".$t['id'].";\n"; + $stmt = $this->dbh->prepare($sql); + $stmt->execute(); + } +} + +// Get teams stats +$teamsStats = $Teams->getTeamsStats(); +$this->page->teamsStats = $this->bindArrayToObject($teamsStats); + +// Get teams list +$teams = $Teams->getTeamsList(); +$this->page->teamsList = $this->bindArrayToObject($teams); + +$this->templateFile = 'Team/TeamsList.html'; + +?> \ No newline at end of file diff --git a/models/admin/actions/Team/update.inc b/models/admin/actions/Team/update.inc new file mode 100644 index 0000000..f6b2df1 --- /dev/null +++ b/models/admin/actions/Team/update.inc @@ -0,0 +1,45 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: event.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/teams.php'; +$Teams = new EventManagementAdminTeams($this->dbh, $this->config); +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/contacts.php'; +$Contacts = new EventManagementAdminContacts($this->dbh, $this->config); + + +// Process new record +$r = $Teams->updateTeam(); + +// Get success status, false = fail +$status = $r['status']; +$this->page->formFail = !$status; + +$this->page->teamDetail = $this->bindArrayToObject($r['fieldData']); +$this->page->fieldRequired = $this->bindArrayToObject($r['fieldRequired']); +$this->page->fieldFail = $this->bindArrayToObject($r['fieldFail']); + +// Get currently stored data for fields that are display only +$r = $Teams->getTeamDetail(); +$this->page->storedDetail = $this->bindArrayToObject($r['teamDetail']); +$this->page->teamRoster = $this->bindArrayToObject($r['teamRoster']); + +// If invalid submission +if (!$status) { + $this->page->editingTeam = true; + $this->templateFile = 'Team/EditTeam.html'; +} else { + $this->templateFile = 'Team/TeamDetail.html'; +} + +?> \ No newline at end of file diff --git a/models/admin/actions/Team/updateRoster.inc b/models/admin/actions/Team/updateRoster.inc new file mode 100644 index 0000000..47b1f45 --- /dev/null +++ b/models/admin/actions/Team/updateRoster.inc @@ -0,0 +1,32 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: event.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/teams.php'; +$Teams = new EventManagementAdminTeams($this->dbh, $this->config); + + +$r = $Teams->updateTeamRoster(); + +$this->page->teamDetail = $this->bindArrayToObject($r['teamDetail']); +$this->page->teamRoster = $this->bindArrayToObject($r['teamRoster']); +$this->page->fieldFail = $this->bindArrayToObject($r['fieldFail']); + +// If invalid submission +if (!$r['status']) { + $this->templateFile = 'Team/EditTeamRoster.html'; +} else { + $this->templateFile = 'Team/TeamDetail.html'; +} + +?> \ No newline at end of file diff --git a/models/admin/actions/Ticket/add.inc b/models/admin/actions/Ticket/add.inc new file mode 100644 index 0000000..a20665b --- /dev/null +++ b/models/admin/actions/Ticket/add.inc @@ -0,0 +1,58 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: add.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +// Check if we need to ask for a member/venue first +//if (!$_SESSION[GLM_EVENT_SESSION]['Member']) { +$memberID = ($_REQUEST['memberID'] - 0); +if ($memberID == 0) { + require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/members.php'; + $Members = new EventManagementAdminMembers($this->dbh, $this->config); + $members = $Members->getMembersList('all'); + + // Check if there's only one member and if so don't bother asking + if (count($members) == 1) { + $_SESSION[GLM_EVENT_SESSION]['Member'] = $members[0]['id']; + } else { + + $this->page->membersList = $this->bindArrayToObject($members); + $this->templateFile = 'Ticket/addGetMember.html'; + return; + } + +} else { + $_SESSION[GLM_EVENT_SESSION]['Member'] = $memberID; + + require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/members.php'; + $Members = new EventManagementAdminMembers($this->dbh, $this->config); + $member = $Members->getEntry($memberID); + +} + +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/tickets.php'; +$Tickets = new EventManagementAdminTickets($this->dbh, $this->config); + +$r = $Tickets->newTicket(); + +$this->page->memberDetail = $this->bindArrayToObject($member); +$this->page->ticketDetail = $this->bindArrayToObject($r['fieldData']); +$this->page->fieldRequired = $this->bindArrayToObject($r['fieldRequired']); +$this->page->fieldFail = $this->bindArrayToObject($r['fieldFail']); + +$this->page->addingNewTicket = true; + +$this->templateFile = 'Ticket/edit.html'; + +$this->addDebug("Ticket/add.inc", 'Array: $r', print_r($r,1)); + +?> \ No newline at end of file diff --git a/models/admin/actions/Ticket/confirmDelete.inc b/models/admin/actions/Ticket/confirmDelete.inc new file mode 100644 index 0000000..b8e5c10 --- /dev/null +++ b/models/admin/actions/Ticket/confirmDelete.inc @@ -0,0 +1,26 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: confirmDelete.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/tickets.php'; +$Tickets = new EventManagementAdminTickets($this->dbh, $this->config); + +$ticketDetail = $Tickets->ticketDelete(true); +$this->page->ticketDetail = $this->bindArrayToObject($ticketDetail); + +$this->templateFile = 'Ticket/detail.html'; + +$this->addDebug("Ticket/confirmDelete.inc", 'Section Confirm Delete', print_r($ticketDetail,1)); + +?> + diff --git a/models/admin/actions/Ticket/delete.inc b/models/admin/actions/Ticket/delete.inc new file mode 100644 index 0000000..4258d52 --- /dev/null +++ b/models/admin/actions/Ticket/delete.inc @@ -0,0 +1,27 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: delete.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/tickets.php'; +$Tickets = new EventManagementAdminTickets($this->dbh, $this->config); + + +$ticketDetail = $Tickets->ticketDelete(false); +$this->page->ticketDetail = $this->bindArrayToObject($ticketDetail); + +$this->templateFile = 'Ticket/delete.html'; + +$this->addDebug("Ticket/delete.inc", 'Array: $ticketDetail', print_r($ticketDetail,1)); + +?> + diff --git a/models/admin/actions/Ticket/detail.inc b/models/admin/actions/Ticket/detail.inc new file mode 100644 index 0000000..38244c7 --- /dev/null +++ b/models/admin/actions/Ticket/detail.inc @@ -0,0 +1,47 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: detail.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/tickets.php'; +$Tickets = new EventManagementAdminTickets($this->dbh, $this->config); + +// Get Ticket detail +$ticketDetail = $Tickets->getTicketDetail(); +$this->page->ticketDetail = $this->bindArrayToObject($ticketDetail); + +// If it's a package, get the package contents +$this->page->isPackage = false; +if ($this->config->option->packages && $ticketDetail['ticket_type']['value'] == 20) { + require_once EVENT_MANAGEMENT_APP_BASE.'classes/data/dataTicketPackages.php'; + $TicketPackages = new EventManagementDataTicketPackages($this->dbh, $this->config); + $packageData = $TicketPackages->getPackageList("package = ".$ticketDetail['id']); + $this->page->isPackage = true; +} +$this->page->ticketPackage = $this->bindArrayToObject($packageData); + +$_SESSION[GLM_EVENT_SESSION]['Member'] = $ticketDetail['member']; + +// Also get Ticket inventory Stats - and check if none exist for this ticket +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/ticketInventory.php'; +$ticketInventory = new EventManagementAdminTicketInventory($this->dbh, $this->config); +$ticketInventoryStats = $ticketInventory->getTicketTicketInventoryStats(); +$this->page->noTicketInventory = true; +if ($ticketInventoryStats > 0) { + $this->page->noTicketInventory = false; +} + +$this->templateFile = 'Ticket/detail.html'; + +$this->addDebug("Ticket/detail.inc", 'Array: $ticketDetail', print_r($ticketDetail,1)); + +?> \ No newline at end of file diff --git a/models/admin/actions/Ticket/edit.inc b/models/admin/actions/Ticket/edit.inc new file mode 100644 index 0000000..9e168f8 --- /dev/null +++ b/models/admin/actions/Ticket/edit.inc @@ -0,0 +1,46 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: edit.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/tickets.php'; +$Tickets = new EventManagementAdminTickets($this->dbh, $this->config); + +$ticketDetail = $Tickets->editTicket(); +$this->page->ticketDetail = $this->bindArrayToObject($ticketDetail); + +// We need this to mimic stored detail for edit templates that show this on entry to edit +$this->page->storedDetail = $this->bindArrayToObject($ticketDetail); + +// We need a full list of other tickets to use for selecting tickets in a package +$ticketsList = $Tickets->getTicketsList($ticketDetail['member'], false, false, 'packageSelect', false, false, false, $ticketDetail['id']); +$this->page->ticketsList = $this->bindArrayToObject($ticketsList); + +// var_dump($ticketsList); + +// Also get a list of any tickets that are included in the package +$this->page->isPackage = false; +if ($ticketDetail['ticket_type']['value'] == 20) { + require_once EVENT_MANAGEMENT_APP_BASE.'classes/data/dataTicketPackages.php'; + $TicketPackages = new EventManagementDataTicketPackages($this->dbh, $this->config); + $packageData = $TicketPackages->getPackageList("T.package = ".$ticketDetail['id']); + $this->page->ticketPackage = $this->bindArrayToObject($packageData); + $this->page->isPackage = true; +} + +$this->page->editingTicket = true; + +$this->templateFile = 'Ticket/edit.html'; + +$this->addDebug("Ticket/edit.inc", 'Array: $ticketDetail', print_r($ticketDetail,1)); + +?> \ No newline at end of file diff --git a/models/admin/actions/Ticket/insert.inc b/models/admin/actions/Ticket/insert.inc new file mode 100644 index 0000000..c90ab95 --- /dev/null +++ b/models/admin/actions/Ticket/insert.inc @@ -0,0 +1,63 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: insert.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/tickets.php'; +$Tickets = new EventManagementAdminTickets($this->dbh, $this->config); + +// Process new record +$r = $Tickets->insertTicket(); + +// Get success status, false = fail +$status = $r['status']; +$this->page->formFail = !$status; + +$this->page->ticketDetail = $this->bindArrayToObject($r['fieldData']); +$this->page->fieldRequired = $this->bindArrayToObject($r['fieldRequired']); +$this->page->fieldFail = $this->bindArrayToObject($r['fieldFail']); + +// If invalid submission +if (!$status) { + $this->page->addingNewTicket = true; + $this->templateFile = 'Ticket/edit.html'; +} else { + + $ticketID = $r['fieldData']['id']; + // Also get Ticket inventory Stats - and check if none exist for this ticket + require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/ticketInventory.php'; + $TicketInventory = new EventManagementAdminTicketInventory($this->dbh, $this->config); + $ticketInventoryStats = $TicketInventory->getTicketTicketInventoryStats($ticketID); + + $this->page->noTicketInventory = true; + if ($ticketInventoryStats > 0) { + $this->page->noTicketInventory = false; + } else { + + // Try to create default ticket inventory + $TicketInventory->generateDefaultTicketInventory(); + + // Get inventory stats again + $ticketInventoryStats = $TicketInventory->getTicketTicketInventoryStats($ticketDetail['id']); + + if ($ticketInventoryStats > 0) { + $this->page->noTicketInventory = false; + } + } + + $this->templateFile = 'Ticket/selected.html'; +} + +$this->addDebug("Ticket/insert.inc", 'Array: $r', print_r($r,1)); + + +?> \ No newline at end of file diff --git a/models/admin/actions/Ticket/inventory.inc b/models/admin/actions/Ticket/inventory.inc new file mode 100644 index 0000000..c4d4657 --- /dev/null +++ b/models/admin/actions/Ticket/inventory.inc @@ -0,0 +1,59 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: inventory.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/ticketInventory.php'; +$TicketInventory = new EventManagementAdminTicketInventory($this->dbh, $this->config); + +// Check if a CreateInventory request has been received +if (!$_REQUEST['CreateInventory'] == 'true') { + + $res = $TicketInventory->generateDefaultTicketInventory(); + + // If there's a failure, then report that + if (!$res) { + $this->page->ticketCreateInventoryFail = true; + } + +} + +// Get Ticket detail +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/tickets.php'; +$Tickets = new EventManagementAdminTickets($this->dbh, $this->config); +$ticketDetail = $Tickets->getTicketDetail(); +$this->page->ticketDetail = $this->bindArrayToObject($ticketDetail); + +$this->addDebug("Ticket/inventory.inc", 'Array: $ticketDetail', print_r($ticketDetail,1)); + +// If ticket is date specific +if ($ticketDetail['date_specific']['value']) { + + // Get Ticket Inventory as calendar data + $ticketCalendar = $TicketInventory->getTicketInventoryCalendarData(); + $this->page->ticketCalendar = $this->bindArrayToObject($ticketCalendar); + $this->addDebug("Ticket/inventory.inc", 'Array: $ticketCalendar', print_r($ticketCalendar,1)); + + $this->templateFile = 'Ticket/inventory.html'; + +} else { + + // Ticket is not date specific, so not using a calendar + $inventoryData = $TicketInventory->getTicketInventoryList(false, "ticket_date is null"); + $this->page->inventoryData = $this->bindArrayToObject($inventoryData); + $this->addDebug("Ticket/inventory.inc", 'Array: $inventoryData', print_r($inventoryData,1)); + $this->templateFile = 'Ticket/inventoryNoCalendar.html'; + +} + + +?> \ No newline at end of file diff --git a/models/admin/actions/Ticket/inventoryUpdate.inc b/models/admin/actions/Ticket/inventoryUpdate.inc new file mode 100644 index 0000000..b04fb1b --- /dev/null +++ b/models/admin/actions/Ticket/inventoryUpdate.inc @@ -0,0 +1,36 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: inventoryUpdate.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/ticketInventory.php'; +$TicketInventory = new EventManagementAdminTicketInventory($this->dbh, $this->config); + +// Process new record +$r = $TicketInventory->updateTicketInventory(); + +// If inventory is not date specific, simply redisplay form +if (isset($_REQUEST['dateSpecific'])) { + + // Redisplay form + $this->page->inventoryUpdated = true; + include(EVENT_MANAGEMENT_APP_BASE.'models/admin/actions/Ticket/inventory.inc'); + +} else { + + $this->templateFile = false; // No response expected + + $this->addDebug("Ticket/inventoryUpdate.inc", 'Array: $r', print_r($r,1)); + +} + +?> \ No newline at end of file diff --git a/models/admin/actions/Ticket/list.inc b/models/admin/actions/Ticket/list.inc new file mode 100644 index 0000000..425dbf7 --- /dev/null +++ b/models/admin/actions/Ticket/list.inc @@ -0,0 +1,46 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: list.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/tickets.php'; +$Tickets = new EventManagementAdminTickets($this->dbh, $this->config); + +// Get Tickets stats +$ticketsStats = $Tickets->getTicketsStats(); +$this->page->ticketsStats = $this->bindArrayToObject($ticketsStats); + +// If this is a member user then make sure they only list their own member tickets +$type = false; +$id = false; +if ($_SESSION[GLM_EVENT_SESSION]['MemberUser']) { + $type = 'member'; + $id = $this->page->userMemberID; + // Also specify current memberID for other uses + $this->page->memberID = $id; + +// Otherwise if we already have a member selected they pass that for other uses +} elseif ($_SESSION[GLM_EVENT_SESSION]['Member'] != false) { + $this->page->memberID = $_SESSION[GLM_EVENT_SESSION]['Member']; +} else { + $this->page->memberID = false; +} + +// Get tickets list +$tickets = $Tickets->getTicketsList($id, false, false, $type, false, false, true); +$this->page->tickets = $this->bindArrayToObject($tickets); + +$this->templateFile = 'Ticket/list.html'; + +$this->addDebug("Ticket/list.inc", 'Array: $tickets', print_r($tickets,1)); + +?> \ No newline at end of file diff --git a/models/admin/actions/Ticket/printSampleVoucher.inc b/models/admin/actions/Ticket/printSampleVoucher.inc new file mode 100644 index 0000000..dbf0b11 --- /dev/null +++ b/models/admin/actions/Ticket/printSampleVoucher.inc @@ -0,0 +1,145 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: printSampleVoucher.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +// Get supplied ticket ID to use for test +$testTicket = $_REQUEST['testTicket'] - 0; + +// Check for Coupon Test only +$couponTest = false; +if (isset($_REQUEST['testCoupons']) && $_REQUEST['testCoupons'] == 'true') { + $couponTest = true; +} + +// Get Ticket Detail +require_once EVENT_MANAGEMENT_APP_BASE.'classes/data/dataTickets.php'; +$Tickets = new EventManagementDataTickets($this->dbh, $this->config); +$Tickets->optionIncludeSelectListData = false; +$ticketDetail = $Tickets->getTicketDetail($testTicket); + +// Get Section Detail +require_once EVENT_MANAGEMENT_APP_BASE.'classes/data/dataSections.php'; +$Sections = new EventManagementDataSections($this->dbh, $this->config); +$Sections->optionIncludeSelectListData = false; +$sectionDetail = $Sections->getSectionDetail($ticketDetail['section_id']); + +// Get Member Detail +require_once EVENT_MANAGEMENT_APP_BASE.'classes/data/dataMembers.php'; +$Members = new EventManagementDataMembers($this->dbh, $this->config); +$Members->optionIncludeSelectListData = false; +$memberDetail = $Members->getMemberDetail($ticketDetail['member']); + +// Get Performance Detail +require_once EVENT_MANAGEMENT_APP_BASE.'classes/data/dataPerformances.php'; +$Performances = new EventManagementDataPerformances($this->dbh, $this->config); +$Performances->optionIncludeSelectListData = false; +$performanceDetail = $Performances->getPerformanceDetail($ticketDetail['performance_id']); + +// Sample Order Detail +$orderDetail = array( + 'id' => 12345678, + 'user_trace_info' => $_SERVER["REMOTE_ADDR"]." - ".date("m/d/Y H:i:s"), + 'fname' => 'John', + 'lname' => 'Smith', + 'addr1' => '120 E. Lake St.', + 'addr2' => 'Apt 123', + 'city' => 'Petoskey', + 'state' => 'MI', + 'country' => 'US', + 'zip' => '49770', + 'phone' => '231-487-0692', + 'email' => 'info@gaslightmedia.com', + 'email_ok' => true, + 'purchase_date' => date('m/d/Y'), + 'member' => $memberDetail['id'], + 'member_name' => $memberDetail['name'], + 'cctype' => 'VISA', + 'ccnumber' => '0011001100110011', + 'expire' => '01/19', + 'ccname' => 'JOHN SMITH', + 'ccconf' => '12312', + 'charge_numb' => 123.45, + 'charge_total' => '$123.45', + 'special_needs' => 'No special needs', + 'notes' => '' +); + +// Sample Tickets Sold List +$soldList = array( + 0 => array( + 'id' => 12345678, + 'ticket_order' => 11223344, + 'member' => $memberDetail['id'], + 'member_name' => $memberDetail['name'], + 'performance' => $performanceDetail['id'], + 'performance_name' => $performanceDetail['name'], + 'entrance' => 123, + 'entrance_name' => 'Test Entrance', + 'entrance_color' => '#FFB6C1', + 'section' => $sectionDetail['name'], + 'ticket' => $testTicket, + 'ticket_name' => $ticketDetail['title'], + 'date_specific' => $ticketDetail['date_specific'], + 'ticket_date' => array( + 'date' => ($ticketDetail['date_specific'] ? date('m/d/Y') : 'Use any date') + ), + 'ticket_time' => array( + 'time' => ($ticketDetail['time_specific'] ? '12:00 PM' : 'Use any time') + ), + 'start_date' => array('date' => $ticketDetail['start_date']), + 'end_date' => array('date' => $ticketDetail['end_date']['date']), + 'likely_date' => array('date' => '06/13/14'), + 'price_paid' => $this->money($ticketDetail['price']), + 'time_claimed' => false + ), + 1 => array( + 'id' => 12345679, + 'ticket_order' => 11223345, + 'member' => $memberDetail['id'], + 'member_name' => $memberDetail['name'], + 'performance' => $performanceDetail['id'], + 'performance_name' => $performanceDetail['name'], + 'entrance' => 123, + 'entrance_name' => 'Test Entrance', + 'entrance_color' => '#FFB6C1', + 'section' => $sectionDetail['name'], + 'ticket' => $testTicket, + 'ticket_name' => $ticketDetail['title'], + 'date_specific' => $ticketDetail['date_specific'], + 'ticket_date' => array( + 'date' => ($ticketDetail['date_specific'] ? date('m/d/Y') : 'Use any date') + ), + 'ticket_time' => array( + 'time' => ($ticketDetail['time_specific'] ? '12:00 PM' : 'Use any time') + ), + 'start_date' => array('date' => $ticketDetail['start_date']), + 'end_date' => array('date' => $ticketDetail['end_date']['date']), + 'likely_date' => array('date' => '06/13/14'), + 'price_paid' => $this->money($ticketDetail['price']), + 'time_claimed' => date('m/d/Y h:i:s A') + ), +); + +// Load voucher design code as per the "voucher_design" config parameter in the site's config/applications/EventManagement.ini file +if (is_file(EVENT_MANAGEMENT_APP_BASE.'models/vouchers/'.$this->config->voucher_design.'/voucher.php')) { + require_once EVENT_MANAGEMENT_APP_BASE.'models/vouchers/'.$this->config->voucher_design.'/voucher.php'; + $pdf = new PdfVoucher($orderDetail, $soldList, $memberDetail, $this->dbh, $this->config, $couponTest); +} else { + echo "SYSTEM ERROR: Site is not configured with a valid voucher design file."; + exit; +} + +// There's nothing to do from here. Output should go direct to browser. +exit; + +?> \ No newline at end of file diff --git a/models/admin/actions/Ticket/selected.inc b/models/admin/actions/Ticket/selected.inc new file mode 100644 index 0000000..28f4ad6 --- /dev/null +++ b/models/admin/actions/Ticket/selected.inc @@ -0,0 +1,50 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: selected.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/tickets.php'; +$Tickets = new EventManagementAdminTickets($this->dbh, $this->config); + +$ticketDetail = $Tickets->getTicketDetail(); +$this->page->ticketPackage = ($ticketDetail['ticket_type']['value']==20); +$this->page->ticketDetail = $this->bindArrayToObject($ticketDetail); + +$_SESSION[GLM_EVENT_SESSION]['Performance'] = $ticketDetail['performance_id']; + +// Also get Ticket inventory Stats - and check if none exist for this ticket +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/ticketInventory.php'; +$TicketInventory = new EventManagementAdminTicketInventory($this->dbh, $this->config); +$ticketInventoryStats = $TicketInventory->getTicketTicketInventoryStats($ticketDetail['id']); + +// Check if we have inventory or need to create it +$this->page->noTicketInventory = true; +if ($ticketInventoryStats > 0) { + $this->page->noTicketInventory = false; +} else { + + // Try to create default ticket inventory + $TicketInventory->generateDefaultTicketInventory(); + + // Get inventory stats again + $ticketInventoryStats = $TicketInventory->getTicketTicketInventoryStats($ticketDetail['id']); + + if ($ticketInventoryStats > 0) { + $this->page->noTicketInventory = false; + } +} + +$this->templateFile = 'Ticket/selected.html'; + +$this->addDebug("Ticket/selected.inc", 'Ticket Detail', print_r($ticketDetail,1)); + +?> \ No newline at end of file diff --git a/models/admin/actions/Ticket/setActive.inc b/models/admin/actions/Ticket/setActive.inc new file mode 100644 index 0000000..956f028 --- /dev/null +++ b/models/admin/actions/Ticket/setActive.inc @@ -0,0 +1,28 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: setActive.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +// Get ticket inventory ID and desired status +$ticketInventoryID = ($_REQUEST['TicketInventoryID'] - 0); +$ticketInventoryStatus = ($_REQUEST['TicketInventoryStatus'] - 0); // 0 if false, 1 if true +if ($ticketInventoryID > 0 && $ticketInventoryStatus > -1 && $ticketInventoryStatus < 2) { + $active = ($ticketInventoryStatus == 1 ? 'true' : 'false'); + $sql = "UPDATE eventmgt.ticket_inventory SET active = $active WHERE id = $ticketInventoryID;"; + $this->dbh->exec($sql); +} + +$this->templateFile = false; // No response expected + +$this->addDebug("Ticket/setActive.inc", "ID: $ticketInventoryID, Set active to: $active
    "); + +?> \ No newline at end of file diff --git a/models/admin/actions/Ticket/update.inc b/models/admin/actions/Ticket/update.inc new file mode 100644 index 0000000..12c7f5e --- /dev/null +++ b/models/admin/actions/Ticket/update.inc @@ -0,0 +1,56 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: update.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/tickets.php'; +$Tickets = new EventManagementAdminTickets($this->dbh, $this->config); + +// Process new record +$r = $Tickets->updateTicket(); + +// Get success status, false = fail +$status = $r['status']; +$this->page->formFail = !$status; + +$this->page->ticketDetail = $this->bindArrayToObject($r['fieldData']); +$this->page->fieldRequired = $this->bindArrayToObject($r['fieldRequired']); +$this->page->fieldFail = $this->bindArrayToObject($r['fieldFail']); + +// Get currently stored data for fields that are display only +$ticketDetail = $Tickets->getTicketDetail(); +$this->page->storedDetail = $this->bindArrayToObject($ticketDetail); + +// Check for changes in selected package tickets +require_once EVENT_MANAGEMENT_APP_BASE.'classes/data/dataTicketPackages.php'; +$TicketPackages = new EventManagementDataTicketPackages($this->dbh, $this->config); +$this->page->isPackage = false; +if ($ticketDetail['ticket_type']['value'] == 20) { + $packageData = $TicketPackages->updatePackageTicketsList($ticketDetail['id']); + $this->page->isPackage = true; + $this->page->ticketPackage = $this->bindArrayToObject($packageData); +// Otherwise make sure there's no package tickets +} else { + $TicketPackages->clearPackageTicketsList($ticketDetail['id']); +} + +// If invalid submission +if (!$status) { + $this->page->editingTicket = true; + $this->templateFile = 'Ticket/edit.html'; +} else { + $this->templateFile = 'Ticket/detail.html'; +} + +$this->addDebug("Ticket/update.inc", 'Array: $r', print_r($r,1)); + +?> diff --git a/models/admin/actions/User/login.inc b/models/admin/actions/User/login.inc new file mode 100644 index 0000000..362fc44 --- /dev/null +++ b/models/admin/actions/User/login.inc @@ -0,0 +1,17 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: login.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +$this->templateFile = 'User/loginForm.html'; + +?> \ No newline at end of file diff --git a/models/admin/actions/VoucherCoupon/add.inc b/models/admin/actions/VoucherCoupon/add.inc new file mode 100755 index 0000000..11e6573 --- /dev/null +++ b/models/admin/actions/VoucherCoupon/add.inc @@ -0,0 +1,30 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: add.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/voucherCoupons.php'; +$VoucherCoupons = new EventManagementAdminVoucherCoupons($this->dbh, $this->config); + +$r = $VoucherCoupons->newVoucherCoupon(); + +$this->page->voucherCouponDetail = $this->bindArrayToObject($r['fieldData']); +$this->page->fieldRequired = $this->bindArrayToObject($r['fieldRequired']); +$this->page->fieldFail = $this->bindArrayToObject($r['fieldFail']); + +$this->page->addingNewVoucherCoupon = true; + +$this->templateFile = 'VoucherCoupon/edit.html'; + +$this->addDebug("VoucherCoupon/add.inc", 'Array: $r', print_r($r,1)); + +?> \ No newline at end of file diff --git a/models/admin/actions/VoucherCoupon/confirmDelete.inc b/models/admin/actions/VoucherCoupon/confirmDelete.inc new file mode 100755 index 0000000..b8b7deb --- /dev/null +++ b/models/admin/actions/VoucherCoupon/confirmDelete.inc @@ -0,0 +1,26 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: confirmDelete.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/voucherCoupons.php'; +$VoucherCoupons = new EventManagementAdminVoucherCoupons($this->dbh, $this->config); + +$voucherCouponDetail = $VoucherCoupons->voucherCouponDelete(true); +$this->page->voucherCouponDetail = $this->bindArrayToObject($voucherCouponDetail); + +$this->templateFile = 'VoucherCoupon/detail.html'; + +$this->addDebug("VoucherCoupon/confirmDelete.inc", 'Section Confirm Delete', print_r($voucherCouponDetail,1)); + +?> + diff --git a/models/admin/actions/VoucherCoupon/delete.inc b/models/admin/actions/VoucherCoupon/delete.inc new file mode 100755 index 0000000..44811c3 --- /dev/null +++ b/models/admin/actions/VoucherCoupon/delete.inc @@ -0,0 +1,26 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: delete.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/voucherCoupons.php'; +$VoucherCoupons = new EventManagementAdminVoucherCoupons($this->dbh, $this->config); + +$voucherCouponDetail = $VoucherCoupons->voucherCouponDelete(false); +$this->page->voucherCouponDetail = $this->bindArrayToObject($voucherCouponDetail); + +$this->templateFile = 'VoucherCoupon/delete.html'; + +$this->addDebug("VoucherCoupon/delete.inc", 'Array: $$voucherCouponDetail', print_r($voucherCouponDetail,1)); + +?> + diff --git a/models/admin/actions/VoucherCoupon/detail.inc b/models/admin/actions/VoucherCoupon/detail.inc new file mode 100644 index 0000000..9724e8e --- /dev/null +++ b/models/admin/actions/VoucherCoupon/detail.inc @@ -0,0 +1,26 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: detail.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/voucherCoupons.php'; +$VoucherCoupons = new EventManagementAdminVoucherCoupons($this->dbh, $this->config); + +// Get Voucher Coupon detail +$voucherCouponDetail = $VoucherCoupons->getVoucherCouponDetail(); +$this->page->voucherCouponDetail = $this->bindArrayToObject($voucherCouponDetail); + +$this->templateFile = 'VoucherCoupon/detail.html'; + +$this->addDebug("VoucherCoupon/detail.inc", 'Array: $voucherCouponDetail', print_r($voucherCouponDetail,1)); + +?> \ No newline at end of file diff --git a/models/admin/actions/VoucherCoupon/edit.inc b/models/admin/actions/VoucherCoupon/edit.inc new file mode 100755 index 0000000..f036c3a --- /dev/null +++ b/models/admin/actions/VoucherCoupon/edit.inc @@ -0,0 +1,27 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: edit.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/voucherCoupons.php'; +$VoucherCoupons = new EventManagementAdminVoucherCoupons($this->dbh, $this->config); + +$voucherCouponDetail = $VoucherCoupons->editVoucherCoupon(); +$this->page->voucherCouponDetail = $this->bindArrayToObject($voucherCouponDetail); + +$this->page->editingVoucherCoupon = true; + +$this->templateFile = 'VoucherCoupon/edit.html'; + +$this->addDebug("VoucherDetail/edit.inc", 'Array: $voucherCouponDetail', print_r($voucherCouponDetail,1)); + +?> \ No newline at end of file diff --git a/models/admin/actions/VoucherCoupon/insert.inc b/models/admin/actions/VoucherCoupon/insert.inc new file mode 100755 index 0000000..6509fe9 --- /dev/null +++ b/models/admin/actions/VoucherCoupon/insert.inc @@ -0,0 +1,43 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: insert.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/voucherCoupons.php'; +$VoucherCoupons = new EventManagementAdminVoucherCoupons($this->dbh, $this->config); + +// Process new record +$r = $VoucherCoupons->insertVoucherCoupon(); + +// Get success status, false = fail +$status = $r['status']; +$this->page->formFail = !$status; + +$this->page->voucherCouponDetail = $this->bindArrayToObject($r['fieldData']); +$this->page->fieldRequired = $this->bindArrayToObject($r['fieldRequired']); +$this->page->fieldFail = $this->bindArrayToObject($r['fieldFail']); + +// If invalid submission +if (!$status) { + $this->page->addingNewVoucherCoupon = true; + $this->templateFile = 'VoucherCoupon/edit.html'; +} else { + + $voucherCouponID = $r['fieldData']['id']; + + $this->templateFile = 'VoucherCoupon/selected.html'; +} + +$this->addDebug("VoucherCoupon/insert.inc", 'Array: $r', print_r($r,1)); + + +?> \ No newline at end of file diff --git a/models/admin/actions/VoucherCoupon/list.inc b/models/admin/actions/VoucherCoupon/list.inc new file mode 100755 index 0000000..f2e2414 --- /dev/null +++ b/models/admin/actions/VoucherCoupon/list.inc @@ -0,0 +1,30 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: list.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/voucherCoupons.php'; +$VoucherCoupons = new EventManagementAdminVoucherCoupons($this->dbh, $this->config); + +// Get Voucher Coupon stats +$voucherCouponStats = $VoucherCoupons->getVoucherCouponsStats(); +$this->page->voucherCouponStats = $this->bindArrayToObject($voucherCouponStats); + +// Get Voucher Coupons list +$voucherCouponsList = $VoucherCoupons->getVoucherCouponList(); +$this->page->voucherCoupons = $this->bindArrayToObject($voucherCouponsList); + +$this->templateFile = 'VoucherCoupon/list.html'; + +$this->addDebug("VoucherCoupon/list.inc", 'Array: $voucherCouponsList', print_r($voucherCouponsList, 1)); + +?> \ No newline at end of file diff --git a/models/admin/actions/VoucherCoupon/selected.inc b/models/admin/actions/VoucherCoupon/selected.inc new file mode 100755 index 0000000..a303ff0 --- /dev/null +++ b/models/admin/actions/VoucherCoupon/selected.inc @@ -0,0 +1,25 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: selected.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/voucherCoupons.php'; +$VoucherCoupons = new EventManagementAdminVoucherCoupons($this->dbh, $this->config); + +$voucherCouponDetail = $VoucherCoupons->getVoucherCouponDetail(); +$this->page->voucherCouponDetail = $this->bindArrayToObject($voucherCouponDetail); + +$this->templateFile = 'VoucherCoupon/selected.html'; + +$this->addDebug("VoucherCoupon/selected.inc", 'Voucher Coupon Detail', print_r($voucherCouponDetail,1)); + +?> \ No newline at end of file diff --git a/models/admin/actions/VoucherCoupon/test.inc b/models/admin/actions/VoucherCoupon/test.inc new file mode 100755 index 0000000..e1a5dc8 --- /dev/null +++ b/models/admin/actions/VoucherCoupon/test.inc @@ -0,0 +1,25 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: test.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/voucherCoupons.php'; +$VoucherCoupons = new EventManagementAdminVoucherCoupons($this->dbh, $this->config); + +$voucherCouponDetail = $VoucherCoupons->newVoucherCoupon(); +$this->page->voucherCouponDetail = $this->bindArrayToObject($voucherCouponDetail); + +$this->templateFile = 'VoucherCoupon/test.html'; + +$this->addDebug("VoucherDetail/test.inc", 'Array: $voucherCouponDetail', print_r($voucherCouponDetail,1)); + +?> \ No newline at end of file diff --git a/models/admin/actions/VoucherCoupon/update.inc b/models/admin/actions/VoucherCoupon/update.inc new file mode 100755 index 0000000..defc044 --- /dev/null +++ b/models/admin/actions/VoucherCoupon/update.inc @@ -0,0 +1,38 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: update.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/voucherCoupons.php'; +$VoucherCoupons = new EventManagementAdminVoucherCoupons($this->dbh, $this->config); + +// Process new record +$r = $VoucherCoupons->updateVoucherCoupon(); + +// Get success status, false = fail +$status = $r['status']; +$this->page->formFail = !$status; + +$this->page->voucherCouponDetail = $this->bindArrayToObject($r['fieldData']); +$this->page->fieldRequired = $this->bindArrayToObject($r['fieldRequired']); +$this->page->fieldFail = $this->bindArrayToObject($r['fieldFail']); + +// If invalid submission +if (!$status) { + $this->page->editingVoucherCoupon = true; + $this->templateFile = 'VoucherCoupon/edit.html'; + $this->addDebug("VoucherCoupon/update.inc", 'Array: $r', print_r($r,1)); +} else { + require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/actions/VoucherCoupon/detail.inc'; +} + +?> \ No newline at end of file diff --git a/models/admin/actions/inventory/add.inc b/models/admin/actions/inventory/add.inc new file mode 100644 index 0000000..1907907 --- /dev/null +++ b/models/admin/actions/inventory/add.inc @@ -0,0 +1,40 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: event.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/inventory.php'; +$Inventory = new EventManagementAdminInventory($this->dbh, $this->config); + + +// Check for member ID supplied and force to a number +$this->page->defMember = false; +if (isset($_REQUEST['member'])) { + $this->page->defMember = ($_REQUEST['member'] - 0); +} + +$r = $Inventory->addInven(); + +if (isset($r['reason'])) { + $this->reason = array_merge($this->reason, $r['reason']); +} + +$this->page->invenDetail = $this->bindArrayToObject($r['fieldData']); +$this->page->fieldRequired = $this->bindArrayToObject($r['fieldRequired']); +$this->page->fieldFail = $this->bindArrayToObject($r['fieldFail']); +$this->page->membAccom = $this->bindArrayToObject($r['membAccom']); + +$this->page->addingNewInven = true; + +$this->templateFile = 'Inventory/EditInventory.html'; + +?> \ No newline at end of file diff --git a/models/admin/actions/inventory/detail.inc b/models/admin/actions/inventory/detail.inc new file mode 100644 index 0000000..af25856 --- /dev/null +++ b/models/admin/actions/inventory/detail.inc @@ -0,0 +1,27 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: event.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/inventory.php'; +$Inventory = new EventManagementAdminInventory($this->dbh, $this->config); + + +// Get inventory itme detail +$invenDetail = $Inventory->getInvenDetail(); +$this->page->invenDetail = $this->bindArrayToObject($invenDetail); + +$this->templateFile = 'Inventory/InventoryDetail.html'; + +$this->addDebug("Inventory/detail.inc", 'Inventory Detail', print_r($invenDetail,1)); + +?> \ No newline at end of file diff --git a/models/admin/actions/inventory/edit.inc b/models/admin/actions/inventory/edit.inc new file mode 100644 index 0000000..055f28c --- /dev/null +++ b/models/admin/actions/inventory/edit.inc @@ -0,0 +1,31 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: event.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/inventory.php'; +$Inventory = new EventManagementAdminInventory($this->dbh, $this->config); + + +$invenDetail = $Inventory->editInven(); +$this->page->invenDetail = $this->bindArrayToObject($invenDetail); + +// We need this to mimic stored detail for edit templates that show this on entry to edit +$this->page->storedDetail = $this->bindArrayToObject($invenDetail); + +$this->page->editingInven = true; + +$this->templateFile = 'Inventory/EditInventory.html'; + +$this->addDebug("Inventory/edit.inc", 'Edit Inventory', print_r($invenDetail,1)); + +?> \ No newline at end of file diff --git a/models/admin/actions/inventory/insert.inc b/models/admin/actions/inventory/insert.inc new file mode 100644 index 0000000..4452cee --- /dev/null +++ b/models/admin/actions/inventory/insert.inc @@ -0,0 +1,48 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: event.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/inventory.php'; +$Inventory = new EventManagementAdminInventory($this->dbh, $this->config); + + +// Process new record +$r = $Inventory->insertInven(); + +if (isset($r['reason'])) { + $this->reason = array_merge($this->reason, $r['reason']); +} + +// Get success status, false = fail +$status = $r['status']; +$this->page->formFail = !$status; + +$this->page->invenDetail = $this->bindArrayToObject($r['fieldData']); +$this->page->fieldRequired = $this->bindArrayToObject($r['fieldRequired']); +$this->page->fieldFail = $this->bindArrayToObject($r['fieldFail']); +$this->page->membSelected = $this->bindArrayToObject($r['membSelected']); +$this->page->membAccom = $this->bindArrayToObject($r['membAccom']); +// $this->page->lt = '<'; // needed to avoid breaking javascript + +// If invalid submission +if (!$status) { + $this->page->addingNewInven = true; + $this->templateFile = 'Inventory/EditInventory.html'; +} else { + // Inventory added, so display data on the last inventory item stored. + $invenDetail = $Inventory->getInvenDetail($r['insertedID']); + $this->page->invenDetail = $this->bindArrayToObject($invenDetail); + $this->templateFile = 'Inventory/InventoryDetail.html'; +} + +?> \ No newline at end of file diff --git a/models/admin/actions/inventory/list.inc b/models/admin/actions/inventory/list.inc new file mode 100644 index 0000000..05e6bc1 --- /dev/null +++ b/models/admin/actions/inventory/list.inc @@ -0,0 +1,68 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: event.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/inventory.php'; +$Inventory = new EventManagementAdminInventory($this->dbh, $this->config); + + +// Get inventory stats +$invenStats = $Inventory->getInvenStats(); +$this->page->invenStats = $this->bindArrayToObject($invenStats); + +// Get inventory list +$i = $Inventory->getInvenList(); +$inventory = $i['inventory']; + +// If there's member results, then sort them +if (is_array($i['sum'])) { + // Sort members under each event listed + function sortByMember($a, $b) + { + if ($a['name'] > $b['name']) { + return 1; + } elseif ($b['name'] > $a['name']) { + return -1; + } + return 0; + } + while (list($k, $v) = each($i['sum'])) { + uasort($v['memb'], 'sortByMember'); + $i['sum'][$k] = $v; + } +} + +$this->page->inventoryList = $this->bindArrayToObject($inventory); +$this->page->dates = $this->bindArrayToObject($i['dates']); +if ($i['have_sum']) { + $this->page->summary = $this->bindArrayToObject($i['sum']); +} + +$this->page->have_summary = $i['have_sum']; + +$d = getdate($i['firstDate']); + +$this->page->firstInventoryDay = $d['mday']; +$this->page->firstInventoryMonth = $d['mon'] - 1; +$this->page->firstInventoryYear = $d['year']; + +if ($i['type'] == 'Summary') { + $this->templateFile = 'Inventory/InventoryListSummary.html'; +} else { + $this->page->memberName = $i['inventory'][0]['member']; + $this->templateFile = 'Inventory/InventoryListCalendar.html'; +} + +$this->addDebug("Inventory/list.inc", 'Inventory List', print_r($i,1)); + +?> \ No newline at end of file diff --git a/models/admin/actions/inventory/selected.inc b/models/admin/actions/inventory/selected.inc new file mode 100644 index 0000000..e2fbd3e --- /dev/null +++ b/models/admin/actions/inventory/selected.inc @@ -0,0 +1,49 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: selected.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/tickets.php'; +$Tickets = new EventManagementAdminTickets($this->dbh, $this->config); + +$ticketDetail = $Tickets->getTicketDetail(); +$this->page->ticketDetail = $this->bindArrayToObject($ticketDetail); + +$_SESSION[GLM_EVENT_SESSION]['Performance'] = $ticketDetail['performance_id']; + +// Also get Ticket inventory Stats - and check if none exist for this ticket +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/ticketInventory.php'; +$TicketInventory = new EventManagementAdminTicketInventory($this->dbh, $this->config); +$ticketInventoryStats = $TicketInventory->getTicketTicketInventoryStats($ticketDetail['id']); + +// Check if we have inventory or need to create it +$this->page->noTicketInventory = true; +if ($ticketInventoryStats > 0) { + $this->page->noTicketInventory = false; +} else { + + // Try to create default ticket inventory + $TicketInventory->generateDefaultTicketInventory(); + + // Get inventory stats again + $ticketInventoryStats = $TicketInventory->getTicketTicketInventoryStats($ticketDetail['id']); + + if ($ticketInventoryStats > 0) { + $this->page->noTicketInventory = false; + } +} + +$this->templateFile = 'Ticket/selected.html'; + +$this->addDebug("Ticket/selected.inc", 'Ticket Detail', print_r($ticketDetail,1)); + +?> \ No newline at end of file diff --git a/models/admin/actions/inventory/update.inc b/models/admin/actions/inventory/update.inc new file mode 100644 index 0000000..f7e6cd0 --- /dev/null +++ b/models/admin/actions/inventory/update.inc @@ -0,0 +1,50 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: event.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/inventory.php'; +$Inventory = new EventManagementAdminInventory($this->dbh, $this->config); + + +// Process new record +$r = $Inventory->updateInven(); + +// Get success status and reasons and save to add after getInvenDetail() below +$status = $r['status']; +$reason = $r['reason']; +$this->page->formFail = !$status; + +$this->page->invenDetail = $this->bindArrayToObject($r['fieldData']); +$this->page->fieldRequired = $this->bindArrayToObject($r['fieldRequired']); +$this->page->fieldFail = $this->bindArrayToObject($r['fieldFail']); + + +// If invalid submission +if (!$status) { + $this->reason = $r['reason']; + $this->page->storedDetail = $this->bindArrayToObject($r); + $this->page->editingInven = true; + $this->templateFile = 'Inventory/EditInventory.html'; + +} else { + + // Get currently stored data for fields that are display only + $invenDetail = $Inventory->getInvenDetail(); + $this->page->storedDetail = $this->bindArrayToObject($invenDetail); + $this->templateFile = 'Inventory/InventoryDetail.html'; + +} + +$this->addDebug("Inventory/update.inc", 'Update Inventory', print_r($feeDetail,1)); + +?> \ No newline at end of file diff --git a/models/admin/classes/accommodations.php b/models/admin/classes/accommodations.php new file mode 100644 index 0000000..8aea93c --- /dev/null +++ b/models/admin/classes/accommodations.php @@ -0,0 +1,80 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: classes/accommodations.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'classes/data/dataAccoms.php'; + +/** + * EventManagementAdminAccoms class + * + * Event Management and Reservations System - Admin Code - Accommodations section + * + * PHP version 5 + * + * @category Event Management Admin Accommodations + * @package EventManagement + * @author Chuck Scott + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: classes/accommodations.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + * @link http://www.gaslightmedia.com/admin/EventManagement + */ +class EventManagementAdminAccoms extends EventManagementDataAccoms +{ + /** + * Configuration information object + * @var $ini + * @access public + */ + public $config; + /** + * Database Object + * @var $dbh + * @access public + */ + public $dbh; + /** + * File/Image server adapter + * @var $isa + * @var $imageServer + * @access public + */ + + /** + * Get Accommodations Stats + * + * @return object containing array as sub-objects + */ + function getMemberAccomsStats() + { + // Get member ID from session - if available get stats for member + if (($memberID = $_SESSION[GLM_EVENT_SESSION]['Member'])) { + return $this->getStats("member = $memberID"); + } + return 0; + } + function getAccomsStats() + { + $accomsStats = array( + 'all' => $this->getStats(), + 'member' => $this->getMemberAccomsStats() + ); + + return $accomsStats; + } + + +} + +?> + diff --git a/models/admin/classes/addons.php b/models/admin/classes/addons.php new file mode 100644 index 0000000..d37d165 --- /dev/null +++ b/models/admin/classes/addons.php @@ -0,0 +1,81 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: classes/addons.php,v 1.0 2011/01/25 19:31:47 cscott Exp $ + * @link <> + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'classes/data/dataAddons.php'; + +/** + * EventManagementAdminAddons class + * + * Event Management and Reservations System - Admin Code - Add-Ons section + * + * PHP version 5 + * + * @category Event Management Admin Add-Ons + * @package EventManagement + * @author Chuck Scott + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: classes/addons.php,v 1.0 2011/01/25 19:31:47 cscott Exp $ + * @link <> + */ +class EventManagementAdminAddons extends EventManagementDataAddons +{ + /** + * Configuration information object + * @var $config + * @access public + */ + public $config; + /** + * Database Object + * @var $dbh + * @access public + */ + public $dbh; + /** + * Data Definitions Object + * @var $data + * @access public + */ + public $data; + + /** + * Get Add-Ons Stats + * + * @return object containing array as sub-objects + */ + function getTicketAddonsStats($ticketID = false) + { + // Get ticket ID from session - if available get stats for ticket Add-ons + if ($ticketID || ($ticketID = $_SESSION[GLM_EVENT_SESSION]['Ticket'])) { + return $this->getStats("ticket = $ticketID"); + } + return 0; + } + function getAddonStats() + { + $addonStats = array( + 'all' => $this->getStats(), + 'ticket' => $this->getTicketAddonStats() + ); + + return $addonStats; + } + + + +} + +?> \ No newline at end of file diff --git a/models/admin/classes/addonsSold.php b/models/admin/classes/addonsSold.php new file mode 100644 index 0000000..1dd1073 --- /dev/null +++ b/models/admin/classes/addonsSold.php @@ -0,0 +1,57 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: classes/addonsSold.php,v 1.0 2011/01/25 19:31:47 cscott Exp $ + * @link <> + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'classes/data/dataAddonSold.php'; + +/** + * EventManagementAdminAddonsSold class + * + * Event Management and Reservations System - Admin Code - Sold Ticket add-ons + * + * PHP version 5 + * + * @category Event Management Admin Tickets + * @package EventManagement + * @author Chuck Scott + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: classes/addonsSold.php,v 1.0 2011/01/25 19:31:47 cscott Exp $ + * @link <> + */ + +class EventManagementAdminAddonsSold extends EventManagementDataAddonSold +{ + /** + * Configuration information object + * @var $ini + * @access public + */ + public $config; + /** + * Database Object + * @var $dbh + * @access public + */ + public $dbh; + /** + * Data Definitions Object + * @var $dbh + * @access public + */ + public $data; + + +} + +?> \ No newline at end of file diff --git a/models/admin/classes/attendance.php b/models/admin/classes/attendance.php new file mode 100755 index 0000000..1d92d3d --- /dev/null +++ b/models/admin/classes/attendance.php @@ -0,0 +1,70 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: classes/addons.php,v 1.0 2011/01/25 19:31:47 cscott Exp $ + * @link <> + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'classes/data/dataAttendance.php'; + +/** + * EventManagementAdminAttendance class + * + * Event Management and Reservations System - Admin Code - Attendance section + * + * PHP version 5 + * + * @category Event Management Admin Attendance + * @package EventManagement + * @author Chuck Scott + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: classes/attendance.php,v 1.0 2011/01/25 19:31:47 cscott Exp $ + * @link <> + */ +class EventManagementAdminAttendance extends EventManagementDataAttendance +{ + /** + * Configuration information object + * @var $config + * @access public + */ + public $config; + /** + * Database Object + * @var $dbh + * @access public + */ + public $dbh; + /** + * Data Definitions Object + * @var $data + * @access public + */ + public $data; + + /** + * Get Attendance Stats + * + * @return object containing array as sub-objects + */ + function getAttendanceStats($performanceID = false) + { + // Get performance ID from session + if ($performanceID || ($performanceID = $_SESSION[GLM_EVENT_SESSION]['Performance'])) { + return $this->getStats("performance = $performanceID"); + } + return 0; + } + +} + +?> \ No newline at end of file diff --git a/models/admin/classes/blocks.php b/models/admin/classes/blocks.php new file mode 100644 index 0000000..f5f36d0 --- /dev/null +++ b/models/admin/classes/blocks.php @@ -0,0 +1,1025 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: classes/blocks.php,v 1.0 2011/01/25 19:31:47 cscott Exp $ + * @link <> + */ + +/** + * EventManagementAdminBookings class + * + * Event Management and Reservations System - Admin Code - Bookings section + * + * PHP version 5 + * + * @category Event Management Admin Members + * @package EventManagement + * @author Chuck Scott + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: classes/bookings.php,v 1.0 2011/01/25 19:31:47 cscott Exp $ + * @link <> + * + * NOTE: This class does not currently have a DataBlocks class to extend + * because we don't seem to want the lower-level data definitions for this class. + */ +class EventManagementAdminBlocks +{ + /** + * Configuration information object + * @var $ini + * @access public + */ + public $config; + /** + * Database Object + * @var $dbh + * @access public + */ + public $dbh; + /** + * File/Image server adapter + * @var $isa + * @var $imageServer + * @access public + */ + public $data; + + /** + * File/Image server adapter + * @var $isa + * @var $imageServer + * @access public + */ + + /** + * Constructor + * + * @param object $d database connection + * + * @return void + * @access public + */ + function __construct($dbh, $config) + { + + $this->dbh = $dbh; + $this->config = $config; + + } + + /** + * Get Blocks Summary + * + * @return object containing array as sub-objects + */ + function getBlocksSummary($event = false, $sort = true) + { + + // Check for valid Event + if ($event) { + $eventID = $event; + } elseif (isset($_SESSION[GLM_EVENT_SESSION]['Event'])) { + // Get the event ID from the session + $eventID = $_SESSION[GLM_EVENT_SESSION]['Event']; + } else { + // Otherwise, we don't have a member id + return false; + } + + // Need to make sure this is a team event - Don't do blocks for a non-team event! + $sql = "SELECT team_event FROM eventmgt.event WHERE id = $eventID"; + $stmt = $this->dbh->prepare($sql); + $stmt->execute(); + $event = $stmt->fetch(PDO::FETCH_ASSOC); + if (!$event['team_event']) { + return false; + } + + // Get list of Members (properties) along with blocks and inventory stats + $sql = " + SELECT R.id AS memb_id, + R.name AS memb_name, + M.street AS addr, + M.lat, + M.lon, + C.city_name AS city, + A.id AS accom_id, + A.name AS accom_name, + I.assigned AS rooms, + ( SELECT COUNT(B.id) FROM eventmgt.room_block B WHERE B.member = R.id AND B.conv = $eventID ) AS room_blocks, + COALESCE (S.block, 0) AS block_numb, + COALESCE (S.allocated, 0) AS allocated, + ( SELECT COUNT(B.block_name) FROM eventmgt.room_block B WHERE B.member = R.id AND b.conv = $eventID ) AS block_count + FROM eventmgt.member R, + member.member M, + inventory I, + city C, + accommodation A + LEFT OUTER JOIN room_block_seg S ON (S.accommodation = A.id AND S.conv = $eventID) + WHERE I.member = R.id + AND A.member = R.id + AND I.accommodation = A.id + AND I.conv = $eventID + AND M.member_id = R.id + AND C.city_id = M.city_id + GROUP BY R.id, A.id, I.assigned, R.name, M.street, M.lat, M.lon, C.city_name, A.name, S.block, S.allocated + ORDER BY R.name, A.id + ;"; + $stmt = $this->dbh->prepare($sql); + $stmt->execute(); + $memb_data = $stmt->fetchAll(PDO::FETCH_ASSOC); + + // If there's no results then fail + if (!$memb_data) { + return false; + } + + // Add distances to the member data and sort by distance + if(class_exists('EventManagementGeoCalculations') != true) { + require '../../classes/GeoCalculations.php'; + } + $Geo = new EventManagementGeoCalculations($this->dbh); + $memb_data = $Geo->getMemberEventDistance( $eventID, $memb_data, 'lat', 'lon', 'distance', 'duration', 'memb_id', $sort); + + // Compile summary from list + $r = array(); + foreach ($memb_data as $m) { + + // If member entry has not been created + if (!isset($r[$m['memb_id']])) { + + $r[$m['memb_id']] = array( + 'id' => $m['memb_id'], + 'name' => addslashes($m['memb_name']), + 'distance' => $m['distance'], + 'street' => $m['addr'], + 'city' => $m['city'], + 'blocks' => $m['room_blocks'], + 'rooms' => 0, + 'allocated' => 0, + 'unallocated' => 0, + 'all_allocated' => false, + 'alert' => false, + 'accom' => array() + ); + } + + // If accommodation entry has not been created + if (!isset($r[$m['memb_id']]['accom'][$m['accom_id']])) { + + // Add this accomodation + $r[$m['memb_id']]['accom'][$m['accom_id']] = array( + 'id' => $m['accom_id'], + 'name' => $m['accom_name'], + 'rooms' => $m['rooms'], + 'allocated' => 0, + 'all_allocated' => false, + 'alert' => false + ); + + $r[$m['memb_id']]['rooms'] += $m['rooms']; + $r[$m['memb_id']]['unallocated'] += $m['rooms']; + + } + // tally assingments and allocation for this member + $r[$m['memb_id']]['allocated'] += $m['allocated']; + $r[$m['memb_id']]['unallocated'] -= $m['allocated']; + if ($r[$m['memb_id']]['unallocated'] <= 0) { + $r[$m['memb_id']]['all_allocated'] = true; + } + + // Check for mixed inventory levels across dates for this accommodation + if ($r[$m['memb_id']]['accom'][$m['accom_id']]['rooms'] != $m['rooms']) { + // Oops! We have multiple results for the same accommodation with different assigned inventory levels. + // This means we don't have the same amount of inventory assigned for all of the dates + // User must check inventory for this accommodation for this event + $r[$m['memb_id']]['accom'][$m['accom_id']]['alert'] = true; + $r[$m['memb_id']]['alert'] = true; + } + + // Insert allocated data for this block + $r[$m['memb_id']]['accom'][$m['accom_id']]['allocated'] += $m['allocated']; + if ($r[$m['memb_id']]['accom'][$m['accom_id']]['rooms'] - $r[$m['memb_id']]['accom'][$m['accom_id']]['allocated'] <= 0) { + $r[$m['memb_id']]['accom'][$m['accom_id']]['all_allocated'] = true; + } + + } + + // echo "getBlocksSummary()

    ".print_r($r,1)."
    "; + return $r; + + + } + + /** + * Get Blocks Detail and Management Screen + * + * @return object containing array as sub-objects + */ + function getBlocksDetail() + { + // Check for valid Event + if (isset($_SESSION[GLM_EVENT_SESSION]['Event'])) { + // Get the event ID from the session + $eventID = $_SESSION[GLM_EVENT_SESSION]['Event']; + } else { + // Otherwise, we don't have a member id + return false; + } + + // Need to make sure this is a team event - Don't do blocks for a non-team event! + $sql = "SELECT team_event FROM eventmgt.event WHERE id = $eventID"; + $stmt = $this->dbh->prepare($sql); + $stmt->execute(); + $event = $stmt->fetch(PDO::FETCH_ASSOC); + if (!$event['team_event']) { + return false; + } + + // Get the specified Member + if (!($membID = filter_input(INPUT_GET, 'MemberID', FILTER_SANITIZE_NUMBER_INT))) { + return false; + } + $sql = "SELECT name FROM eventmgt.member WHERE id = $membID"; + $stmt = $this->dbh->prepare($sql); + $stmt->execute(); + $memberData = $stmt->fetch(PDO::FETCH_ASSOC); + + // Get inventory data for this member for this event + $sql = " + SELECT DISTINCT(I.assigned) AS rooms, + A.id AS accom_id, + A.name AS accom_name, + a.sort + FROM eventmgt.inventory I, eventmgt.accommodation A + WHERE I.member = $membID + AND I.conv = $eventID + AND A.id = I.accommodation + ORDER BY A.sort + ;"; + $stmt = $this->dbh->prepare($sql); + $stmt->execute(); + $accom_data = $stmt->fetchAll(PDO::FETCH_ASSOC); + + // Build accommodation type array and short version array to use for building block data + $accoms = array(); + $a_array = array(); + $a_count = 1; + foreach ($accom_data as $a) { + + // Check for duplicate accommodation type - indicates inconsistent quantities + if (isset($a_array[$a['accom_id']])) { + $accoms[$a['accom_id']]['alert'] = true; + } + + $accoms[$a['accom_id']] = array( + 'accom_numb' => $a_count, + 'id' => $a['accom_id'], + 'name' => $a['accom_name'], + 'rooms' => $a['rooms'], + 'alert' => false + ); + + $a_array[$a['accom_id']] = array( + 'accom_numb' => $a_count, + 'id' => false, + 'allocated' => 0, + 'accom_id' => $a['accom_id'], + ); + + $a_count++; + + } + + // Get all related block data + $sql = " + SELECT R.id AS block_id, + R.block_name AS block_name, + R.state_rep AS state_rep, + coalesce((SELECT code FROM eventmgt.state_rep P WHERE P.id = R.state_rep), '') AS state_code, + R.team AS team, + S.id AS seg_id, + S.accommodation AS accom_id, + S.allocated AS allocated + FROM eventmgt.room_block R, eventmgt.room_block_seg S + WHERE R.member = $membID + AND R.conv = $eventID + AND S.block = R.id + ;"; + $stmt = $this->dbh->prepare($sql); + $stmt->execute(); + $block_segs = $stmt->fetchAll(PDO::FETCH_ASSOC); + + // Build list of blocks with assignments + $blocks = array(); + $blockCounter = 1; + foreach ($block_segs as $s) { + + // If the block hasn't been created yet + if (!isset($blocks[$s['block_id']])) { + $blocks[$s['block_id']] = array( + 'block_numb' => $blockCounter++, + 'id' => $s['block_id'], + 'name' => $s['block_name'], + 'segments' => $a_array, + 'assigned' => $s['state_code'] + ); + } + + // Add this segment to the block + $blocks[$s['block_id']]['segments'][$s['accom_id']] = array( + 'accom_numb' => $accoms[$s['accom_id']]['accom_numb'], + 'id' => $s['seg_id'], + 'allocated' => $s['allocated'], + 'accom_id' => $s['accom_id'] + ); + + } + + $r = array( + 'memberID' => $membID, + 'memberName' => $memberData['name'], + 'accomData' => $accoms, + 'blockData' => $blocks, + 'lineLength' => (count($accoms)+1), + 'numbAccoms' => count($accoms), + 'nextBlock' => $blockCounter, + 'nextBlock2' => ($blockCounter +1) + ); + + $this->addDebug("classes/blocks.inc", 'getBlocksDetail()', print_r($r,1)); + + return $r; + + } + + /** + * Update Blocks Detail and Management Screen + * + * @return object containing array as sub-objects + */ + function updateBlocksDetail() + { + // Assume everything works fine + $status = true; + + // Check for valid Event + if (isset($_SESSION[GLM_EVENT_SESSION]['Event'])) { + // Get the event ID from the session + $eventID = $_SESSION[GLM_EVENT_SESSION]['Event']; + } else { + // Otherwise, we don't have a member id + return false; + } + + // Need to make sure this is a team event - Don't do blocks for a non-team event! + $sql = "SELECT team_event FROM eventmgt.event WHERE id = $eventID"; + $stmt = $this->dbh->prepare($sql); + $stmt->execute(); + $event = $stmt->fetch(PDO::FETCH_ASSOC); + if (!$event['team_event']) { + return false; + } + + // Get the specified Member + if (!($membID = filter_input(INPUT_POST, 'MemberID', FILTER_SANITIZE_NUMBER_INT))) { + return false; + } + + // Get accomodation/inventory data for this member for this event + $sql = " + SELECT DISTINCT(I.assigned) AS rooms, + A.id AS accom_id, + A.name AS accom_name, + a.sort + FROM eventmgt.inventory I, eventmgt.accommodation A + WHERE I.member = $membID + AND I.conv = $eventID + AND A.id = I.accommodation + ORDER BY A.sort + ;"; + $stmt = $this->dbh->prepare($sql); + $stmt->execute(); + $accom_data = $stmt->fetchAll(PDO::FETCH_ASSOC); + + // Build accommodation type array + $accoms = array(); + $a_array = array(); + $a_count = 1; + foreach ($accom_data as $a) { + + // Check for duplicate accommodation type - indicates inconsistent quantities + if (isset($a_array[$a['accom_id']])) { + $accoms[$a['accom_id']]['alert'] = true; + } + + $accoms[$a_count] = array( + 'accom_numb' => $a_count, + 'id' => $a['accom_id'], + 'name' => $a['accom_name'], + 'rooms' => $a['rooms'], + 'alert' => false + ); + + $a_count++; + + } + + // Get existing room block data for this event/member + $sql = " + SELECT * + FROM eventmgt.room_block + WHERE conv = $eventID + AND member = $membID + ORDER BY id + ;"; + $stmt = $this->dbh->prepare($sql); + $stmt->execute(); + $block_data = $stmt->fetchAll(PDO::FETCH_ASSOC); + + // For each block submitted + $blocks = array(); + $block = 1; + while (isset($_REQUEST['seg_'.$block.'_1'])) { + + // Create an entry for this block + $blocks[$block] = array( + 'numb' => $block, + 'block_id' => false, + 'sql' => false, + 'segs' => array() + ); + + // For each accommodation + for ($accom=1 ; $accom<$a_count ; $accom++) { + + // Create an entry for this accom + $blocks[$block]['segs'][$accom] = array( + 'numb' => $accom, + 'seg_id' => false, + 'sql' => false, + 'new_block' => false, + 'quant' => 0 + ); + + // Check if there was an existing entry + if ( isset($_REQUEST['current_'.$block.'_'.$accom]) && + ($current = filter_input(INPUT_POST, 'current_'.$block.'_'.$accom, FILTER_SANITIZE_STRING, FILTER_FLAG_NO_ENCODE_QUOTES))) { + $x = explode(',', $current); + $blocks[$block]['block_id'] = $x[0]; + $blocks[$block]['segs'][$accom]['seg_id'] = $x[1]; + } + + // Get inventory quantity for this segment + if (($quant = filter_input(INPUT_POST, 'seg_'.$block.'_'.$accom, FILTER_SANITIZE_NUMBER_INT))) { + $blocks[$block]['segs'][$accom]['quant'] = $quant; + } + + } + + $block++; + } + + // Get some data on the existing blocks + $sql = "SELECT MAX(state_rep) AS max_rep, + MAX(team) AS max_team, + MAX(block_name) AS max_name + FROM eventmgt.room_block + WHERE conv = $eventID + ;"; + $stmt = $this->dbh->prepare($sql); + $stmt->execute(); + $block_stats = $stmt->fetch(PDO::FETCH_ASSOC); + $next_block_name = $block_stats['max_name'] + 1; + + // We should now have all the block and segment data so start building queries to update - for each block + $sql = array(); + foreach ($blocks as $b) { + + $block_total = 0; // Total number of rooms for this block + + // For each block segment + foreach ($b['segs'] as $s) { + + // Add the number of rooms in this segment to the block total + $block_total += $s['quant']; + + // If the segment is already in the database - update it + if ($s['seg_id']) { + + // If the segment now 0 then delete it + if ($s['quant'] == false || $s['quant'] == 0) { + $blocks[$b['numb']]['segs'][$s['numb']]['sql'] = "DELETE FROM eventmgt.room_block_seg WHERE id = ".$s['seg_id'].";"; + + // Otherwise we're going to update it + } else { + $blocks[$b['numb']]['segs'][$s['numb']]['sql'] = "UPDATE room_block_seg SET allocated = ".$s['quant'].", available = ".$s['quant']." WHERE id = ".$s['seg_id'].";"; + } + + // Othewise it's a new segment and it's not 0 add it + } elseif ($s['quant'] != false && $s['quant'] > 0) { + + // If we already have a block ID, use the block number + if ($blocks[$b['numb']]['block_id'] != false) { + $bval = $blocks[$b['numb']]['block_id']; + + // Otherwise we'll be adding the block so use the last sequence value for the block ID + } else { + $bval = "currval('room_block_id_seq')"; + } + + // Create the block segement insert query + $blocks[$b['numb']]['segs'][$s['numb']]['sql'] = " + INSERT INTO eventmgt.room_block_seg + (block, conv, accommodation, allocated, available) + VALUES + ($bval, $eventID, ".$accoms[$s['numb']]['id'].", ".$s['quant'].", ".$s['quant'].") + ;"; + } + + } + + // If block is empty + if ($block_total == 0) { + + // If the block existed, then delete it + if ($b['block_id'] != false) { + $blocks[$b['numb']]['sql'] = "DELETE FROM eventmgt.room_block WHERE id = ".$b['block_id'].";"; + } + + // Otherwise if this is a new block + } elseif ($b['block_id'] == false) { + $blocks[$b['numb']]['sql'] = " + INSERT INTO eventmgt.room_block + (conv, member, state_rep, team, block_name) + VALUES + ($eventID, $membID, 0, 0, ".$next_block_name++.") + ;"; + $blocks[$b['numb']]['new_block'] = true; + + } // Note that we don't have to update the block record if it's going to stay + + } + + // Now try to run the queries + reset($blocks); + try { + $this->dbh->beginTransaction(); + + // For each block + foreach ($blocks as $b) { + + // if there's a query + if ($b['sql'] != false) { + $this->dbh->exec($b['sql']); + } + + // for each segment + foreach ($b['segs'] as $s) { + + // if there's a query + if ($s['sql'] != false) { + $this->dbh->exec($s['sql']); + } + } + } + + $this->dbh->commit(); + + } catch (Exception $e) { + $this->dbh->rollBack(); + $status = false; + } + + // If there are no blocks assigned to state reps or teams yet it's OK to renumber + // Otherwise we're just going to add numbers + $renumber = false; + if ($block_stats['max_rep'] + $block_stats['max_team'] == 0) { + $renumber = true; + } + + // Get all blocks in the proper member order then in the order of their creation + $sql = "SELECT B.id, B.block_name, + M.member_id AS memb_id, M.member_name, M.lat, M.lon + FROM eventmgt.room_block B, members.member M + WHERE B.conv = $eventID + AND M.member_id = B.member + ORDER BY M.member_id, B.id + ;"; + $stmt = $this->dbh->prepare($sql); + $stmt->execute(); + $blocks = $stmt->fetchAll(PDO::FETCH_ASSOC); + + // If we have some room blocks + if (count($blocks) > 0) { + + // Add distances to the member data and sort by distance + require '../../classes/GeoCalculations.php'; + $Geo = new EventManagementGeoCalculations($this->dbh); + $blocks = $Geo->getMemberEventDistance( $eventID, $blocks, 'lat', 'lon', 'distance', 'duration', 'memb_id', true); + + // Renumber all blocks according to the current order - if we're allowed to renumber at this time + $block = 1; + if ($renumber) { + + try { + $this->dbh->beginTransaction(); + foreach ($blocks as $b) { + $this->dbh->exec("UPDATE room_block SET block_name = ".$block++." WHERE id = ".$b['id'].";"); + } + $this->dbh->commit(); + } catch (Exception $e) { + $this->dbh->rollBack(); + } + + } + + } + + // echo "updateBlocksDetail()
    ".print_r($blocks,1)."
    "; + return $status; + + } + + /** + * Get Room Blocks + * + * If summary is true, then also put all the data under the properties + * so all blocks show under the property as well. + * + * @return object containing array as sub-objects + */ + function getRoomBlocks($event = false, $sort = true, $summary = false, $state = false, $team = false, $property = false) + { + + // Make sure we have an event selected (shouldn't happen that we don't) + if ($event) { + $eventID = $event; + } elseif (isset($_SESSION[GLM_EVENT_SESSION]['Event'])) { + // Get the event ID from the session + $eventID = $_SESSION[GLM_EVENT_SESSION]['Event']; + } else { + // Otherwise, we don't have a member id + return false; + } + + // Get all State Reps for this event + $where = ''; + if ($state) { + $where = "AND id = $state"; + }; + if ($property) { + $where .= " AND id IN ( + SELECT DISTINCT state_rep FROM eventmgt.room_block + WHERE member = $property + )"; + } + + $sql = "SELECT id, code + FROM eventmgt.state_rep + WHERE conv = $eventID + $where + ORDER BY code;"; + $stmt = $this->dbh->prepare($sql); + $stmt->execute(); + $states_data = $stmt->fetchAll(PDO::FETCH_ASSOC); + $statesList = array(); + foreach ($states_data as $s) { + $statesList[$s['id']] = array( + 'id' => $s['id'], + 'code' => $s['code'] + ); + } + + // Get all Teams for this event and add under state reps array + $where = ''; + if ($state) { + $where .= " AND T.state = $state"; + }; + if ($team) { + $where .= " AND T.id = $team"; + }; + if ($property) { + $where .= " AND T.room_block IN ( + SELECT DISTINCT id FROM eventmgt.room_block + WHERE member = $property + )"; + } + + $sql = "SELECT T.id, T.name, T.team_code, T.state, D.name AS division + FROM eventmgt.team T, eventmgt.division D + WHERE T.conv = $eventID + AND D.id = T.division + $where + ORDER BY T.name;"; + $stmt = $this->dbh->prepare($sql); + $stmt->execute(); + $teams_data = $stmt->fetchAll(PDO::FETCH_ASSOC); + foreach ($teams_data as $t) { + $statesList[$t['state']]['teams'][$t['id']] = array( + 'id' => $t['id'], + 'name' => $t['name'], + 'team_code' => $t['team_code'] + ); + } + + // Get all existing Room Blocks for this event + $where = ''; + if ($state) { + $where .= " AND B.state_rep = $state"; + }; + if ($team) { + $where .= " AND B.team = $team"; + }; + if ($property) { + $where .= " AND R.id = $property"; + } + + + $sql = "SELECT B.id as block_id, + B.block_name, + B.state_rep, + B.team, + B.member AS memb_id, + R.name AS memb_name, + M.street AS street, + M.lat, + M.lon, + C.city_name AS city, + A.name AS accom_name, + S.allocated AS quant, + S.available AS available + FROM eventmgt.room_block B, eventmgt.member R, members.member M, members.city C, eventmgt.room_block_seg S, eventmgt.accommodation A + WHERE B.conv = $eventID + AND R.id = B.member + AND S.block = B.id + AND A.id = S.accommodation + AND C.city_id = M.city_id + AND M.member_id = R.id + $where + ORDER BY M.member_id, B.block_name, A.name;"; + $stmt = $this->dbh->prepare($sql); + $stmt->execute(); + $blocks_data = $stmt->fetchAll(PDO::FETCH_ASSOC); + + // Add distances to the member data and sort by distance + if(class_exists('EventManagementGeoCalculations') != true) { + require '../../classes/GeoCalculations.php'; + } + $Geo = new EventManagementGeoCalculations($this->dbh); + $blocks_data = $Geo->getMemberEventDistance( $eventID, $blocks_data, 'lat', 'lon', 'distance', 'duration', 'memb_id', $sort); + + if (!is_array($blocks_data) || count($blocks_data) == 0) { + return false; + } + reset($blocks_data); + + // Build room blocks list + $blocksList = array(); + foreach ($blocks_data as $b) { + + // If the Property (member) hasn't been added to the array yet + if (!isset($blocksList[$b['memb_id']])) { + $blocksList[$b['memb_id']] = array( + 'memb_id' => $b['memb_id'], + 'memb_name' => $b['memb_name'], + 'distance' => $b['distance'], + 'street' => $b['street'], + 'city' => $b['city'] + ); + } + + // Get assignement summary if assigned + $assigned = false; + $assigned_to_state = ''; + $assigned_to_team = ''; + if ($b['state_rep'] > 0) { + $assigned_to_state = $statesList[$b['state_rep']]['code']; + } + if ($b['team'] > 0 ) { + $assigned_to_team = $statesList[$b['state_rep']]['teams'][$b['team']]['name']; + $team_code = $statesList[$b['state_rep']]['teams'][$b['team']]['team_code']; + } + + // Build block info array + $block = array ( + 'block_id' => $b['block_id'], + 'block_name' => $b['block_name'], + 'memb_name' => $b['memb_name'], + 'memb_id' => $b['memb_id'], + 'accom_info' => + ''.$b['memb_name']."
    " + .$b['quant'].": ".$b['accom_name']."
    ", + 'accoms' => array($b['accom_name'] => array( + 'accom_name' => $b['accom_name'], 'quant' => $b['quant'], 'available' => $b['available'] + )), + 'accom_quant' => $b['quant'], + 'assigned' => $assigned, + 'assigned_to_state' => $assigned_to_state, + 'assigned_to_team' => $assigned_to_team, + 'team_code' => $team_code + ); + + // If block as been assigned to a team + if ($b['team'] > 0) { + + if (!isset($statesList[$b['state_rep']]['teams'][$b['team']]['blocks'][$b['block_id']])) { + $statesList[$b['state_rep']]['teams'][$b['team']]['blocks'][$b['block_id']] = $block; + } else { + $statesList[$b['state_rep']]['teams'][$b['team']]['blocks'][$b['block_id']]['accom_info'] .= $b['quant'].": ".$b['accom_name']."
    "; + $statesList[$b['state_rep']]['teams'][$b['team']]['blocks'][$b['block_id']]['accoms'][$b['accom_name']] = array( + 'accom_name' => $b['accom_name'], 'quant' => $b['quant'], 'available' => $b['available'] + ); + // Update sort of accoms array to keep it alphabetical + ksort($statesList[$b['state_rep']]['teams'][$b['team']]['blocks'][$b['block_id']]['accoms']); + } + + // Otherwise it must just be assigned to a state rep so far + } elseif ($b['state_rep'] > 0) { + + if (!isset($statesList[$b['state_rep']]['blocks'][$b['block_id']])) { + $statesList[$b['state_rep']]['blocks'][$b['block_id']] = $block; + } else { + $statesList[$b['state_rep']]['blocks'][$b['block_id']]['accom_info'] .= $b['quant'].": ".$b['accom_name']."
    "; + $statesList[$b['state_rep']]['blocks'][$b['block_id']]['accoms'][$b['accom_name']] = array( + 'accom_name' => $b['accom_name'], 'quant' => $b['quant'], 'available' => $b['available'] + ); + + ksort($statesList[$b['state_rep']]['blocks'][$b['block_id']]['accoms']); + } + + } + + // If the block is not assigned to either a state or team, or if we're running in summary mode, include under property. + if (($b['team'] == 0 && $b['state_rep'] == 0) || $summary) { + + if (!isset($blocksList[$b[memb_id]]['blocks'][$b['block_id']])) { + $blocksList[$b[memb_id]]['blocks'][$b['block_id']] = $block; + } else { + $blocksList[$b[memb_id]]['blocks'][$b['block_id']]['accom_info'] .= $b['quant'].": ".$b['accom_name']."
    "; + $blocksList[$b[memb_id]]['blocks'][$b['block_id']]['accoms'][$b['accom_name']] = array( + 'accom_name' => $b['accom_name'], 'quant' => $b['quant'], 'available' => $b['available'] + ); + // Update sort of accoms array to keep it alphabetical + ksort($blocksList[$b[memb_id]]['blocks'][$b['block_id']]['accoms']); + } + + } + + } + + // Check if there's no blocksList yet + if (count($blocksList) == 0) { + $blocksList = false; + } + + // Function to Sort all blocks by block_name (number) + function blockCmp($a, $b) { + + $aval = $a['block_name']; + $bval = $b['block_name']; + + if ($val == $bval) { + return 0; + } + return ($aval < $bval) ? -1 : 1; + } + + // Sort unasigned blocks + reset ($blocksList); + while (list($k, $v) = each($blocksList)) { + if (is_array($v['blocks'])) { + uasort($blocksList[$k]['blocks'], 'blockCmp'); + } + } + + // Sort blocks assigned to states or teams + reset ($statesList); + while (list($k, $v) = each($statesList)) { + + // Check for and sort any blocks not assigned to teams + if (is_array($v['blocks'])) { + uasort($statesList[$k]['blocks'], 'blockCmp'); + } + + // Check for any teams + if (is_array($v['teams'])) { + while (list($tk, $tv) = each($v['teams'])) { + if (is_array($tv['blocks'])) { + uasort($statesList[$k]['teams'][$tk]['blocks'], 'blockCmp'); + } + } + } + } + + // Sort accommodation types + + $r = array( + 'blocks' => $blocksList, + 'states' => $statesList + ); + + // echo "
    ".htmlentities(print_r($r,1))."
    "; + return $r; + } + + /** + * Save Room Blocks + * + * @return object containing array as sub-objects + */ + function saveRoomBlocks() + { + + // Make sure we have an event selected (shouldn't happen that we don't) + if (isset($_SESSION[GLM_EVENT_SESSION]['Event'])) { + // Get the event ID from the session + $eventID = $_SESSION[GLM_EVENT_SESSION]['Event']; + } else { + // Otherwise, we don't have a member id + return false; + } + + // Get room block drop list + $dropList = $_REQUEST['blocks']; + + // Separate into separate move requests + $drops = explode(',', $dropList); + + $sql = array(); + + // For each block moved + foreach ($drops as $d) { + + // separate the block id from the destination + $x = explode('|', $d); + $block = $x[0]; + + // separate the destination id from the type + $y = explode('_', $x[1]); + + // Set any state and team assignments for this block + $state = 'null'; + $team = 'null'; + switch ($y[0]) { + + case 'state': + + $state = ($y[1] - 0); + + if ($y[2] == 'team') { + $team = ($y[3] - 0); + } + + break; + + case 'member': + // If moved back to member, then there's no assignment + break; + + } + + if ($state == 0) { + $state = 'null'; + } + if ($team == 0) { + $team = 'null'; + + } + + $sql[] = " + UPDATE room_block + SET state_rep = $state, + team = $team + WHERE conv = $eventID + AND block_name = $block; + "; + } + + if (count($sql) > 0) { + try { + $this->dbh->beginTransaction(); + foreach ($sql as $s) { + $this->dbh->exec($s); + } + $this->dbh->commit(); + } catch (Exception $e) { + $this->dbh->rollBack(); + } + + } + + } + + +} + +?> \ No newline at end of file diff --git a/models/admin/classes/bookings.php b/models/admin/classes/bookings.php new file mode 100644 index 0000000..c85c779 --- /dev/null +++ b/models/admin/classes/bookings.php @@ -0,0 +1,102 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: classes/bookings.php,v 1.0 2011/01/25 19:31:47 cscott Exp $ + * @link <> + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'classes/data/dataBookings.php'; + +/** + * EventManagementAdminBookings class + * + * Event Management and Reservations System - Admin Code - Bookings section + * + * PHP version 5 + * + * @category Event Management Admin Members + * @package EventManagement + * @author Chuck Scott + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: classes/bookings.php,v 1.0 2011/01/25 19:31:47 cscott Exp $ + * @link <> + */ +class EventManagementAdminBookings extends EventManagementDataBookings +{ + /** + * Configuration information object + * @var $ini + * @access public + */ + public $config; + /** + * Database Object + * @var $dbh + * @access public + */ + public $dbh; + /** + * File/Image server adapter + * @var $isa + * @var $imageServer + * @access public + */ + public $data; + + /** + * File/Image server adapter + * @var $isa + * @var $imageServer + * @access public + */ + + + /** + * Get Members Stats + * + * @return object containing array as sub-objects + */ + function getBookingsStats() + { + $bookingsStats = array( + 'all' => $this->getStats(), + 'event' => 0, + 'member' => 0, + 'team' => 0 + ); + + // Get event ID from session - if available get stats for bookings listed with this event + if (($eventID = $_SESSION[GLM_EVENT_SESSION]['Event'])) { + $bookingsStats['event'] = $this->getStats(" + conv = $eventID + "); + } + + // Get member ID from session - if available get stats for bookings for this member + if (($memberID = $_SESSION[GLM_EVENT_SESSION]['Member'])) { + $bookingsStats['member'] = $this->getStats(" + property = $memberID + "); + } + + // Get team ID from session - if available get stats for bookings listed with this team + if (($teamID = $_SESSION[GLM_EVENT_SESSION]['Team'])) { + $bookingsStats['team'] = $this->getStats(" + team = $teamID + "); + } + + return $bookingsStats; + } + +} + +?> \ No newline at end of file diff --git a/models/admin/classes/contacts.php b/models/admin/classes/contacts.php new file mode 100644 index 0000000..422cd1f --- /dev/null +++ b/models/admin/classes/contacts.php @@ -0,0 +1,122 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: classes/contacts.php,v 1.0 2011/01/25 19:31:47 cscott Exp $ + * @link <> + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'classes/data/dataContacts.php'; + +/** + * EventManagementAdminContacts class + * + * Event Management and Reservations System - Admin Code - Contacts section + * + * PHP version 5 + * + * @category Event Management Admin Contacts + * @package EventManagement + * @author Chuck Scott + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: classes/contacts.php,v 1.0 2011/01/25 19:31:47 cscott Exp $ + * @link <> + */ +class EventManagementAdminContacts extends EventManagementDataContacts +{ + /** + * Configuration information object + * @var $ini + * @access public + */ + public $config; + /** + * Database Object + * @var $dbh + * @access public + */ + public $dbh; + /** + * Data Definitions Object + * @var $dbh + * @access public + */ + public $data; + + + /** + * Get Contacts Stats + * + * @return object containing array as sub-objects + */ + function getEventContactsStats() + { + // Check for selected Event + if (($eventID = $_SESSION[GLM_EVENT_SESSION]['Event'])) { + return $this->getStats(" + contact_type = ".$this->config->reference_type->event." + AND affiliation = $eventID + "); + } + return 0; + } + function getMemberContactsStats() + { + // Check for selected Member + if (($memberID = $_SESSION[GLM_EVENT_SESSION]['Member'])) { + return $this->getStats(" + contact_type = ".$this->config->reference_type->member." + AND affiliation = $memberID + "); + } + return 0; + } + function getStateContactsStats() + { + // Check for selected State Rep + if (($stateID = $_SESSION[GLM_EVENT_SESSION]['State'])) { + return $this->getStats(" + contact_type = ".$this->config->reference_type->state." + AND affiliation = $stateID + "); + } + return 0; + } + function getTeamContactsStats() + { + + // Check for selected Team + if (($teamID = $_SESSION[GLM_EVENT_SESSION]['Team'])) { + return $this->getStats(" + contact_type = ".$this->config->reference_type->team." + AND affiliation = $teamID + "); + } + return 0; + } + function getContactsStats() + { + + $contactsStats = array( + 'all' => $this->getStats(), + 'event' => $this->getEventContactsStats(), + 'member' => $this->getMemberContactsStats(), + 'state' => $this->getStateContactsStats(), + 'team' => $this->getTeamContactsStats() + ); + + return $contactsStats; + } + + +} + +?> \ No newline at end of file diff --git a/models/admin/classes/dataList.php b/models/admin/classes/dataList.php new file mode 100644 index 0000000..1719cbd --- /dev/null +++ b/models/admin/classes/dataList.php @@ -0,0 +1,188 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: classes/events.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + * @link <> + */ + +/** + * EventManagementAdminEvents class + * + * Event Management and Reservations System - Admin Code - Events section + * + * PHP version 5 + * + * @category Event Management Admin Events + * @package EventManagement + * @author Chuck Scott + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: classes/events.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + * @link <> + */ +class EventManagementAdminEvents +{ + /** + * Configuration information object + * @var $ini + * @access public + */ + public $config; + /** + * Database Object + * @var $dbh + * @access public + */ + public $dbh; + /** + * File/Image server adapter + * @var $isa + * @var $imageServer + * @access public + */ + + /** + * Constructor + * + * @param object $d database connection + * + * @return void + * @access public + */ + public function __construct($dbh, $config) + { + $this->dbh = $dbh; + $this->config = $config; + } + + + /** + * Get Events Stats + * + * @return object containing array as sub-objects + */ + function getEventsStats() + { + + // Get list of all available Events + $sql = "SELECT ( SELECT count(id) FROM eventmgt.event WHERE active ) AS active, + ( SELECT count(id) FROM eventmgt.event WHERE NOT active ) AS inactive + ;"; + + $stmt = $this->dbh->prepare($sql); + $stmt->execute(); + $eventsStats = $stmt->fetch(PDO::FETCH_ASSOC); + + return $eventsStats; + } + + /** + * Get Events list + * + * @param string type of events list + * + * @return object containing array as sub-objects + */ + function getEventsList() + { + + // Get any specified event listing option - default to active + $option = 'active'; + if (($eventsListOption = filter_input(INPUT_GET, 'EventsListOption', FILTER_SANITIZE_STRING))) { + $option = $eventsListOption; + } + + // Clear Session Event Selection + $_SESSION[GLM_EVENT_SESSION]['Event'] = false; + + // Select type of list + $where = ''; + switch ($option) { + case 'all': + $where = 'true'; + break; + case 'active': + $where = "active AND end_date > 'now'"; + break; + case 'inactive': + $where = "NOT active AND end_date > 'now'"; + break; + case 'expired': + $where = "active AND end_date < 'now'"; + break; + case 'archived': + $where = "NOT active AND end_date < 'now'"; + break; + default: + echo "Option not set"; + break; + } + + // Get list of all available Events + $sql = "SELECT id, name, event_code, start_date, end_date, cutoff_date + FROM eventmgt.event + WHERE $where + ;"; + $stmt = $this->dbh->prepare($sql); + $stmt->execute(); + $eventsList = $stmt->fetchAll(PDO::FETCH_ASSOC); + + if (count($eventsList) == 0) + return false; + return $eventsList; + } + + /** + * Get Event Detail + * + * Returns an array of event detail data for an event. + * + * @param array $array of values to convert + * + * @return object containing array as sub-objects + */ + function getEventDetail() + { + // Is there a new event code selected? + if (($eventID = filter_input(INPUT_GET, 'EventID', FILTER_SANITIZE_NUMBER_INT))) { + + // If so then add it to the session + $_SESSION[GLM_EVENT_SESSION]['Event'] = $eventID; + + } elseif (isset($_SESSION[GLM_EVENT_SESSION]['Event'])) { + + // Otherwise, get the event ID from the session + $eventID = $_SESSION[GLM_EVENT_SESSION]['Event']; + + } else { + + // Otherwise, we don't have an event id + return false; + + } + + $sql = "SELECT * + FROM eventmgt.event + WHERE id = '$eventID';"; + + $stmt = $this->dbh->prepare($sql); + $stmt->execute(); + $eventDetail = $stmt->fetch(PDO::FETCH_ASSOC); + + return $eventDetail; + } + + + +} + +?> + diff --git a/models/admin/classes/divisions.php b/models/admin/classes/divisions.php new file mode 100644 index 0000000..f88d22e --- /dev/null +++ b/models/admin/classes/divisions.php @@ -0,0 +1,87 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: classes/divisions.php,v 1.0 2011/01/25 19:31:47 cscott Exp $ + * @link <> + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'classes/data/dataDivisions.php'; + +/** + * EventManagementAdminDivisions class + * + * Event Management and Reservations System - Admin Code - Divisions section + * + * PHP version 5 + * + * @category Event Management Admin Members + * @package EventManagement + * @author Chuck Scott + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: classes/divisions.php,v 1.0 2011/01/25 19:31:47 cscott Exp $ + * @link <> + */ +class EventManagementAdminDivisions extends EventManagementDataDivisions +{ + /** + * Configuration information object + * @var $ini + * @access public + */ + public $config; + /** + * Database Object + * @var $dbh + * @access public + */ + public $dbh; + /** + * File/Image server adapter + * @var $isa + * @var $imageServer + * @access public + */ + public $data; + + /** + * File/Image server adapter + * @var $isa + * @var $imageServer + * @access public + */ + + + /** + * Get State Divisions + * + * @return object containing array as sub-objects + */ + function getDivisionsStats() + { + $divisionsStats = array( + 'all' => $this->getStats(), + 'event' => 0, + 'state' => 0 + ); + + // Get event ID from session - if available get stats for teams listed with this event + if (($eventID = $_SESSION[GLM_EVENT_SESSION]['Event'])) { + $divisionsStats['event'] = $this->getStats(" + conv = $eventID + "); + } + + return $divisionsStats; + } + +} + +?> \ No newline at end of file diff --git a/models/admin/classes/entrances.php b/models/admin/classes/entrances.php new file mode 100644 index 0000000..a863ca6 --- /dev/null +++ b/models/admin/classes/entrances.php @@ -0,0 +1,81 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: classes/entrances.php,v 1.0 2011/01/25 19:31:47 cscott Exp $ + * @link <> + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'classes/data/dataEntrances.php'; + +/** + * EventManagementAdminContacts class + * + * Event Management and Reservations System - Admin Code - Entrances section + * + * PHP version 5 + * + * @category Event Management Admin Entrances + * @package EventManagement + * @author Chuck Scott + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: classes/entrances.php,v 1.0 2011/01/25 19:31:47 cscott Exp $ + * @link <> + */ +class EventManagementAdminEntrances extends EventManagementDataEntrances +{ + /** + * Configuration information object + * @var $ini + * @access public + */ + public $config; + /** + * Database Object + * @var $dbh + * @access public + */ + public $dbh; + /** + * Data Definitions Object + * @var $dbh + * @access public + */ + public $data; + + /** + * Get Entrances Stats + * + * @return object containing array as sub-objects + */ + function getMemberEntrancesStats($memberID = false) + { + // Get member ID from session - if available get stats for member + if ($memberID || ($memberID = $_SESSION[GLM_EVENT_SESSION]['Member'])) { + return $this->getStats("member = $memberID"); + } + return 0; + } + function getEntrancesStats() + { + $entrancesStats = array( + 'all' => $this->getStats(), + 'member' => $this->getMemberEntrancesStats() + ); + + return $entrancesStats; + } + + + +} + +?> \ No newline at end of file diff --git a/models/admin/classes/eventFees.php b/models/admin/classes/eventFees.php new file mode 100644 index 0000000..0218d87 --- /dev/null +++ b/models/admin/classes/eventFees.php @@ -0,0 +1,86 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: classes/eventFees.php,v 1.0 2011/01/25 19:31:47 cscott Exp $ + * @link <> + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'classes/data/dataFees.php'; + +/** + * EventManagementAdminStates class + * + * Event Management and Reservations System - Admin Code - Event Fees Section + * + * PHP version 5 + * + * @category Event Management Admin Members + * @package EventManagement + * @author Chuck Scott + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: classes/eventFees.php,v 1.0 2011/01/25 19:31:47 cscott Exp $ + * @link <> + */ +class EventManagementAdminEventFees extends EventManagementDataFees +{ + /** + * Configuration information object + * @var $ini + * @access public + */ + public $config; + /** + * Database Object + * @var $dbh + * @access public + */ + public $dbh; + /** + * File/Image server adapter + * @var $isa + * @var $imageServer + * @access public + */ + public $data; + + /** + * File/Image server adapter + * @var $isa + * @var $imageServer + * @access public + */ + + + /** + * Get Event Fees Stats + * + * @return object containing array as sub-objects + */ + function getEventFeesStats() + { + $eventFeesStats = array( + 'all' => $this->getStats(), + 'event' => 0 + ); + + // Get event ID from session - if available get stats for teams listed with this event + if (($eventID = $_SESSION[GLM_EVENT_SESSION]['Event'])) { + $eventFeesStats['event'] = $this->getStats(" + owner = $eventID + "); + } + + return $eventFeesStats; + } + +} + +?> \ No newline at end of file diff --git a/models/admin/classes/eventReport.php b/models/admin/classes/eventReport.php new file mode 100644 index 0000000..a091d24 --- /dev/null +++ b/models/admin/classes/eventReport.php @@ -0,0 +1,206 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: classes/eventReport.php,v 1.0 2011/01/25 19:31:47 cscott Exp $ + * @link <> + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'classes/data/Reports/dataEventReport.php'; + +/** + * EventManagementAdminEvents class + * + * Event Management and Reservations System - Admin Code - Event Report section + * + * PHP version 5 + * + * @category Event Management Admin Events + * @package EventManagement + * @author Chuck Scott + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: classes/events.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + * @link <> + */ +class EventManagementAdminEventReport extends EventManagementDataEventReport +{ + /** + * Configuration information object + * @var $ini + * @access public + */ + public $config; + /** + * Database Object + * @var $dbh + * @access public + */ + public $dbh; + /** + * Data Definitions Object + * @var $dbh + * @access public + */ + public $data; + + /** + * File/Image server adapter + * @var $isa + * @var $imageServer + * @access public + */ + + function __construct($dbh, $config) + { + parent::__construct($dbh, $config); + } + + /** + * Get Report Request Form + * + * @return object containing array as sub-objects + */ + function getForm() + { + + $reportData = array( + 'status' => true, + 'reason' => array(), + 'form' => array() + ); + + $reportData['form'] = $this->newControls(); + + return $reportData; + } + + /** + * Process Report + * + * @return object containing array as sub-objects + */ + function getReport() + { + + $reportData = array( + 'status' => true, + 'output' => false, + 'reason' => array(), + 'report' => array() + ); + + /* + * Try to process report form request + */ + $request = $this->processInputData(); + if (!$request['status']) { + $reportData['status'] = false; + + if ($request['fieldFail']['event_name']) { + $reportData['reason'][] = 'An event was not selected'; + } + + if ($request['fieldFail']['output_type']) { + $reportData['reason'][] = 'An output type was not selected'; + } + + } + + // Get selections + $r = $request['fieldData']; + $event = $r['event_name']['in']; + $statistics = $r['statistics_section']['value']; + $contacts = $r['contacts_section']['value']; + $housing = $r['housing_section']['value']; + $housing_available_only = $r['housing_available_only']['value']; + $housing_summary_only = $r['housing_summary_only']['value']; + $reservations = $r['reservations_section']['value']; + $reservations_summary_only = $r['reservations_summary_only']['value']; + $reportData['output'] = $r['output_type']['value']; + + // If the request is valid - Produce the report + if ($reportData['status']) { + + /* + * Get report data + */ + + // Get Event data + $sql = "SELECT * FROM eventmgt.event WHERE id = $event;"; + $stmt = $this->dbh->prepare($sql); + $stmt->execute(); + $eventData = $stmt->fetch(PDO::FETCH_ASSOC); + $reportData['report']['event'] = $eventData; + + // Get Statistics + $reportData['report']['doingStatistics'] = $statistics; + if ($statistics) { + // Not built yet + } + + // Get Contacts + $reportData['report']['doingContacts'] = $contacts; + if ($contacts) { + require_once EVENT_MANAGEMENT_APP_BASE.'classes/data/dataContacts.php'; + $Contacts = new EventManagementDataContacts($this->dbh, $this->config); + $where = "T.contact_type = ".$this->config->reference_type->event." AND affiliation = $event"; + $contactsList = $Contacts->getList($where); + $reportData['report']['contacts'] = $contactsList; + } + + // Get Housing and Inventory + + $reportData['report']['doingHousing'] = $housing; + $reportData['report']['showAllInventoryDataDetail'] = !$housing_available_only; + $reportData['report']['showHousingDetail'] = !$housing_summary_only; + if ($housing) { + require_once EVENT_MANAGEMENT_APP_BASE.'classes/data/dataInventory.php'; + $Inventory = new EventManagementDataInventory($this->dbh, $this->config); + $inventoryList = $Inventory->getInvenList('event', $event); + + // Sort inventory by summary + function sortByMember($a, $b) + { + if ($a['name'] > $b['name']) { + return 1; + } elseif ($b['name'] > $a['name']) { + return -1; + } + return 0; + } + while (list($k, $v) = each($inventoryList['sum'])) { + uasort($v['memb'], 'sortByMember'); + $inventoryList['sum'][$k] = $v; + } + + $reportData['report']['housing'] = $inventoryList; + } + + // Get Reservations - Use existing report class for reservations + $reportData['report']['doingReservations'] = $reservations; + $reportData['report']['showReservationsDetail'] = !$reservations_summary_only; + if ($reservations) { + require 'reservationReport.php'; + $Reservations = new EventManagementAdminReservationReport($this->dbh, $this->config); + $reservationsList = $Reservations->getReport($event); + $reportData['report']['reservations'] = $reservationsList['report']; + } + + } + + return $reportData; + } + + + +} + +?> \ No newline at end of file diff --git a/models/admin/classes/events.php b/models/admin/classes/events.php new file mode 100644 index 0000000..2fa7625 --- /dev/null +++ b/models/admin/classes/events.php @@ -0,0 +1,153 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: classes/events.php,v 1.0 2011/01/25 19:31:47 cscott Exp $ + * @link <> + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'classes/data/dataEvents.php'; + +/** + * EventManagementAdminEvents class + * + * Event Management and Reservations System - Admin Code - Events section + * + * PHP version 5 + * + * @category Event Management Admin Events + * @package EventManagement + * @author Chuck Scott + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: classes/events.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + * @link <> + */ +class EventManagementAdminEvents extends EventManagementDataEvents +{ + /** + * Configuration information object + * @var $ini + * @access public + */ + public $config; + /** + * Database Object + * @var $dbh + * @access public + */ + public $dbh; + /** + * Data Definitions Object + * @var $dbh + * @access public + */ + public $data; + + /** + * File/Image server adapter + * @var $isa + * @var $imageServer + * @access public + */ + + + /** + * Get Events Stats + * + * @return object containing array as sub-objects + */ + function getEventsStats() + { + $eventsStats = array( + 'all' => $this->getStats(), + 'active' => $this->getStats('active'), + 'inactive' => $this->getStats('NOT active'), + 'expired' => $this->getStats("active AND end_date < 'now'"), + 'archived' => $this->getStats("NOT active AND end_date < 'now'"), + 'member' => 0, + 'team' => 0 + ); + + // Get member ID from session - if available get stats for events for this member + if (($memberID = $_SESSION[GLM_EVENT_SESSION]['Member'])) { + $eventsStats['member'] = $this->getStats(" + id IN ( + SELECT DISTINCT event + FROM eventmgt.inventory + WHERE member = $memberID + ) + "); +/* Trying to not use event_prop table for this + $eventsStats['member'] = $this->getStats(" + id IN ( + SELECT DISTINCT event + FROM eventmgt.event_prop + WHERE property = $memberID + ) + "); +*/ + } + + // Get team ID from session - if available get stats for bookings listed with this team + if (($teamID = $_SESSION[GLM_EVENT_SESSION]['Team'])) { + $bookingsStats['team'] = $this->getStats(" + id IN ( + SELECT DISTINCT event + FROM eventmgt.team_property + WHERE team = $teamID + ) + "); + } + + return $eventsStats; + } + + /** + * Get Member Events + * + * @return object containing array as sub-objects + */ + function getMemberEvents() + { + // Get member ID + if (isset($_SESSION[GLM_EVENT_SESSION]['Member'])) { + // Get the event ID from the session + $memberID = $_SESSION[GLM_EVENT_SESSION]['Member']; + } else { + // Otherwise, we don't have a member id + return false; + } + + // Only look for events for the specified property + $where = "T.id IN ( + SELECT DISTINCT event + FROM eventmgt.inventory + WHERE member = $memberID + )"; +/* Trying to not use event_prop table for this + $where = "T.id IN ( + SELECT event + FROM eventmgt.event_prop + WHERE property = $memberID + )"; +*/ + $memberEvents = $this->getEventsList($where); + + if (count($memberEvents) == 0) { + return false; + } + + return $memberEvents; + } + +} + +?> \ No newline at end of file diff --git a/models/admin/classes/inventory.php b/models/admin/classes/inventory.php new file mode 100644 index 0000000..dddc77a --- /dev/null +++ b/models/admin/classes/inventory.php @@ -0,0 +1,124 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: classes/invetory.php,v 1.0 2011/01/25 19:31:47 cscott Exp $ + * @link <> + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'classes/data/dataInventory.php'; + +/** + * EventManagementAdminInventory class + * + * Event Management and Reservations System - Admin Code - Inventory section + * + * PHP version 5 + * + * @category Event Management Admin Members + * @package EventManagement + * @author Chuck Scott + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: classes/inventory.php,v 1.0 2011/01/25 19:31:47 cscott Exp $ + * @link <> + */ +class EventManagementAdminInventory extends EventManagementDataInventory +{ + /** + * Configuration information object + * @var $ini + * @access public + */ + public $config; + /** + * Database Object + * @var $dbh + * @access public + */ + public $dbh; + /** + * File/Image server adapter + * @var $isa + * @var $imageServer + * @access public + */ + public $data; + + /** + * File/Image server adapter + * @var $isa + * @var $imageServer + * @access public + */ + + + /** + * Get Inventory Stats + * + * @return object containing array as sub-objects + */ + function getEventInvenStats() + { + // Get event ID from session - if available get stats for event + if (($eventID = $_SESSION[GLM_EVENT_SESSION]['Event'])) { + return $this->getStats("conv = $eventID"); + } + return 0; + } + function getMemberInvenStats() + { + // Get member ID from session - if available get stats for member + if (($memberID = $_SESSION[GLM_EVENT_SESSION]['Member'])) { + return $this->getStats("member = $memberID"); + } + return 0; + } + function getAccomInvenStats() + { + // Get accommodation ID from session - if available get stats for accommodation + if (($accomID = $_SESSION[GLM_EVENT_SESSION]['Accom'])) { + return $this->getStats("accommodation = $accomID"); + } + return 0; + } + function getTeamInvenStats() + { + // Get team ID from session - if available get stats for team + if (($teamID = $_SESSION[GLM_EVENT_SESSION]['Team'])) { + return $this->getStats(" + id in + ( + SELECT I.id + FROM eventmgt.inventory I, eventmgt.team_property TP + WHERE TP.team = $teamID + AND I.member = TP.property + AND I.date between TP.start AND TP.stop + ) + "); + } + return 0; + } + function getInvenStats() + { + $invenStats = array( + 'all' => $this->getStats(), + 'event' => $this->getEventInvenStats(), + 'member' => $this->getMemberInvenStats(), + 'accom' => $this->getAccomInvenStats(), + 'team' => $this->getTeamInvenStats() + ); + return $invenStats; + } + + +} + +?> \ No newline at end of file diff --git a/models/admin/classes/memberAmenities.php b/models/admin/classes/memberAmenities.php new file mode 100644 index 0000000..201a22d --- /dev/null +++ b/models/admin/classes/memberAmenities.php @@ -0,0 +1,86 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: classes/memberAmenities.php,v 1.0 2011/01/25 19:31:47 cscott Exp $ + * @link <> + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'classes/data/dataAmenities.php'; + +/** + * EventManagementAdminStates class + * + * Event Management and Reservations System - Admin Code - Member Amenities Section + * + * PHP version 5 + * + * @category Event Management Admin Members + * @package EventManagement + * @author Chuck Scott + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: classes/memberAmenities.php,v 1.0 2011/01/25 19:31:47 cscott Exp $ + * @link <> + */ +class EventManagementAdminMemberAmenities extends EventManagementDataAmenities +{ + /** + * Configuration information object + * @var $ini + * @access public + */ + public $config; + /** + * Database Object + * @var $dbh + * @access public + */ + public $dbh; + /** + * File/Image server adapter + * @var $isa + * @var $imageServer + * @access public + */ + public $data; + + /** + * File/Image server adapter + * @var $isa + * @var $imageServer + * @access public + */ + + + /** + * Get Member Amenities Stats + * + * @return object containing array as sub-objects + */ + function getMemberAmenitiesStats() + { + $memberAmenitiesStats = array( + 'all' => $this->getStats(), + 'member' => 0 + ); + + // Get member ID from session - if available get stats + if (($memberID = $_SESSION[GLM_EVENT_SESSION]['Member'])) { + $memberAmenitiesStats['member'] = $this->getStats(" + owner = $memberID + "); + } + + return $memberAmenitiesStats; + } + +} + +?> \ No newline at end of file diff --git a/models/admin/classes/memberFees.php b/models/admin/classes/memberFees.php new file mode 100644 index 0000000..d1f43a8 --- /dev/null +++ b/models/admin/classes/memberFees.php @@ -0,0 +1,86 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: classes/memberFees.php,v 1.0 2011/01/25 19:31:47 cscott Exp $ + * @link <> + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'classes/data/dataFees.php'; + +/** + * EventManagementAdminStates class + * + * Event Management and Reservations System - Admin Code - Member Fees Section + * + * PHP version 5 + * + * @category Event Management Admin Members + * @package EventManagement + * @author Chuck Scott + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: classes/memberFees.php,v 1.0 2011/01/25 19:31:47 cscott Exp $ + * @link <> + */ +class EventManagementAdminMemberFees extends EventManagementDataFees +{ + /** + * Configuration information object + * @var $ini + * @access public + */ + public $config; + /** + * Database Object + * @var $dbh + * @access public + */ + public $dbh; + /** + * File/Image server adapter + * @var $isa + * @var $imageServer + * @access public + */ + public $data; + + /** + * File/Image server adapter + * @var $isa + * @var $imageServer + * @access public + */ + + + /** + * Get Member Fees Stats + * + * @return object containing array as sub-objects + */ + function getMemberFeesStats() + { + $memberFeesStats = array( + 'all' => $this->getStats(), + 'member' => 0 + ); + + // Get member ID from session - if available get stats + if (($memberID = $_SESSION[GLM_EVENT_SESSION]['Member'])) { + $memberFeesStats['member'] = $this->getStats(" + owner = $memberID + "); + } + + return $memberFeesStats; + } + +} + +?> \ No newline at end of file diff --git a/models/admin/classes/members.php b/models/admin/classes/members.php new file mode 100644 index 0000000..1605604 --- /dev/null +++ b/models/admin/classes/members.php @@ -0,0 +1,198 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: classes/members.php,v 1.0 2011/01/25 19:31:47 cscott Exp $ + * @link <> + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'classes/data/dataMembers.php'; + +/** + * EventManagementAdminMembers class + * + * Event Management and Reservations System - Admin Code - Members section + * + * PHP version 5 + * + * @category Event Management Admin Members + * @package EventManagement + * @author Chuck Scott + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: classes/members.php,v 1.0 2011/01/25 19:31:47 cscott Exp $ + * @link <> + */ +class EventManagementAdminMembers extends EventManagementDataMembers +{ + /** + * Configuration information object + * @var $ini + * @access public + */ + public $config; + /** + * Database Object + * @var $dbh + * @access public + */ + public $dbh; + /** + * File/Image server adapter + * @var $isa + * @var $imageServer + * @access public + */ + public $data; + + /** + * File/Image server adapter + * @var $isa + * @var $imageServer + * @access public + */ + + + /** + * Get Members Stats + * + * @return object containing array as sub-objects + */ + function getMembersStats() + { + // Basic member stats + $membersStats = array( + 'all' => $this->getStats() // Count of all members + ); + + // Get event ID from session - if available get stats for members listed with this event + if (($eventID = $_SESSION[GLM_EVENT_SESSION]['Event'])) { + $membersStats['event'] = $this->getStats(" + id in + ( + SELECT DISTINCT(member) + FROM eventmgt.inventory + WHERE conv = $eventID + ) + "); + } else { + // Otherwise if no event number is 0 + $membersStats['event'] = 0; + } + + // If doing accommodations - get accommodation stats + if ($this->config->option->accommodations) { + $membersStats['accom'] = $this->getStats(" + id in + ( + SELECT DISTINCT member + FROM eventmgt.accommodation + ) + "); + } + + // If doing tickets - get ticket stats + if ($this->config->option->tickets) { + $membersStats['ticket'] = $this->getStats(" + id in + ( + SELECT DISTINCT member + FROM eventmgt.ticket + ) + "); + }; + + // determine if there's any status flags we should set + $membersStats['flags'] = false; + $membersStats['flag'] = false; + if ($membersStats['all'] == 0) { + $membersStats['flags']['noMembers'] = true; + $membersStats['flag'] = true; + } + if ($this->config->option->accommodations && $membersStats['accom'] == 0) { + $membersStats['flags']['noMemberAccoms'] = true; + $membersStats['flag'] = true; + } + if ($this->config->option->tickets && $membersStats['ticket'] == 0) { + $membersStats['flags']['noMemberTickets'] = true; + $membersStats['flag'] = true; + } + if ($this->config->option->events && $membersStats['event'] == 0) { + $membersStats['flags']['noMemberEvents'] = true; + $membersStats['flag'] = true; + } + + return $membersStats; + } + + function checkNewMembers() + { + // This function should not be called if it's not an integrated database + if ($this->config->option->member_db_integrated == false) { + return false; + } + + // Check that referenced members also have an entry in the res_member table + $sql = "SELECT member_id, member_name + FROM members.member + WHERE member_id IN + ( + SELECT member_id + FROM members.member_category + WHERE category_id IN + ( + SELECT category_id + FROM members.category + WHERE accommodations + ) + ) + AND member_id NOT IN + ( + SELECT id + FROM eventmgt.member + ); + "; + + $stmt = $this->dbh->prepare($sql); + $stmt->execute(); + $members = $stmt->fetchAll(PDO::FETCH_ASSOC); + + $r['reason'] = array(); + $sql = array(); + if ($members && count($members) > 0 ) { + foreach ($members as $memb ) { + // Add an entry in the res_member table + $sql[] = " + INSERT INTO eventmgt.member + (id, name) + VALUES + (".$memb['member_id'].", '".addslashes($memb['member_name'])."'); + "; + } + + try { + $this->dbh->beginTransaction(); + foreach ($sql as $s) { + $this->dbh->exec($s); + } + $this->dbh->commit(); + } catch (Exception $e) { + $this->dbh->rollBack(); + $r['status'] = false; + $r['reason'][] = 'Unable to store new properties for unknown reason. '; + } + + } + + return $r; + } + +} + +?> \ No newline at end of file diff --git a/models/admin/classes/misc.php b/models/admin/classes/misc.php new file mode 100644 index 0000000..37c7131 --- /dev/null +++ b/models/admin/classes/misc.php @@ -0,0 +1,58 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: classes/misc.php,v 1.0 2011/01/25 19:31:47 cscott Exp $ + * @link <> + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'classes/data/dataMisc.php'; + +/** + * EventManagementAdminSold class + * + * Event Management and Reservations System - Admin Code - Misc + * + * PHP version 5 + * + * @category Event Management Admin Tickets + * @package EventManagement + * @author Chuck Scott + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: classes/misc.php,v 1.0 2011/01/25 19:31:47 cscott Exp $ + * @link <> + */ + +class EventManagementAdminMisc extends EventManagementDataMisc +{ + /** + * Configuration information object + * @var $ini + * @access public + */ + public $config; + /** + * Database Object + * @var $dbh + * @access public + */ + public $dbh; + /** + * Data Definitions Object + * @var $dbh + * @access public + */ + public $data; + + +} + +?> \ No newline at end of file diff --git a/models/admin/classes/orders.php b/models/admin/classes/orders.php new file mode 100644 index 0000000..d0e1fa7 --- /dev/null +++ b/models/admin/classes/orders.php @@ -0,0 +1,58 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: classes/orders.php,v 1.0 2011/01/25 19:31:47 cscott Exp $ + * @link <> + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'classes/data/dataOrders.php'; + +/** + * EventManagementAdminOrders class + * + * Event Management and Reservations System - Admin Code - Contacts ticket + * + * PHP version 5 + * + * @category Event Management Admin Tickets + * @package EventManagement + * @author Chuck Scott + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: classes/orders.php,v 1.0 2011/01/25 19:31:47 cscott Exp $ + * @link <> + */ + +class EventManagementAdminOrders extends EventManagementDataOrders +{ + /** + * Configuration information object + * @var $ini + * @access public + */ + public $config; + /** + * Database Object + * @var $dbh + * @access public + */ + public $dbh; + /** + * Data Definitions Object + * @var $dbh + * @access public + */ + public $data; + + +} + +?> \ No newline at end of file diff --git a/models/admin/classes/performances.php b/models/admin/classes/performances.php new file mode 100644 index 0000000..7a3683c --- /dev/null +++ b/models/admin/classes/performances.php @@ -0,0 +1,79 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: classes/performances.php,v 1.0 2011/01/25 19:31:47 cscott Exp $ + * @link <> + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'classes/data/dataPerformances.php'; + +/** + * EventManagementAdminContacts class + * + * Event Management and Reservations System - Admin Code - Performances Section + * + * PHP version 5 + * + * @category Event Management Admin Performances + * @package EventManagement + * @author Chuck Scott + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: classes/performances.php,v 1.0 2011/01/25 19:31:47 cscott Exp $ + * @link <> + */ +class EventManagementAdminPerformances extends EventManagementDataPerformances +{ + /** + * Configuration information object + * @var $ini + * @access public + */ + public $config; + /** + * Database Object + * @var $dbh + * @access public + */ + public $dbh; + /** + * Data Definitions Object + * @var $dbh + * @access public + */ + public $data; + + /** + * Get Performances Stats + * + * @return object containing array as sub-objects + */ + function getMemberPerformancesStats($memberID = false) + { + // Get member ID from session - if available get stats for member + if ($memberID || ($memberID = $_SESSION[GLM_EVENT_SESSION]['Member'])) { + return $this->getStats("member = $memberID AND active"); + } + return 0; + } + function getPerformancesStats() + { + $performancesStats = array( + 'all' => $this->getStats(), + 'member' => $this->getMemberPerformancesStats() + ); + + return $performancesStats; + } + +} + +?> \ No newline at end of file diff --git a/models/admin/classes/promoTickets.php b/models/admin/classes/promoTickets.php new file mode 100644 index 0000000..9a0b827 --- /dev/null +++ b/models/admin/classes/promoTickets.php @@ -0,0 +1,126 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: classes/promoTickets.php,v 1.0 2011/01/25 19:31:47 cscott Exp $ + * @link <> + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'classes/data/dataPromoTickets.php'; + +/** + * EventManagementAdminPromoTickets class + * + * Event Management and Reservations System - Admin Code - Promotion Tickets section + * + * PHP version 5 + * + * @category Event Management Admin Add-Ons + * @package EventManagement + * @author Chuck Scott + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: classes/promoTickets.php,v 1.0 2011/01/25 19:31:47 cscott Exp $ + * @link <> + */ +class EventManagementAdminPromoTickets extends EventManagementDataPromoTickets +{ + /** + * Configuration information object + * @var $config + * @access public + */ + public $config; + /** + * Database Object + * @var $dbh + * @access public + */ + public $dbh; + /** + * Data Definitions Object + * @var $data + * @access public + */ + public $data; + + /** + * Get Promos Stats + * + * @return object containing array as sub-objects + */ + function getPromoTicketsStats() + { + return $this->getStats(); + } + + /** + * Process Promomotion Tickets and return list + * + * @return object containing array as sub-objects + */ + function processPromoTicketsList($promoID) + { + + // Check for promotion tickets update + if (isset($_REQUEST['Option']) && $_REQUEST['Option'] = 'update_promoTickets') { + + // Process all promotion ticket requests + $sql = ''; + if (isset($_REQUEST['type']) && count($_REQUEST['type']) > 0) { + while (list($k, $v) = each($_REQUEST['type'])) { + + // If this is a new addition + if ($k == 0 && ($_REQUEST['ticket'][$k]-0) > 0 && ($_REQUEST['amount'][$k]-0) > 0) { + $sql .= "INSERT INTO eventmgt.promo_ticket + (promo, ticket, promo_type, amount, notes) + VALUES + ( + $promoID, + ".($_REQUEST['ticket'][$k]-0).", + ".($_REQUEST['type'][$k]-0).", + ".($_REQUEST['amount'][$k]-0.0).", + '".addslashes($_REQUEST['notes'][$k])."' + ); + "; + + // If it's a delete request + } elseif (isset($_REQUEST['delete'][$k])) { + $sql .= "DELETE FROM eventmgt.promo_ticket WHERE id = $k; + "; + + // Otherwise update it + } else { + $sql .= "UPDATE eventmgt.promo_ticket SET + amount = ".($_REQUEST['amount'][$k]-0.0).", + notes = '".addslashes($_REQUEST['notes'][$k])."' + WHERE id = $k; + "; + } + + } + if ($sql != '') { + $this->dbh->exec($sql); + } + + } + + } + + // Get updated list of promotion tickets + $promoTicketsList = $this->getPromoTicketsList($promoID); + + return $promoTicketsList; + } + + +} + +?> \ No newline at end of file diff --git a/models/admin/classes/promos.php b/models/admin/classes/promos.php new file mode 100644 index 0000000..034e6f3 --- /dev/null +++ b/models/admin/classes/promos.php @@ -0,0 +1,68 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: classes/promos.php,v 1.0 2011/01/25 19:31:47 cscott Exp $ + * @link <> + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'classes/data/dataPromos.php'; + +/** + * EventManagementAdminPromos class + * + * Event Management and Reservations System - Admin Code - Promotionss section + * + * PHP version 5 + * + * @category Event Management Admin Add-Ons + * @package EventManagement + * @author Chuck Scott + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: classes/promos.php,v 1.0 2011/01/25 19:31:47 cscott Exp $ + * @link <> + */ +class EventManagementAdminPromos extends EventManagementDataPromos +{ + /** + * Configuration information object + * @var $config + * @access public + */ + public $config; + /** + * Database Object + * @var $dbh + * @access public + */ + public $dbh; + /** + * Data Definitions Object + * @var $data + * @access public + */ + public $data; + + /** + * Get Promos Stats + * + * @return object containing array as sub-objects + */ + function getPromosStats() + { + return $this->getStats(); + + return 0; + } + +} + +?> \ No newline at end of file diff --git a/models/admin/classes/promosSold.php b/models/admin/classes/promosSold.php new file mode 100644 index 0000000..9d18aec --- /dev/null +++ b/models/admin/classes/promosSold.php @@ -0,0 +1,57 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: classes/promosSold.php,v 1.0 2011/01/25 19:31:47 cscott Exp $ + * @link <> + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'classes/data/dataPromoSold.php'; + +/** + * EventManagementAdminPromosSold class + * + * Event Management and Reservations System - Admin Code - Sold Ticket promos + * + * PHP version 5 + * + * @category Event Management Admin Tickets + * @package EventManagement + * @author Chuck Scott + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: classes/promosSold.php,v 1.0 2011/01/25 19:31:47 cscott Exp $ + * @link <> + */ + +class EventManagementAdminPromosSold extends EventManagementDataPromoSold +{ + /** + * Configuration information object + * @var $ini + * @access public + */ + public $config; + /** + * Database Object + * @var $dbh + * @access public + */ + public $dbh; + /** + * Data Definitions Object + * @var $dbh + * @access public + */ + public $data; + + +} + +?> \ No newline at end of file diff --git a/models/admin/classes/reservationReport.php b/models/admin/classes/reservationReport.php new file mode 100644 index 0000000..1712904 --- /dev/null +++ b/models/admin/classes/reservationReport.php @@ -0,0 +1,343 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: classes/reservationReporteport.php,v 1.0 2011/01/25 19:31:47 cscott Exp $ + * @link <> + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'classes/data/Reports/dataReservationReport.php'; + +/** + * EventManagementAdminEvents class + * + * Event Management and Reservations System - Admin Code - Reservation Report section + * + * PHP version 5 + * + * @category Event Management Admin Events + * @package EventManagement + * @author Chuck Scott + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: classes/events.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + * @link <> + */ +class EventManagementAdminReservationReport extends EventManagementDataReservationReport +{ + /** + * Configuration information object + * @var $ini + * @access public + */ + public $config; + /** + * Database Object + * @var $dbh + * @access public + */ + public $dbh; + /** + * Data Definitions Object + * @var $dbh + * @access public + */ + public $data; + + /** + * File/Image server adapter + * @var $isa + * @var $imageServer + * @access public + */ + + function __construct($dbh, $config) + { + parent::__construct($dbh, $config); + } + + /** + * Get Report Request Form + * + * @return object containing array as sub-objects + */ + function getForm() + { + + $reportData = array( + 'status' => true, + 'reason' => array(), + 'form' => array() + ); + + $reportData['form'] = $this->newControls(); + + $this->addDebug("classes/reservationReport.inc", 'getForm()', print_r($reportData,1)); + + return $reportData; + } + + /** + * Process Report + * + * @return object containing array as sub-objects + */ + function getReport($setEvent = false, $setState = false) + { + + $reportData = array( + 'status' => true, + 'output' => false, + 'reason' => array(), + 'report' => array() + ); + + // If no specific event and state rep is requested, then process input for selections + if ($setState == false) { + + /* + * Try to process report form request + */ + $request = $this->processInputData(); + if (!$request['status']) { + $reportData['status'] = false; + + if ($request['fieldFail']['event_name']) { + $reportData['reason'][] = 'An event was not selected'; + } + + if ($request['fieldFail']['output_type']) { + $reportData['reason'][] = 'An output type was not selected'; + } + + } + $r = $request['fieldData']; + + + /* + * Get report data + */ + // Check for specified event + if ($setEvent) { + $event = $setEvent; + } else { + $event = $request['fieldData']['event_name']['in']; + } + + $state = ($r['state_rep']['in'] != '0' ? $r['state_rep']['in'] : false); + $team = ($r['team_code']['in'] != '0' ? $r['team_code']['in'] : false); + $property = ($r['prop_name']['in'] != '0' ? $r['prop_name']['in'] : false); + $status = $r['status']['value']; + $where = ''; + + // Make Reservation Report Request Data available to template + $reportData['report']['event'] = false; + if ($event > 0) { + + // Get Event data + $sql = "SELECT * FROM eventmgt.event WHERE id = $event;"; + $stmt = $this->dbh->prepare($sql); + $stmt->execute(); + $eventData = $stmt->fetch(PDO::FETCH_ASSOC); + $reportData['report']['event'] = $eventData; + + $where = "conv = $event"; + + } + + // Check for State Rep filter + if ($state > 0) { + $where .= ($where!=''?' AND ':'')." T.state_rep = $state"; + } + + // If a team has been selected, filter by that. + if ($team) { + $where .= ($where!=''?' AND ':'')." T.team_id = $team"; + } + + // If a property has been selected, filter by that. + if ($property) { + $where .= ($where!=''?' AND ':'')." T.member = $property"; + } + + // Select by status + switch ($status) { + case 'pending': + $where .= ($where!=''?' AND ':'')." NOT T.confirmed AND NOT T.declined"; + break; + case 'confirmed': + $where .= ($where!=''?' AND ':'')." T.confirmed AND NOT T.declined"; + break; + case 'declined': + $where .= ($where!=''?' AND ':'')." T.declined"; + break; + case 'all': + default: + break; + } + + } else { + + // There's been a specific request + $event = $setEvent; + $state = $setState; + $team = false; + $where = " T.state_rep = $state"; + + } + + + // If a State Rep is selected filter by that + if ($state) { + + // Build query where clause to filter for any requested state + $where .= ($where!=''?' AND ':'')." T.team_id IN (SELECT team.id FROM eventmgt.team WHERE state = $state)"; + + // Also get state information + $sql = "SELECT * FROM eventmgt.state_rep WHERE id = $state;"; + $stmt = $this->dbh->prepare($sql); + $stmt->execute(); + $stateData = $stmt->fetch(PDO::FETCH_ASSOC); + $reportData['report']['state'] = $stateData; + + } + + // If a team has been selected, filter by that. + if ($team) { + + $where .= ($where!=''?' AND ':'')." T.team_id = $team"; + + // Also get team information + $sql = "SELECT * FROM eventmgt.team WHERE id = $team;"; + $stmt = $this->dbh->prepare($sql); + $stmt->execute(); + $teamData = $stmt->fetch(PDO::FETCH_ASSOC); + $reportData['report']['team'] = $teamData; + } + + // If a property has been selected, filter by that. + if ($property) { + + $where .= ($where!=''?' AND ':'')." T.member = $property"; + + // Also get team information + $sql = "SELECT * FROM eventmgt.member WHERE id = $property;"; + $stmt = $this->dbh->prepare($sql); + $stmt->execute(); + $propertyData = $stmt->fetch(PDO::FETCH_ASSOC); + $reportData['report']['property'] = $propertyData; + } + + // Get Event Reservations + require_once EVENT_MANAGEMENT_APP_BASE.'classes/data/dataReservations.php'; + $Reservations = new EventManagementDataReservations($this->dbh, $this->config); + $reservationsList = $Reservations->getList($where); + + // Build totals + $numb_res = 0; + $total_hotel = 0; + $total_taxes = 0; + $total_fees = 0; + $grand_total = 0; + if (is_array($reservationsList) && count($reservationsList) > 0) { + reset($reservationsList); + while (list($k, $v) = each($reservationsList)) { + $reservationsList[$k]['detail'] = unserialize($v['res_detail']); + $taxes = 0; + $fees = 0; + // Make sure we decoded the res_detail (there's been some problems with that) + if($reservationsList[$k]['detail']) { + + $x = $reservationsList[$k]['detail']['propFees']; + foreach ($x as $f) { + $fees += $f['fee_calculated']; + } + +/* This doesn't seem to work. Need to revisit this when done with Kalamazoo Fee structure + $x = $reservationsList[$k]['detail']['propAccom']; + foreach ($x as $accom) { + // In case we get the values with leading "$" + if($accom['accom_fees_taxable'][0] == '$') { + $accom['accom_fees_taxable'] = substr($accom['accom_fees_non_taxable'],1); + } + if($accom['accom_fees_non_taxable'][0] == '$') { + $accom['accom_fees_non_taxable'] = substr($accom['accom_fees_non_taxable'],1); + } + // Now add the taxes and fees + $taxes += ($accom['accom_fees_taxable']-0); + $fees += ($accom['accom_fees_non_taxable']-0); + + } +*/ + + $numb_res++; + $total_taxes += $taxes; + $total_fees += $fees; + $reservationsList[$k]['taxes'] = $this->money($taxes); + $reservationsList[$k]['fees'] = $this->money($fees); + $reservationsList[$k]['taxes_and_fees'] = $this->money($taxes + $fees); + $total_hotel += $v['hotel_price_numb']; + $grand_total += $v['grand_total_numb']; + } else { + // We get here if the res_detail field doesn't unserialize or if there's nothing in the field. + // Had a problem with this originally due to corruption of the serialized data by using stripslashes(). Don't do that! + echo "System Error: Unable to decode reservation detail for reservation # ".$v['id']." - Please contact Gaslight Media.
    "; + } + } + } + + $reportData['report']['reservations'] = $reservationsList; + $reportData['output'] = $r['output_type']['value']; + + $reportData['report']['totals'] = array( + 'numb_reservations' => $numb_res, + 'hotel' => $this->money($total_hotel), + 'taxes' => $this->money($total_taxes), + 'fees' => $this->money($total_fees), + 'taxes_and_fees' => $this->money($total_taxes + $total_fees), + 'grand_total' => $this->money($grand_total) + ); + + $this->addDebug("classes/reservationReport.inc", 'getReport', print_r($reportData,1)); + + return $reportData; + } + + + /** + * Format a number as money + * + * @param $value Value to format + * @param $option Options that control output + * NOPREFIX stops the "$" prefix + * + * @return none + * @access public + */ + public function money($value, $option = "") + { + + if ($option == "NOPREFIX") + $prefix = ""; + else + $prefix = "$"; + + // Do value sanity check + + if (!is_numeric($value)) + return ($prefix."0.00"); + + return ($prefix.number_format($value, 2, ".", ",")); + } + + +} + +?> \ No newline at end of file diff --git a/models/admin/classes/reservations.php b/models/admin/classes/reservations.php new file mode 100644 index 0000000..80f5525 --- /dev/null +++ b/models/admin/classes/reservations.php @@ -0,0 +1,103 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: classes/reservations.php,v 1.0 2011/01/25 19:31:47 cscott Exp $ + * @link <> + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'classes/data/dataReservations.php'; + +/** + * EventManagementAdminReservations class + * + * Event Management and Reservations System - Admin Code - Reservations section + * + * PHP version 5 + * + * @category Event Management Admin Members + * @package EventManagement + * @author Chuck Scott + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: classes/reservations.php,v 1.0 2011/01/25 19:31:47 cscott Exp $ + * @link <> + */ +class EventManagementAdminReservations extends EventManagementDataReservations +{ + /** + * Configuration information object + * @var $ini + * @access public + */ + public $config; + /** + * Database Object + * @var $dbh + * @access public + */ + public $dbh; + /** + * File/Image server adapter + * @var $isa + * @var $imageServer + * @access public + */ + public $data; + + /** + * File/Image server adapter + * @var $isa + * @var $imageServer + * @access public + */ + + + /** + * Get Reservations Stats + * + * @return object containing array as sub-objects + */ + function getReservationsStats() + { + $resStats = array( + 'all' => $this->getStats(), + 'event' => 0, + 'member' => 0, + 'accom' => 0, + 'team' => 0 + ); + + // Get stats for selected event + if (($eventID = $_SESSION[GLM_EVENT_SESSION]['Event'])) { + $resStats['event'] = $this->getStats("conv = $eventID"); + } + + // Get stats for selected member + if (($memberID = $_SESSION[GLM_EVENT_SESSION]['Member'])) { + $resStats['member'] = $this->getStats("member = $memberID"); + } + + // Get stats for selected accommodation + if (($accomID = $_SESSION[GLM_EVENT_SESSION]['Accom'])) { + $resStats['accom'] = $this->getStats("accommodation = $accomID"); + } + + // Get stats for selected team + if (($teamID = $_SESSION[GLM_EVENT_SESSION]['Team'])) { + $resStats['event'] = $this->getStats("team = $teamID"); + } + + // var_dump($resStats); + return $resStats; + } + +} + +?> \ No newline at end of file diff --git a/models/admin/classes/roomBlockReport.php b/models/admin/classes/roomBlockReport.php new file mode 100644 index 0000000..174a2ff --- /dev/null +++ b/models/admin/classes/roomBlockReport.php @@ -0,0 +1,240 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: classes/roomBlockReporteport.php,v 1.0 2011/01/25 19:31:47 cscott Exp $ + * @link <> + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'classes/data/Reports/dataRoomBlockReport.php'; + +/** + * EventManagementAdminEvents class + * + * Event Management and Reservations System - Admin Code - Reservation Report section + * + * PHP version 5 + * + * @category Event Management Admin Events + * @package EventManagement + * @author Chuck Scott + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: classes/events.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + * @link <> + */ +class EventManagementAdminRoomBlockReport extends EventManagementDataRoomBlockReport +{ + /** + * Configuration information object + * @var $ini + * @access public + */ + public $config; + /** + * Database Object + * @var $dbh + * @access public + */ + public $dbh; + /** + * Data Definitions Object + * @var $dbh + * @access public + */ + public $data; + + /** + * File/Image server adapter + * @var $isa + * @var $imageServer + * @access public + */ + + function __construct($dbh, $config) + { + parent::__construct($dbh, $config); + } + + /** + * Get Report Request Form + * + * @return object containing array as sub-objects + */ + function getForm() + { + + $reportData = array( + 'status' => true, + 'reason' => array(), + 'form' => array() + ); + + $reportData['form'] = $this->newControls(); + + $this->addDebug("classes/roomBlockReport.inc", 'getForm()', print_r($reportData,1)); + + return $reportData; + } + + /** + * Process Report + * + * @return object containing array as sub-objects + */ + function getReport($setEvent = false, $setState = false) + { + + $reportData = array( + 'status' => true, + 'reason' => array(), + 'report' => array() + ); + + // If no specific event and state rep is requested, then process input for selections + if ($setState == false) { + + /* + * Try to process report form request + */ + $request = $this->processInputData(); + if (!$request['status']) { + $reportData['status'] = false; + + if ($request['fieldFail']['event_name']) { + $reportData['reason'][] = 'An event was not selected'; + } + + if ($request['fieldFail']['output_type']) { + $reportData['reason'][] = 'An output type was not selected'; + } + + } + + /* + * Get report data + */ + $r = $request['fieldData']; + $event = $r['event_name']['in']; + $state = ($r['state_rep']['in'] != '0' ? $r['state_rep']['in'] : false); + $team = ($r['team_code']['in'] != '0' ? $r['team_code']['in'] : false); + $property = ($r['prop_name']['in'] != '0' ? $r['prop_name']['in'] : false); + $reportData['report']['doingProperties'] = $r['property_section']['value']; + $reportData['report']['doingAssigned'] = $r['assigned_section']['value']; + $reportData['report']['doingOptionAssigned'] = $r['option_assigned']['value']; + $reportData['output'] = $r['output_type']['value']; + + } else { + + // There's been a specific request + $event = $setEvent; + $state = $setState; + + $team = false; + $property = false; + $reportData['report']['doingProperties'] = true; + $reportData['report']['doingAssigned'] = true; + $reportData['report']['doingOptionAssigned'] = false; + $reportData['output'] = 'html'; + + } + + // If the request is valid - Produce the report + if ($reportData['status']) { + + // Get Event data + $sql = "SELECT * FROM eventmgt.event WHERE id = $event;"; + $stmt = $this->dbh->prepare($sql); + $stmt->execute(); + $eventData = $stmt->fetch(PDO::FETCH_ASSOC); + $reportData['report']['event'] = $eventData; + + // Get State data + $reportData['report']['state'] = false; + if ($state) { + $sql = "SELECT * FROM eventmgt.state_rep WHERE id = $state;"; + $stmt = $this->dbh->prepare($sql); + $stmt->execute(); + $stateData = $stmt->fetch(PDO::FETCH_ASSOC); + $reportData['report']['state'] = $stateData; + } + + // Get Team data + $reportData['report']['team'] = false; + if ($team) { + $sql = "SELECT * FROM eventmgt.team WHERE id = $team;"; + $stmt = $this->dbh->prepare($sql); + $stmt->execute(); + $teamData = $stmt->fetch(PDO::FETCH_ASSOC); + $reportData['report']['team'] = $teamData; + } + + // Get Property data + $reportData['report']['property'] = false; + if ($property) { + $sql = "SELECT * FROM eventmgt.member WHERE id = $property;"; + $stmt = $this->dbh->prepare($sql); + $stmt->execute(); + $propertyData = $stmt->fetch(PDO::FETCH_ASSOC); + $reportData['report']['property'] = $propertyData; + } + + // Get Event Room Blocks + + require 'blocks.php'; + $Blocks = new EventManagementAdminBlocks($this->dbh, $this->config); + // Get room block list sorted and in summary mode (see function for explanation) + $blocksList = $Blocks->getRoomBlocks($event, true, true, $state, $team, $property); + $reportData['report']['roomBlocks'] = $blocksList; + + // Check for results + if (!is_array($blocksList) || count($blocksList) == 0) { + $reportData['status'] = false; + $reportData['reason'][] = 'No data was returned for this report.'; + } + + } + + $this->addDebug("classes/roomBlockReport.inc", 'getReport()', print_r($reportData,1)); + + return $reportData; + } + + + /** + * Format a number as money + * + * @param $value Value to format + * @param $option Options that control output + * NOPREFIX stops the "$" prefix + * + * @return none + * @access public + */ + public function money($value, $option = "") + { + + if ($option == "NOPREFIX") + $prefix = ""; + else + $prefix = "$"; + + // Do value sanity check + + if (!is_numeric($value)) + return ($prefix."0.00"); + + return ($prefix.number_format($value, 2, ".", ",")); + } + + +} + +?> \ No newline at end of file diff --git a/models/admin/classes/roomRequestReport.php b/models/admin/classes/roomRequestReport.php new file mode 100644 index 0000000..2bdb02c --- /dev/null +++ b/models/admin/classes/roomRequestReport.php @@ -0,0 +1,383 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: classes/roomRequestReporteport.php,v 1.0 2011/01/25 19:31:47 cscott Exp $ + * @link <> + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'classes/data/Reports/dataRoomRequestReport.php'; + +/** + * EventManagementAdminEvents class + * + * Event Management and Reservations System - Admin Code - Room Request Report section + * + * PHP version 5 + * + * @category Event Management Admin Events + * @package EventManagement + * @author Chuck Scott + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: classes/events.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + * @link <> + */ +class EventManagementAdminRoomRequestReport extends EventManagementDataRoomRequestReport +{ + /** + * Configuration information object + * @var $ini + * @access public + */ + public $config; + /** + * Database Object + * @var $dbh + * @access public + */ + public $dbh; + /** + * Data Definitions Object + * @var $dbh + * @access public + */ + public $data; + + /** + * File/Image server adapter + * @var $isa + * @var $imageServer + * @access public + */ + + function __construct($dbh, $config) + { + parent::__construct($dbh, $config); + } + + /** + * Get Report Request Form + * + * @return object containing array as sub-objects + */ + function getForm() + { + + $reportData = array( + 'status' => true, + 'reason' => array(), + 'form' => array() + ); + + $reportData['form'] = $this->newControls(); + + $this->addDebug("classes/roomRequestReport.inc", 'getForm()', print_r($reportData,1)); + + return $reportData; + } + + /** + * Process Report + * + * @return object containing array as sub-objects + */ + function getReport($setEvent = false) + { + + $reportData = array( + 'status' => true, + 'output' => false, + 'reason' => array(), + 'report' => array() + ); + + /* + * Try to process report form request + */ + $request = $this->processInputData(); + if (!$request['status']) { + $reportData['status'] = false; + + if ($request['fieldFail']['event_name']) { + $reportData['reason'][] = 'An event was not selected'; + } + + if ($request['fieldFail']['output_type']) { + $reportData['reason'][] = 'An output type was not selected'; + } + + } + $r = $request['fieldData']; + + // Check for specified event + if ($setEvent) { + $event = $setEvent; + } else { + $event = $request['fieldData']['event_name']['in']; + } + + /* + * Get report data + */ + $state = ($r['state_rep']['in'] != '0' ? $r['state_rep']['in'] : false); + $team = ($r['team_code']['in'] != '0' ? $r['team_code']['in'] : false); + $property = ($r['prop_name']['in'] != '0' ? $r['prop_name']['in'] : false); + $reportData['report']['doingAvailable'] = false; + $reportData['report']['doingPending'] = $r['pending_select']['value']; + $reportData['report']['doingConfirmed'] = $r['confirmed_select']['value']; + $reportData['report']['doingDeclined'] = $r['declined_select']['value']; + $where = ''; + + // If an event is selected, get that data + $reportData['report']['event'] = false; + if ($event > 0) { + + // Get Event data + $sql = "SELECT * FROM eventmgt.event WHERE id = $event;"; + $stmt = $this->dbh->prepare($sql); + $stmt->execute(); + $eventData = $stmt->fetch(PDO::FETCH_ASSOC); + $reportData['report']['event'] = $eventData; + + $where = "conv = $event"; + + } else { + // No event selected, so show for all events that haven't ended yet + $where = ($where!=''?' AND ':'')."T.conv_end > 'now'"; + } + + // If a State Rep is selected filter by that + if ($state) { + + // Build query where clause to filter for any requested state + $where .= ($where!=''?' AND ':'')." T.team_id IN (SELECT team.id FROM eventmgt.team WHERE state = $state)"; + + // Also get state information + $sql = "SELECT * FROM eventmgt.state_rep WHERE id = $state;"; + $stmt = $this->dbh->prepare($sql); + $stmt->execute(); + $stateData = $stmt->fetch(PDO::FETCH_ASSOC); + $reportData['report']['state'] = $stateData; + + } + + // If a team has been selected, filter by that. + if ($team) { + + $where .= ($where!=''?' AND ':'')." T.team_id = $team"; + + // Also get team information + $sql = "SELECT * FROM eventmgt.team WHERE id = $team;"; + $stmt = $this->dbh->prepare($sql); + $stmt->execute(); + $teamData = $stmt->fetch(PDO::FETCH_ASSOC); + $reportData['report']['team'] = $teamData; + + // Also check if availability requested. + $reportData['report']['doingAvailable'] = $r['available_select']['value']; + // If doingAvailable, override Pending, Confirmed, Declined + if ($reportData['report']['doingAvailable']) { + $reportData['report']['doingPending'] = true; + $reportData['report']['doingConfirmed'] = true; + $reportData['report']['doingDeclined'] = false; + } + + } + + // If a property has been selected, filter by that. + if ($property) { + + $where .= ($where!=''?' AND ':'')." T.member = $property"; + + // Also get team information + $sql = "SELECT * FROM eventmgt.member WHERE id = $property;"; + $stmt = $this->dbh->prepare($sql); + $stmt->execute(); + $propertyData = $stmt->fetch(PDO::FETCH_ASSOC); + $reportData['report']['property'] = $propertyData; + } + + // Get Event Reservations + require_once EVENT_MANAGEMENT_APP_BASE.'classes/data/dataReservations.php'; + $Reservations = new EventManagementDataReservations($this->dbh, $this->config); + $reservationsList = $Reservations->getList($where); + + // Build totals + $numb_res = 0; + $total_hotel = 0; + $total_taxes = 0; + $total_fees = 0; + $grand_total = 0; + $grand_total_rooms = 0; + + // Reorganize reservations data as room report and collect totals + if (is_array($reservationsList) && count($reservationsList) > 0) { + + reset($reservationsList); + $roomRequests = array(); + while (list($k, $v) = each($reservationsList)) { + + // Check if request matches filters + $show = false; + if ($reportData['report']['doingPending'] && !$v['confirmed']['value'] && !$v['declined']['value']) { + $show = true; + } + if ($reportData['report']['doingConfirmed'] && $v['confirmed']['value']) { + $show = true; + } + if ($reportData['report']['doingDeclined'] && $v['declined']['value']) { + $show = true; + } + + if ($show) { + + // Extract detail in case we need it + $v['detail'] = unserialize($v['res_detail']); + + // Put fees into results - NEED TO FIX AND GET FROM DATABASE + $fees = 25; + $reportData['report']['reservations'][$k]['fees'] = '$25.00'; + + // Add to totals + $numb_res++; + $total_hotel += $v['hotel_price_numb']; + $total_taxes += $v['taxes_numb']; + $total_fees += $fees; + $grand_total += $v['grand_total_numb']; + + // If property hasn't been created yet, do it now + // $propId = $v['detail']['propId']; + $propId = $v['member_id']; + if (!isset($roomRequests[$propId])) { + $roomRequests[$propId] = array( + 'propName' => $v['detail']['propName'], + 'propCity' => $v['detail']['propCity'], + 'propState' => $v['detail']['propState'], + 'propPhone' => $v['detail']['propPhone'], + 'propRoomsTotal' => 0, + 'accoms' => array() + ); + } + + // For each accommodation with this reservation + if ($v['detail']['propAccom']) { + foreach ($v['detail']['propAccom'] as $accom) { + + // If accommodation hasn't been created yet, do it now + if (!isset($roomRequests[$propId]['accoms'][$accom['accomId']])) { + $roomRequests[$propId]['accoms'][$accom['accomId']] = array( + 'accomTitle' => $accom['accomTitle'], + 'accomRoomsTotal' => 0, + 'roomRequests' => array() + ); + + // Get assigned and available for this accommodation/team (from room_block_seg). + $sql = "SELECT B.block_name, S.id, S.allocated, S.available + FROM eventmgt.room_block B, eventmgt.room_block_seg S, eventmgt.team T + WHERE B.state_rep = ".$v['state_rep']." + AND T.name = '".$v['org']."' + AND B.team = T.id + AND S.block = B.id + AND S.accommodation = ".$accom['accomId'].";"; + $stmt = $this->dbh->prepare($sql); + $stmt->execute(); + $blockData = $stmt->fetch(PDO::FETCH_ASSOC); + + $roomRequests[$propId]['accoms'][$accom['accomId']]['blockName'] = $blockData['block_name']; + $roomRequests[$propId]['accoms'][$accom['accomId']]['blockAssigned'] = $blockData['allocated']; + $roomRequests[$propId]['accoms'][$accom['accomId']]['blockAvailable'] = $blockData['available']; + $roomRequests[$propId]['accoms'][$accom['accomId']]['blockAvailableActual'] = $blockData['allocated'];; + } + + // Add this accommodation request + $grand_total_rooms += $accom['accomQuant']; + $roomRequests[$propId]['propRoomsTotal'] += $accom['accomQuant']; + $roomRequests[$propId]['accoms'][$accom['accomId']]['accomRoomsTotal'] += $accom['accomQuant']; + $roomRequests[$propId]['accoms'][$accom['accomId']]['blockAvailableActual'] -= $accom['accomQuant']; + $roomRequests[$propId]['accoms'][$accom['accomId']]['roomRequests'][] = array( + 'org' => trim($v['org']), + 'fname' => $v['fname'], + 'lname' => $v['lname'], + 'city' => $v['city'], + 'state' => $v['state'], + 'phone' => $v['phone'], + 'dateRequested' => $v['date_entered']['date'], + 'confirmed' => $v['confirmed']['value'], + 'dateConfirmed' => $v['date_confirmed']['date'], + 'confirmedBy' => $v['conf_by'], + 'declined' => $v['declined']['value'], + 'accomQuant' => $accom['accomQuant'], + 'arriveDate' => $accom['accomArrive'], + 'departDate' => $accom['accomDepart'], + 'nights' => $accom['accom_nights'] + ); + + } // each accom + } else { +// echo "Problem retrieving reservation detail for: ".$v['lname'].", ".$v['fname'].", res # $propId
    "; + } + } // if show + + } // each reservation + +//echo "
    ".print_r($roomRequests,1)."
    "; + + } +//echo "
    ".print_r($reservationsList,1)."
    "; + + $reportData['report']['roomRequests'] = $roomRequests; + $reportData['output'] = $r['output_type']['value']; + + $reportData['report']['totals'] = array( + 'numb_reservations' => $numb_res, + 'hotel' => $this->money($total_hotel), + 'taxes' => $this->money($total_taxes), + 'fees' => $this->money($total_fees), + 'grand_total' => $this->money($grand_total), + 'grand_total_rooms' => $grand_total_rooms + ); + + $this->addDebug("classes/roomRequestReport.inc", 'getReport()', print_r($reportData,1)); + + return $reportData; + } + + + /** + * Format a number as money + * + * @param $value Value to format + * @param $option Options that control output + * NOPREFIX stops the "$" prefix + * + * @return none + * @access public + */ + public function money($value, $option = "") + { + + if ($option == "NOPREFIX") + $prefix = ""; + else + $prefix = "$"; + + // Do value sanity check + + if (!is_numeric($value)) + return ($prefix."0.00"); + + return ($prefix.number_format($value, 2, ".", ",")); + } + + +} + +?> \ No newline at end of file diff --git a/models/admin/classes/rooms.php b/models/admin/classes/rooms.php new file mode 100644 index 0000000..cfd0427 --- /dev/null +++ b/models/admin/classes/rooms.php @@ -0,0 +1,68 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: classes/rooms.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + * @link <> + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'classes/data/dataRooms.php'; + +/** + * EventManagementAdminRooms class + * + * Event Management and Reservations System - Admin Code - Accommodations section + * + * PHP version 5 + * + * @category Event Management Admin Accommodations + * @package EventManagement + * @author Chuck Scott + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: classes/rooms.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + * @link <> + */ +class EventManagementAdminRooms extends EventManagementDataRooms +{ + /** + * Configuration information object + * @var $ini + * @access public + */ + public $config; + /** + * Database Object + * @var $dbh + * @access public + */ + public $dbh; + /** + * File/Image server adapter + * @var $isa + * @var $imageServer + * @access public + */ + + /** + * Get Rooms Stats + * + * @return object containing array as sub-objects + */ + function getRoomsStats() + { + return false; + } + + +} + +?> + diff --git a/models/admin/classes/sections.php b/models/admin/classes/sections.php new file mode 100644 index 0000000..bf3acc5 --- /dev/null +++ b/models/admin/classes/sections.php @@ -0,0 +1,81 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: classes/sections.php,v 1.0 2011/01/25 19:31:47 cscott Exp $ + * @link <> + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'classes/data/dataSections.php'; + +/** + * EventManagementAdminContacts class + * + * Event Management and Reservations System - Admin Code - Contacts section + * + * PHP version 5 + * + * @category Event Management Admin Sections + * @package EventManagement + * @author Chuck Scott + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: classes/sections.php,v 1.0 2011/01/25 19:31:47 cscott Exp $ + * @link <> + */ +class EventManagementAdminSections extends EventManagementDataSections +{ + /** + * Configuration information object + * @var $ini + * @access public + */ + public $config; + /** + * Database Object + * @var $dbh + * @access public + */ + public $dbh; + /** + * Data Definitions Object + * @var $dbh + * @access public + */ + public $data; + + /** + * Get Sectionss Stats + * + * @return object containing array as sub-objects + */ + function getMemberSectionsStats($memberID = false) + { + // Get member ID from session - if available get stats for member + if ($memberID || ($memberID = $_SESSION[GLM_EVENT_SESSION]['Member'])) { + return $this->getStats("member = $memberID"); + } + return 0; + } + function getSectionsStats() + { + $sectionsStats = array( + 'all' => $this->getStats(), + 'member' => $this->getMemberSectionsStats() + ); + + return $sectionsStats; + } + + + +} + +?> \ No newline at end of file diff --git a/models/admin/classes/sold.php b/models/admin/classes/sold.php new file mode 100644 index 0000000..9fbdb71 --- /dev/null +++ b/models/admin/classes/sold.php @@ -0,0 +1,58 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: classes/sold.php,v 1.0 2011/01/25 19:31:47 cscott Exp $ + * @link <> + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'classes/data/dataSold.php'; + +/** + * EventManagementAdminSold class + * + * Event Management and Reservations System - Admin Code - Sold Tickets + * + * PHP version 5 + * + * @category Event Management Admin Tickets + * @package EventManagement + * @author Chuck Scott + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: classes/sold.php,v 1.0 2011/01/25 19:31:47 cscott Exp $ + * @link <> + */ + +class EventManagementAdminSold extends EventManagementDataSold +{ + /** + * Configuration information object + * @var $ini + * @access public + */ + public $config; + /** + * Database Object + * @var $dbh + * @access public + */ + public $dbh; + /** + * Data Definitions Object + * @var $dbh + * @access public + */ + public $data; + + +} + +?> \ No newline at end of file diff --git a/models/admin/classes/states.php b/models/admin/classes/states.php new file mode 100644 index 0000000..1952d46 --- /dev/null +++ b/models/admin/classes/states.php @@ -0,0 +1,86 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: classes/states.php,v 1.0 2011/01/25 19:31:47 cscott Exp $ + * @link <> + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'classes/data/dataStates.php'; + +/** + * EventManagementAdminStates class + * + * Event Management and Reservations System - Admin Code - States section + * + * PHP version 5 + * + * @category Event Management Admin Members + * @package EventManagement + * @author Chuck Scott + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: classes/states.php,v 1.0 2011/01/25 19:31:47 cscott Exp $ + * @link <> + */ +class EventManagementAdminStates extends EventManagementDataStates +{ + /** + * Configuration information object + * @var $ini + * @access public + */ + public $config; + /** + * Database Object + * @var $dbh + * @access public + */ + public $dbh; + /** + * File/Image server adapter + * @var $isa + * @var $imageServer + * @access public + */ + public $data; + + /** + * File/Image server adapter + * @var $isa + * @var $imageServer + * @access public + */ + + + /** + * Get State Reps Stats + * + * @return object containing array as sub-objects + */ + function getStatesStats() + { + $statesStats = array( + 'all' => $this->getStats(), + 'event' => 0 + ); + + // Get event ID from session - if available get stats for teams listed with this event + if (($eventID = $_SESSION[GLM_EVENT_SESSION]['Event'])) { + $statesStats['event'] = $this->getStats(" + conv = $eventID + "); + } + + return $statesStats; + } + +} + +?> \ No newline at end of file diff --git a/models/admin/classes/teams.php b/models/admin/classes/teams.php new file mode 100644 index 0000000..6c988f5 --- /dev/null +++ b/models/admin/classes/teams.php @@ -0,0 +1,98 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: classes/teams.php,v 1.0 2011/01/25 19:31:47 cscott Exp $ + * @link <> + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'classes/data/dataTeams.php'; + +/** + * EventManagementAdminTeams class + * + * Event Management and Reservations System - Admin Code - Teams section + * + * PHP version 5 + * + * @category Event Management Admin Members + * @package EventManagement + * @author Chuck Scott + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: classes/teams.php,v 1.0 2011/01/25 19:31:47 cscott Exp $ + * @link <> + */ +class EventManagementAdminTeams extends EventManagementDataTeams +{ + /** + * Configuration information object + * @var $ini + * @access public + */ + public $config; + /** + * Database Object + * @var $dbh + * @access public + */ + public $dbh; + /** + * File/Image server adapter + * @var $isa + * @var $imageServer + * @access public + */ + public $data; + + /** + * File/Image server adapter + * @var $isa + * @var $imageServer + * @access public + */ + + + /** + * Get Members Stats + * + * @return object containing array as sub-objects + */ + function getTeamsStats() + { + $teamsStats = array( + 'all' => $this->getStats(), + 'member' => 0, + 'event' => 0 + ); + + // Get member ID from session - if available get stats for teams with booking for this member + if (($memberID = $_SESSION[GLM_EVENT_SESSION]['Member'])) { + $teamsStats['member'] = $this->getStats(" + id in ( + SELECT team + FROM eventmgt.team_property + WHERE property = $memberID + ) + "); + } + + // Get event ID from session - if available get stats for teams listed with this event + if (($eventID = $_SESSION[GLM_EVENT_SESSION]['Event'])) { + $teamsStats['event'] = $this->getStats(" + conv = $eventID + "); + } + + return $teamsStats; + } + +} + +?> \ No newline at end of file diff --git a/models/admin/classes/ticketInventory.php b/models/admin/classes/ticketInventory.php new file mode 100644 index 0000000..20ca4df --- /dev/null +++ b/models/admin/classes/ticketInventory.php @@ -0,0 +1,231 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: classes/ticketInventory.php,v 1.0 2011/01/25 19:31:47 cscott Exp $ + * @link <> + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'classes/data/dataTicketInventory.php'; + +/** + * EventManagementAdminContacts class + * + * Event Management and Reservations System - Admin Code - Contacts ticket + * + * PHP version 5 + * + * @category Event Management Admin Tickets + * @package EventManagement + * @author Chuck Scott + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: classes/tickets.php,v 1.0 2011/01/25 19:31:47 cscott Exp $ + * @link <> + */ + +class EventManagementAdminTicketInventory extends EventManagementDataTicketInventory +{ + /** + * Configuration information object + * @var $ini + * @access public + */ + public $config; + /** + * Database Object + * @var $dbh + * @access public + */ + public $dbh; + /** + * Data Definitions Object + * @var $dbh + * @access public + */ + public $data; + + + /** + * Get Tickets Stats + * + * @return object containing array as sub-objects + */ + function getTicketTicketInventoryStats($ticketID = false) + { + if ($ticketID == false) { + $ticketID = $_SESSION[GLM_EVENT_SESSION]['Ticket']; + } + if (($ticketID)) { + return $this->getStats("ticket = $ticketID"); + } + return 0; + } + function getPerformanceTicketInventoryStats($performanceID = false) + { + if ($performanceID == false) { + $performanceID = $_SESSION[GLM_EVENT_SESSION]['Performance']; + } + if (($performanceID)) { + return $this->getStats("ticket in (SELECT id FROM eventmgt.ticket WHERE performance = $performanceID)"); + } + return 0; + } + function getMemberTicketInventoryStats($memberID = false) + { + + if ($memberID == false) { + $memberID = $_SESSION[GLM_EVENT_SESSION]['Member']; + } + // Get member ID from session - if available get stats for member + if (($memberID)) { + return $this->getStats("member = $memberID"); + } + return 0; + } + function getMemberTicketInventorySalesStats($memberID = false, $where = '') + { + if ($memberID == false) { + $memberID = $_SESSION[GLM_EVENT_SESSION]['Member']; + } + // Get member ID from session - if available get stats for member + if (($memberID)) { + $sql = " + SELECT + ( + SELECT COALESCE(SUM(I.quant),0) + FROM eventmgt.ticket_inventory I + WHERE I.ticket IN ( SELECT id FROM eventmgt.ticket WHERE member = $memberID ) + $where + ) AS totalQuant, + ( + SELECT COALESCE(SUM(I.sold),0) + FROM eventmgt.ticket_inventory I + WHERE I.ticket IN ( SELECT id FROM eventmgt.ticket WHERE member = $memberID ) + $where + ) AS totalSold, + ( + SELECT COALESCE(SUM(I.sold * T.price),0) + FROM eventmgt.ticket_inventory I, eventmgt.ticket T + WHERE I.ticket IN ( SELECT id FROM eventmgt.ticket WHERE member = $memberID ) + $where + AND T.id = I.ticket + ) AS totalPrice + ;"; + $stmt = $this->dbh->prepare($sql); + $stmt->execute(); + $s = $stmt->fetch(PDO::FETCH_ASSOC); + + return $s; + } + return 0; + } + function getTicketInventoryStats() + { + $ticketInventoryStats = array( + 'all' => $this->getStats(), + 'member' => $this->getMemberTicketInventoryStats(), + 'performance' => $this->getPerformanceTicketInventoryStats(), + 'ticket' => $this->getTicketTicketInventoryStats(), + ); + + return $ticketsInventoryStats; + } + + /** + * Generate Default Ticket Inventory + * + * @return object containing array as sub-objects + */ + function generateDefaultTicketInventory($ticketID = false) + { + + // If no ticket ID supplied, check session + if (!$ticketID) { + $ticketID = ($_SESSION[GLM_EVENT_SESSION]['Ticket'] - 0); + } + + // If we have a ticket ID + if ($ticketID) { + + // Get ticket information + require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/tickets.php'; + $Tickets = new EventManagementAdminTickets($this->dbh, $this->config); + $ticketDetail = $Tickets->getTicketDetail(); + if (!$ticketDetail) { + return false; + } + + // Get Performance Information + $_SESSION[GLM_EVENT_SESSION]['Performance'] = $ticketDetail['performance_id']; + require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/performances.php'; + $Performances = new EventManagementAdminPerformances($this->dbh, $this->config); + $performanceDetail = $Performances->getPerformanceDetail(); + if (!$performanceDetail) { + return false; + } + + // Check for existing ticket inventory - Don't generate default inventory if there's some already there + $inventoryStats = $this->getTicketTicketInventoryStats(); + if ($inventoryStats > 0) { + return false; + } + + // Collect needed data + $ticket = $ticketDetail['id']; + $member = $ticketDetail['member']; + $quant = $ticketDetail['quant']; + $time = 'null'; + if ($ticketDetail['time_specific']['value']) { + $time = "'".trim($ticketDetail['ticket_time']['time'])."'"; + } + $start = $ticketDetail['start_date']['timestamp']; + $end = $ticketDetail['end_date']['timestamp']; + + // If not date specific, create a single inventory item with a null date + if (!$ticketDetail['date_specific']['value']) { + + $sql = "INSERT INTO eventmgt.ticket_inventory + (ticket, member, quant, available, ticket_date, ticket_time, sold, active) + values + ($ticket, $member, $quant, $quant, null, $time, 0, true);\n"; + + } else { + + // For each day of the performance + $sql = ''; + for ($date = $start; $date <= $end; $date = strtotime(date('m/d/Y', $date).' +1 day')) { + $dateText = date('m/d/Y', $date); + + // Check day of week settings and create inventory accordingly + $dow = date('w', $date); + if ($ticketDetail['days_of_week']['bitmap'][$dow]['default']) { + $sql .= "INSERT INTO eventmgt.ticket_inventory + (ticket, member, quant, available, ticket_date, ticket_time, sold, active) + values + ($ticket, $member, $quant, $quant, '$dateText', $time, 0, true);\n"; + } + + } + } + + if ($sql != '') { + $this->dbh->exec($sql); + } + + return true; + } + + return false; + + } +} + +?> \ No newline at end of file diff --git a/models/admin/classes/tickets.php b/models/admin/classes/tickets.php new file mode 100644 index 0000000..7cc2380 --- /dev/null +++ b/models/admin/classes/tickets.php @@ -0,0 +1,82 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: classes/tickets.php,v 1.0 2011/01/25 19:31:47 cscott Exp $ + * @link <> + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'classes/data/dataTickets.php'; + +/** + * EventManagementAdminContacts class + * + * Event Management and Reservations System - Admin Code - Contacts ticket + * + * PHP version 5 + * + * @category Event Management Admin Tickets + * @package EventManagement + * @author Chuck Scott + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: classes/tickets.php,v 1.0 2011/01/25 19:31:47 cscott Exp $ + * @link <> + */ + +class EventManagementAdminTickets extends EventManagementDataTickets +{ + /** + * Configuration information object + * @var $ini + * @access public + */ + public $config; + /** + * Database Object + * @var $dbh + * @access public + */ + public $dbh; + /** + * Data Definitions Object + * @var $dbh + * @access public + */ + public $data; + + + /** + * Get Tickets Stats + * + * @return object containing array as sub-objects + */ + function getMemberTicketsStats($memberID = false) + { + // Get member ID from session - if available get stats for member + if ($memberID || ($memberID = $_SESSION[GLM_EVENT_SESSION]['Member'])) { + return $this->getStats("member = $memberID"); + } + return 0; + } + function getTicketsStats() + { + $ticketsStats = array( + 'all' => $this->getStats(), + 'member' => $this->getMemberTicketsStats() + ); + + return $ticketsStats; + } + + +} + +?> \ No newline at end of file diff --git a/models/admin/classes/voucherCoupons.php b/models/admin/classes/voucherCoupons.php new file mode 100755 index 0000000..727b0d6 --- /dev/null +++ b/models/admin/classes/voucherCoupons.php @@ -0,0 +1,68 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: classes/voucherCoupons.php,v 1.0 2011/01/25 19:31:47 cscott Exp $ + * @link <> + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'classes/data/dataVoucherCoupons.php'; + +/** + * EventManagementAdminVoucherCoupons class + * + * Event Management and Reservations System - Admin Code - Voucher Coupons section + * + * PHP version 5 + * + * @category Event Management Admin Voucher Coupons + * @package EventManagement + * @author Chuck Scott + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: classes/voucherCoupons.php,v 1.0 2011/01/25 19:31:47 cscott Exp $ + * @link <> + */ +class EventManagementAdminVoucherCoupons extends EventManagementDataVoucherCoupons +{ + /** + * Configuration information object + * @var $config + * @access public + */ + public $config; + /** + * Database Object + * @var $dbh + * @access public + */ + public $dbh; + /** + * Data Definitions Object + * @var $data + * @access public + */ + public $data; + + /** + * Get Voucher Coupons Stats + * + * @return object containing array as sub-objects + */ + function getVoucherCouponsStats() + { + return $this->getStats(); + + return 0; + } + +} + +?> \ No newline at end of file diff --git a/models/front/actions/Debug/start.inc b/models/front/actions/Debug/start.inc new file mode 100644 index 0000000..d07c4fc --- /dev/null +++ b/models/front/actions/Debug/start.inc @@ -0,0 +1,19 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: event.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +$this->page->debugStartupTime = date('m/d/Y H:i:s'); +$this->templateFile = 'Debug/index.html'; + +?> + diff --git a/models/front/actions/Debug/update.inc b/models/front/actions/Debug/update.inc new file mode 100644 index 0000000..6a7e9e6 --- /dev/null +++ b/models/front/actions/Debug/update.inc @@ -0,0 +1,29 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: event.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +$this->page->debugUpdateTime = date('m/d/Y H:i:s'); + +// If there's nothing to send, then don't +if (!file_exists(DEBUG_DATA_FILENAME)) { + exit; +} + +// Otherwise, send the current debug data +$this->page->debugData = file_get_contents(DEBUG_DATA_FILENAME); +unlink(DEBUG_DATA_FILENAME); + +$this->templateFile = 'Debug/index.html'; + +?> + diff --git a/models/front/actions/Index/index.inc b/models/front/actions/Index/index.inc new file mode 100644 index 0000000..bbd56e5 --- /dev/null +++ b/models/front/actions/Index/index.inc @@ -0,0 +1,21 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: event.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +// Reset Session +$this->startSession(true); + +$this->templateFile = "index.html"; + +?> + diff --git a/models/front/actions/Shop/PayPal.inc b/models/front/actions/Shop/PayPal.inc new file mode 100644 index 0000000..a571bef --- /dev/null +++ b/models/front/actions/Shop/PayPal.inc @@ -0,0 +1,110 @@ +dbh, $this->config); +$cart = $Support->checkCart(); +$this->addDebug("Shop/checkoutSubmit.inc", 'Array: $cart', print_r($cart['cartData'],1)); + +// Get selected cart data +$memberID = ($_REQUEST['memberID']-0); +$cartEntry = $cart['cartData'][$memberID]; + +// If we can't find the correct cart entry +if (!is_array($cartEntry)) { + + $this->templateFile = "Shop/PayPalFail.html"; + + // We have the correct cart entry +} else { + + // Prepare for purchase authorization request with PayPal REST API + $account = array( + 'clientID' => $cartEntry['paypal_client_id'], + 'secret' => $cartEntry['paypal_secret'], + 'test' => $cartEntry['paypal_mode']['value'], + 'returnURL' => $this->page->baseURL."?Action=Shop_PayPalApproved&memberID=$memberID", + 'cancelURL' => $this->page->baseURL."?Action=Shop_PayPalCanceled&memberID=$memberID", + ); + $payment = array( + 'name' => $cartEntry['name'], + 'charge' => $cartEntry['totalPrice_numb'], + 'invoice' => '', + 'description' => $config->term->event->cap.' Tickets', + 'items' => array( + ) + ); + $contact = array(); + + // Build items array from cart data + $items = array(); + // For each date of tickets + foreach ($cartEntry['dates'] as $d) { + + // For each Performance + foreach ($d['performances'] as $p) { + + // For each Section + foreach ($p['sections'] as $s) { + + // For each ticket + foreach ($s['tickets'] as $t) { + + // Add this cart selection + $payment['items'][] = array( + 'quantity' => $t['selected'], + 'name' => $p['name'].", ".$d['date'].", ".$s['name'].", ".$t['name'], + 'price' => $t['price_numb'], + 'sku' => $t['invID'] + ); + + } + + } + + } + + } + + + // Create the PayPal object (note no previous access object) + $PayPal = new PayPalPaymentGateway($account, false, false); + + // Was there an error? + if (!$PayPal->status) { + echo "Received an error: ".$PayPal->error; + exit; + } + + // Try to enter Payment + $PayPal->processPayment($payment, $contact); + + // Was there an error? + if (!$PayPal->status) { + echo "Received an error: ".$PayPal->error; + exit; + } + + // Store access information + $_SESSION[GLM_EVENT_MGT_FRONT]['PayPal'][$memberID] = array( + 'account' => $account, + 'access' => $PayPal->access, + 'trans' => $PayPal->trans, + 'cart' => $cartEntry + ); + + // Show user link to PayPal for them to approve payment + // Note that uses a target to create a new window/tab + // Use browser redirect 302 to send user to PayPal. + // This is proper way to do so according to the API documentation. + header('Location: '.$PayPal->trans->urls->approval_url->href); + exit; + +} + +?> \ No newline at end of file diff --git a/models/front/actions/Shop/PayPalApproved.inc b/models/front/actions/Shop/PayPalApproved.inc new file mode 100644 index 0000000..866fb8e --- /dev/null +++ b/models/front/actions/Shop/PayPalApproved.inc @@ -0,0 +1,96 @@ +dbh, $this->config); +$cart = $Support->checkCart(); +$this->addDebug("Shop/checkoutSubmit.inc", 'Array: $cart', print_r($cart['cartData'],1)); + +// Get selected cart data +$memberID = ($_REQUEST['memberID']-0); +$cartEntry = $cart['cartData'][$memberID]; + +// If we can't find the correct cart entry +if (!is_array($cartEntry)) { + + $this->templateFile = "Shop/PayPalFail.html"; + +// We have the correct cart entry +} else { + + // Prepare to execute payment with PayPal REST API + $account = array( + 'clientID' => $cartEntry['gateway_par1'], + 'secret' => $cartEntry['gateway_par2'], + 'test' => $cartEntry['gateway_par3']['value'], + 'returnURL' => $this->page->baseURL."?Action=Shop_PayPalApproved&memberID=$memberID", + 'cancelURL' => $this->page->baseURL."?Action=Shop_PayPalCanceled&memberID=$memberID", + ); + + // Save Payer ID + $_SESSION[GLM_EVENT_MGT_FRONT]['PayPal'][$memberID]['payerID'] = $_REQUEST['PayerID']; // NEED TO FILTER THIS FOR PRODUCTION + + // Create PayPal object with existing access object from the session + $PayPal = new PayPalPaymentGateway( + $_SESSION[GLM_EVENT_MGT_FRONT]['PayPal'][$memberID]['account'], + $_SESSION[GLM_EVENT_MGT_FRONT]['PayPal'][$memberID]['access'], + $_SESSION[GLM_EVENT_MGT_FRONT]['PayPal'][$memberID]['trans'] + ); + + // Execute the PayPal payment + $payerID = $_REQUEST['PayerID']; + $r = $PayPal->executePayment($payerID); + + // Check if payment executed correctly + if ($r['status']) { + + $payment = array( + 'id' => $memberID, + 'status' => true, + 'type' => 'pp', + 'statusText' => $r['statusText'], + 'authCode' => '', + 'description' => $r['description'], + 'newApproval' => false, + 'spec_req' => '', + 'approved' => true, + 'cctype' => array('name' => 'PayPal'), + 'ccname' => array('value' => $r['payerName']), + 'ccexp' => array('value' => ''), + 'ccnumb' => '', + 'orderID' => '' + ); +var_dump($payment); + + // Store order + $cart = $_SESSION[GLM_EVENT_MGT_FRONT]['PayPal'][$memberID]['cart']; + $contact = $_SESSION[GLM_EVENT_MGT_FRONT]['ContactInput']; + + require_once EVENT_MANAGEMENT_APP_BASE.'models/front/classes/checkoutSupport.php'; + $CheckoutSupport = new EventManagementFrontCheckoutSupport($this->dbh, $this->config, $Support); +var_dump($contact); + $orderID = $CheckoutSupport->storePurchase($cart, $contact, $payment); +echo "Order ID = $orderID

    "; + + // Need to send E-Mail to customer + + + + $this->templateFile = "Shop/PayPalApproved.html"; + + + // Otherwise the payment didn't execute correctly + } else { + + $this->templateFile = "Shop/PayPalFail.html"; + + } + +} + +?> \ No newline at end of file diff --git a/models/front/actions/Shop/additionalInfo.inc b/models/front/actions/Shop/additionalInfo.inc new file mode 100755 index 0000000..348b5b5 --- /dev/null +++ b/models/front/actions/Shop/additionalInfo.inc @@ -0,0 +1,177 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: cart.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +// If this is a home page ticket selection, save default member +if (isset($_REQUEST['locationSelect'])) { + $_SESSION['GLM_EVENT_MGT_FRONT']['Member'] = ($_REQUEST['locationSelect']-0); +} + +// Load the front-end support class +require_once EVENT_MANAGEMENT_APP_BASE.'models/front/classes/support.php'; +$Support = new EventManagementFrontSupport($this->dbh, $this->config); + +// If cart sticky is enables +if ($this->config->option->ticket_selection->show_cart_sticky_items) { + + // Get list of cart sticky items - Items that always display in the cart even if there's no quant selected + $cartSticky = $Support->getCartStickyInventory(); + + // Default all current cart entries to sticky = false (will be updated if they're sticky) + while (list($k, $v) = each($cartSticky)) { + $cartSticky[$k]['sticky'] = false; + } + +} + +// Check if there's any promo codes +require_once EVENT_MANAGEMENT_APP_BASE.'classes/data/dataPromos.php'; +$Promos = new EventManagementDataPromos($this->dbh, $this->config); +$promoList = $Promos->getList(); +$this->page->havePromoCodes = false; +if (is_array($promoList) && count($promoList) > 0) { + $this->page->havePromoCodes = true; +} + +// Check for Promo Code Selection +if (isset($_REQUEST['cart']) && $_REQUEST['cart'] == 'promo_code') { + $promo_code = filter_input(INPUT_GET, 'promo_code', FILTER_SANITIZE_STRING); + $_SESSION['GLM_EVENT_MGT_FRONT']['PromoCode'] = $promo_code; + +} elseif (isset($_SESSION['GLM_EVENT_MGT_FRONT']['PromoCode'])) { + $promo_code = $_SESSION['GLM_EVENT_MGT_FRONT']['PromoCode']; +} + +// Check if we're getting a selection of assignment to a member/location +if ($_REQUEST['cart'] == 'update_assignment') { + + // If we don't have an assignment session array, start one + if (!isset($_SESSION['GLM_EVENT_MGT_FRONT']['Assignment'])) { + $_SESSION['GLM_EVENT_MGT_FRONT']['Assignment'] = array(); + } + + // Add/update this assignment + $_SESSION['GLM_EVENT_MGT_FRONT']['Assignment'][($_REQUEST['member_assigned']-0)] = ($_REQUEST['assigned_to']-0); + + // Also check if we need to handle entrance assignment + unset($_SESSION['GLM_EVENT_MGT_FRONT']['AssignmentEntrance'][($_REQUEST['member_assigned']-0)]); + if ($this->config->option->ticket_selection->select_entrance_on_consignment && + isset($_REQUEST['entrance_assigned']) && ($_REQUEST['entrance_assigned']-0) > 0 ) { + // Add/update entrance assignment + $_SESSION['GLM_EVENT_MGT_FRONT']['AssignmentEntrance'][($_REQUEST['member_assigned']-0)] = ($_REQUEST['entrance_assigned']-0); + } + +} + +// Check if we're getting selection of a likely departure date +if ($_REQUEST['cart'] == 'update_likelyDate') { + + // If we don't have a likely date array, start one + if (!isset($_SESSION['GLM_EVENT_MGT_FRONT']['LikelyDate'])) { + $_SESSION['GLM_EVENT_MGT_FRONT']['LikelyDate'] = array(); + } + + // Validate likely date and store if it's sane + $likelyDate = date('m/d/Y', strtotime($_REQUEST['likely_date'])); + if ($likelyDate != '12/31/1969') { + $_SESSION['GLM_EVENT_MGT_FRONT']['LikelyDate'][($_REQUEST['member']-0)] = $likelyDate; + } else { + $_SESSION['GLM_EVENT_MGT_FRONT']['LikelyDate'][($_REQUEST['member']-0)] = ''; + } + +} + +// If cart sticky items is enabled and we have any cart sticky items +$haveCartStickyItems = false; +if ($this->config->option->ticket_selection->show_cart_sticky_items && $cartSticky) { + + $haveCartStickyItems = true; + + $this->addDebug("Shop/cart.inc", 'Array: $cartSticky', print_r($cartSticky,1)); + + // Make sure cart sticky inventory is in cart + foreach ($cartSticky as $c) { + + // Check if there's no cart entry for this cart sticky item + if (!isset($_SESSION['GLM_EVENT_MGT_FRONT']['TicketCart'][$c['id']])) { + + // Add to cart + $_SESSION['GLM_EVENT_MGT_FRONT']['TicketCart'][$c['id']] = array( + 'invenID' => $c['id'], + 'member' => $c['member'], + 'assigned' => false, + 'quant' => 0 + ); + } + + // Mark entry as Sticky + $_SESSION['GLM_EVENT_MGT_FRONT']['TicketCart'][$c['id']]['sticky'] = true; + + } + +} + +// Check if there's been anything added to the cart and get cart contents +$cart = $Support->checkCart(); + +// If we're already locked into checkout, go there +if ($cart['forceCheckoutPhase']) { + $this->reason[] = 'You have partially paid for your purchases. We have returned you to checkout to complete your purchase.'; + include EVENT_MANAGEMENT_APP_BASE.'models/front/actions/Shop/checkout.inc'; + return; +} + +// If there's no cart contents, make sure there's no cart array. +if (!$cart['cartHasContents']) { + $_SESSION['GLM_EVENT_MGT_FRONT']['TicketCart'] = false; +} + +// If we're doing cart promotions, get any performances with promote_on_cart set +if ($this->config->option->cart_promotions) { + $cartPromotions = $Support->getCartPromotions(); + if ($cartPromotions) { + $this->page->cartPromotions = $this->bindArrayToObject($cartPromotions); + } +} + +//var_dump($this->page->cartPromotions); + +// Check if we received a vertical scroll position +$vertScroll = 0; +if ($_REQUEST['vertScroll']) { + $vertScroll = ($_REQUEST['vertScroll']-0); +} +$this->page->vertScroll = $vertScroll; + +// Otherwise we're OK to continue showing the cart +$this->page->promoCode = $promo_code; +$this->page->blockCheckout = $cart['blockCheckout']; +$this->page->blockCheckoutNonAssignment = $cart['blockCheckoutNonAssignment']; +$this->page->haveCartStickyItems = $haveCartStickyItems; +$this->page->cartHasContents = $cart['cartHasContents']; +$this->page->cartHasOneVenueOnly = $cart['cartHasOneVenueOnly']; +$this->page->cart = $this->bindArrayToObject($cart['cartDataReorganized']); // Use reorganized cart +$this->page->totals = $this->bindArrayToObject($cart['totals']); +$this->reason = array_merge($this->reason, $cart['reason']); + +if ($cart['blockCheckoutNonAssignment']) { + $this->templateFile = "Shop/cart.html"; +} else { + $this->templateFile = "Shop/additionalInfo.html"; +} + +$this->addDebug("Shop/cart.inc", 'Array: $totals', print_r($cart['totals'],1)); +$this->addDebug("Shop/cart.inc", 'Array: $cart', print_r($rCart,1)); + +?> + diff --git a/models/front/actions/Shop/cart.inc b/models/front/actions/Shop/cart.inc new file mode 100644 index 0000000..2232bc0 --- /dev/null +++ b/models/front/actions/Shop/cart.inc @@ -0,0 +1,203 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: cart.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +// If this is a home page ticket selection, save default member +if (isset($_REQUEST['locationSelect'])) { + $_SESSION['GLM_EVENT_MGT_FRONT']['Member'] = ($_REQUEST['locationSelect']-0); +} + +// Load the front-end support class +require_once EVENT_MANAGEMENT_APP_BASE.'models/front/classes/support.php'; +$Support = new EventManagementFrontSupport($this->dbh, $this->config); + +// If cart sticky is enables +if ($this->config->option->ticket_selection->show_cart_sticky_items) { + + // Get list of cart sticky items - Items that always display in the cart even if there's no quant selected + $cartSticky = $Support->getCartStickyInventory(); + + // Default all current cart entries to sticky = false (will be updated if they're sticky) + while (list($k, $v) = each($cartSticky)) { + $cartSticky[$k]['sticky'] = false; + } + +} + +// Check if there's any promo codes +require_once EVENT_MANAGEMENT_APP_BASE.'classes/data/dataPromos.php'; +$Promos = new EventManagementDataPromos($this->dbh, $this->config); +$promoList = $Promos->getList(); +$this->page->havePromoCodes = false; +if (is_array($promoList) && count($promoList) > 0) { + $this->page->havePromoCodes = true; +} + +// Check for Promo Code Selection +if (isset($_REQUEST['cart']) && $_REQUEST['cart'] == 'promo_code') { + $promo_code = filter_input(INPUT_GET, 'promo_code', FILTER_SANITIZE_STRING); + $_SESSION['GLM_EVENT_MGT_FRONT']['PromoCode'] = $promo_code; +} elseif (isset($_SESSION['GLM_EVENT_MGT_FRONT']['PromoCode'])) { + $promo_code = $_SESSION['GLM_EVENT_MGT_FRONT']['PromoCode']; +} + +// Check if we're getting a selection of assignment to a member/location +if ($_REQUEST['cart'] == 'update_assignment') { + + // If we don't have an assignment session array, start one + if (!isset($_SESSION['GLM_EVENT_MGT_FRONT']['Assignment'])) { + $_SESSION['GLM_EVENT_MGT_FRONT']['Assignment'] = array(); + } + + // Add/update this assignment + $_SESSION['GLM_EVENT_MGT_FRONT']['Assignment'][($_REQUEST['member_assigned']-0)] = ($_REQUEST['assigned_to']-0); + + // Also check if we need to handle entrance assignment + unset($_SESSION['GLM_EVENT_MGT_FRONT']['AssignmentEntrance'][($_REQUEST['member_assigned']-0)]); + if ($this->config->option->ticket_selection->select_entrance_on_consignment && + isset($_REQUEST['entrance_assigned']) && ($_REQUEST['entrance_assigned']-0) > 0 ) { + // Add/update entrance assignment + $_SESSION['GLM_EVENT_MGT_FRONT']['AssignmentEntrance'][($_REQUEST['member_assigned']-0)] = ($_REQUEST['entrance_assigned']-0); + } + +} + +// Check if we're getting selection of a likely departure date +if ($_REQUEST['cart'] == 'update_likelyDate') { + + // If we don't have a likely date array, start one + if (!isset($_SESSION['GLM_EVENT_MGT_FRONT']['LikelyDate'])) { + $_SESSION['GLM_EVENT_MGT_FRONT']['LikelyDate'] = array(); + } + + // Validate likely date and store if it's sane + $likelyDate = date('m/d/Y', strtotime($_REQUEST['likely_date'])); + if ($likelyDate != '12/31/1969') { + $_SESSION['GLM_EVENT_MGT_FRONT']['LikelyDate'][($_REQUEST['member']-0)] = $likelyDate; + } else { + $_SESSION['GLM_EVENT_MGT_FRONT']['LikelyDate'][($_REQUEST['member']-0)] = ''; + } + +} + +// If cart sticky items is enabled and we have any cart sticky items +$haveCartStickyItems = false; +if ($this->config->option->ticket_selection->show_cart_sticky_items && $cartSticky) { + + $haveCartStickyItems = true; + + $this->addDebug("Shop/cart.inc", 'Array: $cartSticky', print_r($cartSticky,1)); + + // Make sure cart sticky inventory is in cart + foreach ($cartSticky as $c) { + + // Check if there's no cart entry for this cart sticky item + if (!isset($_SESSION['GLM_EVENT_MGT_FRONT']['TicketCart'][$c['id']])) { + + // Add to cart + $_SESSION['GLM_EVENT_MGT_FRONT']['TicketCart'][$c['id']] = array( + 'invenID' => $c['id'], + 'member' => $c['member'], + 'assigned' => false, + 'quant' => 0 + ); + } + + // Mark entry as Sticky + $_SESSION['GLM_EVENT_MGT_FRONT']['TicketCart'][$c['id']]['sticky'] = true; + + } + +} + +// Check if there's been anything added to the cart and get cart contents +$cart = $Support->checkCart(); +; +// If we're already locked into checkout, go there +if ($cart['forceCheckoutPhase']) { + $this->reason[] = 'You have partially paid for your purchases. We have returned you to checkout to complete your purchase.'; + include EVENT_MANAGEMENT_APP_BASE.'models/front/actions/Shop/checkout.inc'; + return; +} + +// If there's no cart contents, make sure there's no cart array. +if (!$cart['cartHasContents'] || count($cart['cartDataReorganized']) == 0) { + $_SESSION['GLM_EVENT_MGT_FRONT']['TicketCart'] = false; + + $cart['cartHasContents'] = false; +// Otherwise check that we're not mixing no-payment location with other locations +$this->page->blockCheckoutMixedPayment = false; +} else { + + $paid = false; + $nonpaid = false; + + // For each venu in the cart + foreach ($cart['cartDataReorganized'] as $c) { + + // Check for mix of credit card and manual payment + if ($c['payment_gateway']['value'] == 3) { + $nonpaid = true; + } else { + $paid = true; + } + + } + + // If there's a mix, warn the user and don't permit checkout. + if ($paid && $nonpaid) { + $this->reason[] = 'Mixing of credit card purchases and manual payment is not supported at this time.'; + $this->page->blockCheckoutMixedPayment = true; + } + +} + + +// If we're doing cart promotions, get any performances with promote_on_cart set +if ($this->config->option->cart_promotions) { + $cartPromotions = $Support->getCartPromotions(); + if ($cartPromotions) { + $this->page->cartPromotions = $this->bindArrayToObject($cartPromotions); + } +} + +// echo "

    ".print_r($cart,1)."
    "; +// var_dump($this->page->cartPromotions); + +// Check if we received a vertical scroll position +$vertScroll = 0; +if ($_REQUEST['vertScroll']) { + $vertScroll = ($_REQUEST['vertScroll']-0); +} +$this->page->vertScroll = $vertScroll; + +// Otherwise we're OK to continue showing the cart +$this->page->promoCode = $promo_code; +$this->page->blockCheckout = $cart['blockCheckout']; +$this->page->blockCheckoutNonAssignment = $cart['blockCheckoutNonAssignment']; +$this->page->doingAdditionalInfo = $cart['doingAdditionalInfo']; +$this->page->haveCartStickyItems = $haveCartStickyItems; +$this->page->cartHasContents = $cart['cartHasContents']; +$this->page->cartHasOneVenueOnly = $cart['cartHasOneVenueOnly']; +$this->page->cart = $this->bindArrayToObject($cart['cartDataReorganized']); // Use reorganized cart +$this->page->totals = $this->bindArrayToObject($cart['totals']); +$this->reason = array_merge($this->reason, $cart['reason']); +$this->page->reason = $this->bindArrayToObject($this->reason); + +$this->templateFile = "Shop/cart.html"; + +$this->addDebug("Shop/cart.inc", 'Array: $totals', print_r($cart['totals'],1)); +$this->addDebug("Shop/cart.inc", 'Array: $cart', print_r($rCart,1)); + +?> + diff --git a/models/front/actions/Shop/checkout.inc b/models/front/actions/Shop/checkout.inc new file mode 100644 index 0000000..bd84346 --- /dev/null +++ b/models/front/actions/Shop/checkout.inc @@ -0,0 +1,224 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: checkout.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +// Select the front-end support class +require_once EVENT_MANAGEMENT_APP_BASE.'models/front/classes/support.php'; +$Support = new EventManagementFrontSupport($this->dbh, $this->config); +require_once EVENT_MANAGEMENT_APP_BASE.'models/front/classes/checkoutSupport.php'; +$CheckoutSupport = new EventManagementFrontCheckoutSupport($this->dbh, $this->config, $Support); + +// Clear any 0 quantity items from cart - This purges any 0 quant sticky items before trying to checkout +if (is_array($_SESSION['GLM_EVENT_MGT_FRONT']['TicketCart']) && count($_SESSION['GLM_EVENT_MGT_FRONT']['TicketCart']) > 0) { + foreach ($_SESSION['GLM_EVENT_MGT_FRONT']['TicketCart'] as $c) { + if ($c['quant'] == 0) { + unset($_SESSION['GLM_EVENT_MGT_FRONT']['TicketCart'][$c['invenID']]); + } + } +} + +// Check if we're coming back from checkoutSubmit.inc and already have cart data +if (isset($checkoutCart)) { + $cart = $checkoutCart; +} else { + // Check if there's been anything added to the cart and get cart contents (say we're doing checkout) + $cart = $Support->checkCart(true); +} + +if (!$cart['cartHasContents']) { + $this->reason[] = 'Your cart is currently empty.'; + include EVENT_MANAGEMENT_APP_BASE.'models/front/actions/Shop/cart.inc'; + return; +} +$this->page->cartHasContents = true; + +// Check if there been partial payment and we're in a forced checkout phase - no cart changes or additions +$this->page->forceCheckoutPhase = $cart['forceCheckoutPhase']; + +// Get a clear input value array and place payment data under each venue in $cart +if (!isset($checkoutReturnFlag) || $checkoutReturnFlag == false ) { + $formData = $CheckoutSupport->checkoutInit($cart['cartData']); +} + +// Is there central payment? +if ($formData['centralPayment']) { + + // Just a shortcut to the member data + $cpMemb = $formData['centralPayment']['membData']; + + $cp = array( + 'havePayPal' => false, + 'haveCreditCards' => false, + 'havePaymentMethod' => false, + 'haveMultiplePaymentMethods' => false, + 'paymentForm' => $formData['payment'] + ); + + // Check credit card payment setup for venu + if ( + $cpMemb['payment_gateway']['value'] > 0 // Have processor selected + && count($cpMemb['cards_accepted']['names']) > 0 // Have credit cards selected + ) { + + // Check for any needed gateway authentication information + $haveAuth = false; + switch($cpMemb['payment_gateway']['value']) { + case $this->config->ccard_processor_numb->authorize_net: + if ($cpMemb['gateway_par1'] != '' && $cpMemb['gateway_par2'] != '') { + $haveAuth = true; + } + break; + case $this->config->ccard_processor_numb->merchant_solutions: + if ($cpMemb['gateway_par1'] != '' && $cpMemb['gateway_par2'] != '') { + $haveAuth = true; + } + break; + case $this->config->ccard_processor_numb->test: + $haveAuth = true; + break; + } + + if ($haveAuth) { + + // Have good credit card gateway, have cards, have authentication + $cp['haveCreditCards'] = true; + $cp['havePaymentMethod'] = true; + } + } + + // Check if we have PayPal authentication data + if ( + $cpMemb['paypal']['value'] && + $cpMemb['paypal_client_id'] != '' && + $cpMemb['paypal_secret'] != '' + ){ + $cp['havePayPal'] = true; + $cp['havePaymentMethod'] = true; + + } + + // Check if we have multiple payment methods for this member + if ($cp['haveCreditCards'] && $cp['havePayPal']) { + $cp['haveMultiplePaymentMethods'] = true; + } + + $formData['centralPayment'] = array_merge($formData['centralPayment'], $cp); + +} else { + + // Not doing Central Payment + + if (is_array($formData['payment'])) { + + foreach ($formData['payment'] as $p) { + + // set shortcut to cart member/venue + $cm = &$cart['cartDataReorganized'][$p['id']]; + + // Add payment information + $cm['paymentForm'] = $p; + + // Also check for valid payment methods + $cm['havePayPal'] = false; + $cm['haveCreditCards'] = false; + $cm['havePaymentMethod'] = false; + $cm['haveMultiplePaymentMethods'] = false; + if ( + $cm['payment_gateway']['value'] > 0 // Have processor selected + && count($cm['cards_accepted']['names']) > 0 // Have credit cards selected + ) { + // Check for any needed gateway authentication information + $haveAuth = false; + switch($cm['payment_gateway']['value']) { + case $this->config->ccard_processor_numb->authorize_net: + if ($cm['gateway_par1'] != '' && $cm['gateway_par2'] != '') { + $haveAuth = true; + } + break; + case $this->config->ccard_processor_numb->merchant_solutions: + if ($cm['gateway_par1'] != '' && $cm['gateway_par2'] != '') { + $haveAuth = true; + } + break; + case $this->config->ccard_processor_numb->test: + $haveAuth = true; + break; + } + + if ($haveAuth) { + // Have good credit card gateway, have cards, have authentication + $cm['haveCreditCards'] = true; + $cm['havePaymentMethod'] = true; + } + } + + // Check if we have PayPal authentication data + if ( + $cm['paypal']['value'] && + $cm['paypal_client_id'] != '' && + $cm['paypal_secret'] != '' + ) { + $cm['havePayPal'] = true; + $cm['havePaymentMethod'] = true; + + } + + // Check if we have multiple payment methods for this member + if ($cm['haveCreditCards'] && $cm['havePayPal']) { + $cm['haveMultiplePaymentMethods'] = true; + } + + } + } +} + +// If this an admin user +$noPaymentReasons = false; +if ($this->page->adminUser) { + + // Get the misc settings + require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/misc.php'; + $Misc = new EventManagementAdminMisc($this->dbh, $this->config); + $miscDetail = $Misc->getEntry(1); + + // If we have reasons for no payment + if (trim($miscDetail['no_payment_reasons']) != '') { + + // Break it into an array and add to page data + $noPaymentReasons = explode(PHP_EOL, $miscDetail['no_payment_reasons']); + $this->page->noPaymentReasons = $noPaymentReasons; + + } + +} + + +unset($formData['payment']); + +// Otherwise we're OK to continue showing the cart +$this->page->promoCode = $_SESSION['GLM_EVENT_MGT_FRONT']['PromoCode']; +$this->page->cartHasContents = $cart['cartHasContents']; +$this->page->cart = $this->bindArrayToObject($cart['cartDataReorganized']); +$this->page->cartHasOneVenueOnly = $cart['cartHasOneVenueOnly']; +$this->page->cartRequiresPayment = $cart['cartRequiresPayment']; +$this->page->totals = $this->bindArrayToObject($cart['totals']); +$this->page->formData = $this->bindArrayToObject($formData); // Blank form data for cleared fields +$this->reason = array_merge($this->reason, $cart['reason']); + +$this->templateFile = "Shop/checkout.html"; + +$this->addDebug("Shop/checkout.inc", 'Array: $totals', print_r($cart['totals'],1)); +$this->addDebug("Shop/checkout.inc", 'Array: $cart', print_r($cart['cartData'],1)); +$this->addDebug("Shop/checkout.inc", 'Array: $formData', print_r($formData,1)); +?> + diff --git a/models/front/actions/Shop/checkoutSubmit.inc b/models/front/actions/Shop/checkoutSubmit.inc new file mode 100644 index 0000000..dea6f69 --- /dev/null +++ b/models/front/actions/Shop/checkoutSubmit.inc @@ -0,0 +1,323 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: checkout.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +// Select the front-end support class +require_once EVENT_MANAGEMENT_APP_BASE.'models/front/classes/support.php'; +$Support = new EventManagementFrontSupport($this->dbh, $this->config); + +/* + * Start by checking the cart and getting cart contents + */ +$cart = $Support->checkCart(true); + +// Assume we don't have to return to checkout +$checkoutReturnFlag = false; + +// Need this before we put together the E-Mail summaries +$this->page->promoCode = $_SESSION['GLM_EVENT_MGT_FRONT']['PromoCode']; + +// Check if there hasn't been a complete checkout yet. +if (!$cart['checkoutComplete']) { + + // Check for empty cart + if (!$cart['cartHasContents']) { + $this->reason[] = 'Your cart is currently empty.'; + include EVENT_MANAGEMENT_APP_BASE.'models/front/actions/Shop/cart.inc'; + return; + } + + // If there's a problem with the cart, send the user back to the cart page + if ($cart['status'] == false) { + $this->reason = array_merge($this->reason, $cart['reason']); + include EVENT_MANAGEMENT_APP_BASE.'models/front/actions/Shop/checkout.inc'; + return; + } + + /* + * Check the submitted input for required and valid fields + */ + + // Load checkout support class + require_once EVENT_MANAGEMENT_APP_BASE.'models/front/classes/checkoutSupport.php'; + $CheckoutSupport = new EventManagementFrontCheckoutSupport($this->dbh, $this->config, $Support); + + // Check submitted input to see if we have everything we need from the user + // Supply that data to the page and place payment data under each venue + $formData = $CheckoutSupport->checkoutInput($cart['cartDataReorganized']); + + if ($formData != false) { + + + // If we didn't receive all needed input, display checkout form again + if (!$formData['status']) { + $checkoutReturnFlag = true; + $this->reason = array_merge($this->reason, $formData['reason']); + include EVENT_MANAGEMENT_APP_BASE.'models/front/actions/Shop/checkout.inc'; + return; + } + + // If we have Central Payment + if ($formData['centralPayment']) { + + $membID = $formData['centralPayment']['membData']['id']; + + // Check if reorganized cart data doesn't have central billing member. + if (!isset($cart['cartDataReorganized'][$membID])) { + + // Didn't have it, so add the venue data now + $cart['cartDataReorganized'][$membID] = $formData['centralPayment']['membData']; + + // Also flag that it's member data without any performances selected + $cart['cartDataReorganized'][$membID]['centralPaymentOnly'] = true; + } else { + $cart['cartDataReorganized'][$membID]['centralPaymentOnly'] = false; + } + + // Mark the central billing member cart entry + $cart['cartDataReorganized'][$membID]['isCentralPaymentMember'] = true; + + } + + // Provide all cart and payment data back to the page for display + $this->page->formData = $this->bindArrayToObject($formData); + + /* + * Try to process all payments - Supply our cart information and all user submitted information + */ + $paymentResult = $CheckoutSupport->checkoutProcessPayments($cart['cartDataReorganized'], $formData); + + // Inject payment results into cartData array and session data +// foreach($paymentResult['payments'] as $r) { + while (list($key, $r) = each($paymentResult['payments'])) { + + // Make sure there's a card ID in the payments entry. + $r['id'] = $key; + + // If there's a payment error - Save that + if ($r['description'] != '') { + $this->reason[] = $r['description']; + } + + // Create MD5 Check for access to order - Keeps people from tampering with ID # in URL line. + $r['orderVerification'] = md5($r['orderID'].$this->config->orderVerificationSecret); + + // Place payment result under reorganized cart data for output + $cart['cartDataReorganized'][$r['id']]['paymentResult'] = $r; + + // If this is a newly completed payment - Send all appropriate notices for this order + if ($r['newApproval']) { + + // Get customer confirmation E-Mail + $sql = " + SELECT name, email, proc_email, proc_email2, checkout_email, checkout_notify + FROM eventmgt.member + WHERE id = ".$r['id']." + ;"; + $stmt = $this->dbh->prepare($sql); + $stmt->execute(); + $membData = $stmt->fetch(PDO::FETCH_ASSOC); + + // Get any confirmation E-Mail content from Performances (only one per performance type) + $confTextArray = array(); + + if (count($cart['cartDataReorganized'][$r['id']]['performances']) > 0) { + foreach($cart['cartDataReorganized'][$r['id']]['performances'] as $p) { + // If there's confirmation text for this performance, add it with index of the performance ID + if (trim($p['conf_text']) != '') { + $confTextArray[$p['id']] = trim($p['conf_text']); + } + + } + } + + // If there's any confirmation text from performances, compile it all into one string. + $confText = ''; + if (count($confTextArray) > 0) { + foreach($confTextArray as $ct) { + $confText .= "

    $ct

    \n"; + } + } + + $checkoutEmail = $membData['checkout_email']; + + // If we have confirmation E-Mail header text then include that + // Otherwise it will be blank and we'll just send summary + if ($checkoutEmail != '') { + + // Merge order data into E-Mail + $tags = array( + '{first-name}', + '{last-name}', + '{address-line-1}', + '{address-line-2}', + '{city}', + '{state}', + '{zip}', + '{country}', + '{'.$this->config->term->performance->norm.'-text}' + ); + $vals = array( + $formData['contact']['fname']['value'], + $formData['contact']['lname']['value'], + $formData['contact']['addr1']['value'], + $formData['contact']['addr2']['value'], + $formData['contact']['city']['value'], + $formData['contact']['state']['value'], + $formData['contact']['zip']['value'], + $formData['contact']['country']['value'], + $confText + ); + + $checkoutEmail = str_replace($tags, $vals, $checkoutEmail); + + } + + // Create Purchase Summary + $templateFile = "Shop/paymentSummary.html"; + + $this->page->cartForSummaryCentral = $this->bindArrayToObject($cart['cartDataReorganized']); + $this->page->cartEntry = $this->bindArrayToObject($cart['cartDataReorganized'][$r['id']]); + + $this->template->compile($this->userInterface.'/'.$templateFile); + $html_summary = $this->template->bufferedOutputObject($this->page); + unset($this->page->cartEntry); + + // Try to send E-Mail to customer + $email_content = "--ContentBoundry\n" + ."Content-Type: text/plain; charset=\"US-ASCII\"\n" + ."\n" + ."This message may only be read using an HTML enabled E-Mail client." + ."\n" + ."--ContentBoundry\n" + ."Content-Type: text/html; charset=\"US-ASCII\"\n" + ."\n" + .$checkoutEmail + ."\n" + .$html_summary + ."\n" + ."--ContentBoundry--\n" + ."\n"; + + $emailAddress = $formData['contact']['email']['value']; + if (!empty($emailAddress)) { + $this->debug_mail( + $emailAddress, + htmlspecialchars_decode($membData['name'],ENT_QUOTES).' Purchase Confirmation', + $email_content, + "From: ".htmlspecialchars_decode($membData['name'],ENT_QUOTES)." <".$membData['email'].">" + ."\nMime-Version: 1.0\nContent-Type: multipart/alternative; boundary=ContentBoundry\n" + ); +// This one goes to Chuck for testing. +/* + $this->debug_mail( + 'cscott@gaslightmedia.com', + htmlspecialchars_decode($membData['name'],ENT_QUOTES).' Purchase Confirmation', + $email_content, + "From: ".htmlspecialchars_decode($membData['name'],ENT_QUOTES)." <".$membData['email'].">" + ."\nMime-Version: 1.0\nContent-Type: multipart/alternative; boundary=ContentBoundry\n" + ); +*/ + } + + // If notifying member/venue + if ($membData['checkout_notify']) { + + // Build processing E-Mail addresses + $procEmail = $membData['proc_email']; + if ($membData['proc_email2'] != '') { + if ($procEmail != '') { + $procEmail .= ','; + } + $procEmail .= $membData['proc_email2']; + } + + // If we have a processing E-Mail address + if ($procEmail != '') { + + // Send E-Mail to member/venue + $email_content = "--ContentBoundry\n" + ."Content-Type: text/plain; charset=\"US-ASCII\"\n" + ."\n" + ."This message may only be read using an HTML enabled E-Mail client." + ."\n" + ."--ContentBoundry\n" + ."Content-Type: text/html; charset=\"US-ASCII\"\n" + ."\n" + ."The following purchase has been made for your Venue." + ."\n" + .$html_summary + ."\n" + ."--ContentBoundry--\n" + ."\n"; + $this->debug_mail( + $procEmail, + htmlspecialchars_decode($membData['name'],ENT_QUOTES).' Purchase Notification', + $email_content, + "From: ".htmlspecialchars_decode($membData['name'],ENT_QUOTES)." <".$membData['email'].">" + ."\nMime-Version: 1.0\nContent-Type: multipart/alternative; boundary=ContentBoundry\n" + ); + + } // Have processing E-Mail address + + } // Doing notification to member/venue + + // Clear new approval flag so we don't send notices again - If not checkout testing enabled + if (!$this->config->option->checkout_testing) { + $cart['cartDataReorganized'][$r['id']]['paymentResult']['newApproval'] = false; + } else { + // When doing checkout testing, add full SQL transaction to debug for each payment result + $this->addDebug("SQL Transaction for ".$cart['cartDataReorganized'][$r['id']]['name'], 'SQL Transaction', print_r($r['sqlTransaction'],1)); + } + } + + } // Each payment result + + } + + // Store the current payments data back into the session - If not checkout testing enabled + if (!$this->config->option->checkout_testing) { + $_SESSION[GLM_EVENT_SESSION]['TicketPayments'] = $paymentResult['payments']; + } + + // If there was a problem processing any of the venue payments - return user to checkout page + if (!$paymentResult['status']) { + + $checkoutReturnFlag = true; + $this->reason[] = 'There was a problem processing your request. '; + $checkoutCart = $cart; // Save because it's going to get overwritten by checkout.inc + include EVENT_MANAGEMENT_APP_BASE.'models/front/actions/Shop/checkout.inc'; + return; + + } + + +} // If checkout not already complete +$this->page->cartHasContents = $cart['cartHasContents']; +$this->page->cart = $this->bindArrayToObject($cart['cartDataReorganized']); +$this->page->totals = $this->bindArrayToObject($cart['totals']); +$this->page->cartHasOneVenueOnly = $cart['cartHasOneVenueOnly']; +$this->templateFile = "Shop/checkoutSuccess.html"; + +$this->addDebug("Shop/checkoutSubmit.inc", 'Array: $totals', print_r($cart['totals'],1)); +$this->addDebug("Shop/checkoutSubmit.inc", 'Array: $cart', print_r($cart['cartDataReorganized'],1)); +$this->addDebug("Shop/checkoutSubmit.inc", 'Array: $formData', print_r($formData,1)); + +// Destroy session to clear cart - If not doing checkout testing +if (!$this->config->option->checkout_testing) { + $_SESSION[GLM_EVENT_SESSION]['TicketCart'] = false; + $_SESSION[GLM_EVENT_SESSION]['ContactInput'] = false; + $_SESSION[GLM_EVENT_SESSION]['TicketPayments'] = false; +} +?> + diff --git a/models/front/actions/Shop/printVoucher.inc b/models/front/actions/Shop/printVoucher.inc new file mode 100644 index 0000000..5b1e5c4 --- /dev/null +++ b/models/front/actions/Shop/printVoucher.inc @@ -0,0 +1,60 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: printVoucher.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +// Get Order ID +$orderID = $_REQUEST['OrderID'] - 0; +if ($orderID == 0) { + exit; +} + +// Check Order Verification Code - Prevents people just sticking order numbers into urls to get vouchers +$orderVerify = md5($orderID.$this->config->orderVerificationSecret); +if ($orderVerify != $_REQUEST['orderVerify']) { + // Bad verification code + echo "Voucher Fault Code: 21"; + exit; +} + +// Get Order Detail +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/orders.php'; +$Orders = new EventManagementAdminOrders($this->dbh, $this->config); +$orderDetail = $Orders->getOrderDetail($orderID); + +// Get Ticket Sold (voucher) detail +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/sold.php'; +$Sold = new EventManagementAdminSold($this->dbh, $this->config); +$soldList = $Sold->getSoldList($orderID); + +// Get Venue Detail +require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/members.php'; +$Members = new EventManagementAdminMembers($this->dbh, $this->config); +$memberDetail = $Members->getMemberDetail($orderDetail['member']); + +// Load voucher design code as per the "voucher_design" config parameter in the site's config/applications/EventManagement.ini file +if (is_file(EVENT_MANAGEMENT_APP_BASE.'models/vouchers/'.$this->config->voucher_design.'/voucher.php')) { + if (isset($_REQUEST['Mobile'])) { + require_once EVENT_MANAGEMENT_APP_BASE.'models/vouchers/'.$this->config->voucher_design.'/voucherMobile.php'; + } else { + require_once EVENT_MANAGEMENT_APP_BASE.'models/vouchers/'.$this->config->voucher_design.'/voucher.php'; + } + $pdf = new PdfVoucher($orderDetail, $soldList, $memberDetail, $this->dbh, $this->config); +} else { + echo "SYSTEM ERROR: Site is not configured with a valid voucher design file."; + exit; +} + +// There's nothing to do from here. Output should go direct to browser. +exit; + +?> diff --git a/models/front/actions/Shop/sectionSelect.inc b/models/front/actions/Shop/sectionSelect.inc new file mode 100644 index 0000000..b21553a --- /dev/null +++ b/models/front/actions/Shop/sectionSelect.inc @@ -0,0 +1,83 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: sectionSelect.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'models/front/classes/support.php'; +$Support = new EventManagementFrontSupport($this->dbh, $this->config); + +// Check If we're already locked into checkout, if so then go there +$cart = $Support->checkCart(); +if ($cart['forceCheckoutPhase']) { + $this->reason[] = 'You have partially paid for your purchases. We have returned you to checkout to complete your purchase.'; + include EVENT_MANAGEMENT_APP_BASE.'models/front/actions/Shop/checkout.inc'; + return; +} + +// If perfID hasn't been past to us, get selected Performance ID from input +if (!isset($perfID)) { + $perfID = ($_REQUEST['PerformanceID'] - 0); +} + +// Do we have a valid performance ID? +if ($perfID == 0) { + $this->reason[] = 'No '.$this->config->term->event->norm.' has been selected.'; +} else { + + // Get detail on selected performance + $performanceDetail = $this->support->getPerformanceData($perfID); + $this->page->performanceDetail = $this->bindArrayToObject($performanceDetail); + + $this->addDebug("Shop/sectionSelect.inc", 'Array: $performanceDetail', print_r($performanceDetail,1)); + + // If we can't find the performance + if (!$performanceDetail) { + $this->reason[] = 'We were unable to find the selected '.$this->config->term->event->norm.'.'; + } else { + + // Query to find section IDs for sections that have active ticket inventory for the selected performance + $sql = "T.id in ( + SELECT distinct(K.section) + FROM eventmgt.ticket K, eventmgt.ticket_inventory I + WHERE performance = $perfID + AND I.ticket = K.id + )"; + + // Get Section List for this performance for sections with available tickets + $sectionList = $this->support->getSectionList($false, $sql); + $this->page->sectionList = $this->bindArrayToObject($sectionList); + + $this->addDebug("Shop/sectionSelect.inc", 'Array: $sectionList', print_r($sectionList, 1)); + + // If no sections found for this performance + if (!$sectionList) { + $this->reason[] = 'We were unable to find any '.$this->config->term->section->plur.' for this '.$this->config->term->event->norm.'.'; + } else { + + // if there's only one section, then select it for the user and move on to ticket selection - unless we're forcing section display + if (!$this->config->option->ticket_selection->force_section && count($sectionList) == 1) { + + $this->addDebug("Shop/ticketSelect.inc", '*** Change to new method/view ***'); + + $passSectionID = $sectionList[0]['id']; + include EVENT_MANAGEMENT_APP_BASE.'models/front/actions/Shop/ticketSelect.inc'; + return; + } + + } + } +} + +$this->templateFile = "Shop/sectionSelect.html"; + +?> + diff --git a/models/front/actions/Shop/start.inc b/models/front/actions/Shop/start.inc new file mode 100644 index 0000000..8f15c57 --- /dev/null +++ b/models/front/actions/Shop/start.inc @@ -0,0 +1,127 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: start.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'models/front/classes/support.php'; +$Support = new EventManagementFrontSupport($this->dbh, $this->config); + +// Check If we're already locked into checkout, if so then go there +$cart = $Support->checkCart(); +if ($cart['forceCheckoutPhase']) { + $this->reason[] = 'You have partially paid for your purchases. We have returned you to checkout to complete your purchase.'; + include EVENT_MANAGEMENT_APP_BASE.'models/front/actions/Shop/checkout.inc'; + return; +} + +// Check if "Start at Cart" option is enabled. Generally used when there's cart-sticky items. +if ($this->config->option->ticket_selection->start_at_cart) { + include EVENT_MANAGEMENT_APP_BASE.'models/front/actions/Shop/cart.inc'; + return; +} + +$this->templateFile = "Shop/start.html"; + +// Get Members list - all active +$membersList = $Support->getMembersList('active'); + +// if there's no members listed +if (count($membersList) == 0) { + $this->reason[] = 'There are no available '.$this->config->term->prop->plur.'.'; + return; +} + +// Get available performances data for each member and add them to the member data +$havePerformance = false; +$inventory = array(); + +if (is_array($membersList) && count($membersList) > 0) { + + reset($membersList); + + while (list($k, $v) = each($membersList)) { + + // Get list of performances for this member + $performancesList = $Support->getPerformancesList($v[id], 'member_and_active'); + + // If we have performances for this member + if ($performancesList) { + + $havePerformances = true; + + // For each performance, get the ticket data and add it to the array + reset($performancesList); + while (list($k2, $v2) = each($performancesList)) { + + // Get all performance data for this performance + $perfData = $this->support->getAllPerformanceData($v2['id']); + + // if we got any data, add it to the performance + if ($perfData) { + + // Are we supposed to also provide actual ticket selection on this page? + if ($this->config->option->ticket_selection->show_tickets_on_start_page) { + + // Add performance section/ticket data to the performance list + $performancesList[$k2]['oneSectionOnly'] = $perfData['oneSectionOnly']; + $performancesList[$k2]['sections'] = $perfData['sections']; + + // Add inventory to the inventory array + $inventory += $perfData['inventory']; + + } // Option to show tickets on start page + + // If there's no performance data, then drop performance from list + } else { + unset($performancesList[$k2]); + } // have Performance data + + } // for each performance + + // Add all performance data, including tickets, to the member performances + $membersList[$k]['performances'] = $performancesList; + + // Otherwise there's no active performances or tickets + } else { + + // Since there's nothing to display, drop this member. + unset($membersList[$k]); + } + + if ($k && !isset($membersList[$k]['performances'])) { + unset($membersList[$k]); + } + + } +} + +// Pass flag to show tickets on start page from config +$this->page->showTickets = $this->config->option->ticket_selection->show_tickets_on_start_page; + +// Pass members list with performances and optional ticket data to template +$this->page->membersList = $this->bindArrayToObject($membersList); + +// Also supply all ticket inventory as a JSON for the front-end scripts +$this->page->ticketsJSON = json_encode($inventory, (int) JSON_PRETTY_PRINT); + +$this->addDebug("Shop/start.inc", 'Array: $membersList - with Performances', print_r($membersList, 1)); +$this->addDebug("Shop/start.inc", 'Array: $inventory', print_r($inventory, 1)); + +// If we didn't get any performances to select from +if (!$havePerformances) { +echo "...."; + $this->reason[] = 'There are no available '.$this->config->term->event->plur.'.'; +} + + +?> + diff --git a/models/front/actions/Shop/ticketOpt.inc b/models/front/actions/Shop/ticketOpt.inc new file mode 100644 index 0000000..5f52efe --- /dev/null +++ b/models/front/actions/Shop/ticketOpt.inc @@ -0,0 +1,265 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: ticketOpt.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'models/front/classes/support.php'; +$Support = new EventManagementFrontSupport($this->dbh, $this->config); + +// Check If we're already locked into checkout, if so then go there +$cart = $Support->checkCart(); +if ($cart['forceCheckoutPhase']) { + $this->reason[] = 'You have partially paid for your purchases. We have returned you to checkout to complete your purchase.'; + include EVENT_MANAGEMENT_APP_BASE.'models/front/actions/Shop/checkout.inc'; + return; +} + +// If perfID hasn't been passed to us, get selected Performance ID from input +if (!isset($perfID)) { + $perfID = ($_REQUEST['PerformanceID'] - 0); +} + +// Get selected Performance ID +$perfID = ($_REQUEST['PerformanceID'] - 0); +if ($perfID == 0) { + $this->reason[] = 'No '.$this->config->term->event->norm.' has been selected.'; +} else { + + // Get selected performance data + $performanceDetail = $this->support->getPerformanceData($perfID); + $this->page->performanceDetail = $this->bindArrayToObject($performanceDetail); + + $this->addDebug("Shop/ticketOpt.inc", 'Array: $performanceDetail', print_r($performanceDetail,1)); + + // If we can't find the performance + if (!$performanceDetail) { + $this->reason[] = 'We were unable to find the selected '.$this->config->term->event->norm.'.'; + } else { + + // If sectionID hasn't been past to us, get selected Section ID from input + if (!isset($sectionID)) { + $sectionID = ($_REQUEST['SectionID'] - 0); + } + + if ($sectionID == 0) { + $this->reason[] = 'No '.$this->config->term->section->norm.' has been selected.'; + } else { + + // Get selected section data + $sectionDetail = $this->support->getSpecifiedSectionDetail($sectionID); + $this->page->sectionDetail = $this->bindArrayToObject($sectionDetail); + + $this->addDebug("Shop/ticketOpt.inc", 'Array: $sectionDetail', print_r($sectionDetail,1)); + + // If section not found + if (!$sectionDetail) { + $this->reason[] = 'We were unable to find the selected '.$this->config->term->section->plur.'.'; + } else { + + // If ticketID hasn't been past to us, get selected ticket ID from input + if (!isset($ticketID)) { + $ticketID = ($_REQUEST['TicketID'] - 0); + } + + if ($ticketID == 0) { + $this->reason[] = 'No '.$this->config->term->ticket->norm.' has been selected.'; + } else { + + // Get Ticket detail + $ticketDetail = $this->support->getSpecifiedTicketDetail($ticketID); + $this->page->ticketDetail = $this->bindArrayToObject($ticketDetail); + + $this->addDebug("Shop/ticketOpt.inc", 'Array: $ticketDetail', print_r($ticketDetail,1)); + + // If ticket not found + if (!$ticketDetail) { + $this->reason[] = 'We were unable to find the selected '.$this->config->term->ticket->plur.'.'; + } else { + + // Get inventory for this ticket + $inventoryList = $this->support->getInventoryList($ticketID, 'T.active', true); + + // If no inventory found for this ticket + if (!$inventoryList) { + $this->reason[] = 'We were unable to find inventory for the selected '.$this->config->term->ticket->norm.'.'; + } else { + + // Determine if any of the dates are too late to buy on-line. + // If no timestamp then it's not a date-specific ticket, so no purchase leadtime issue. + while (list($k, $v) = each($inventoryList)) { + if ($v['ticket_date']['timestamp']) { + $inventoryList[$k]['tooLate'] = (time() > strtotime($k) - ($performanceDetail['purch_leadtime']*3600) ); + } else { + $inventoryList[$k]['tooLate'] = false; + } + } + + // We're now ready to pass the inventory list to the page + $this->page->inventoryList = $this->bindArrayToObject($inventoryList); + + $this->addDebug("Shop/ticketOpt.inc", 'Array: $inventoryList', print_r($inventoryList,1)); + + // Also supply this list as a JSON for the scripts + $this->page->inventoryJSON = json_encode($inventoryList, (int) JSON_PRETTY_PRINT); + $this->addDebug("Shop/ticketOpt.inc", 'JSON: $inventoryJSON', print_r($this->page->inventoryJSON,1)); + + } // Have inventory list + + } // Have ticket detail + + } // Have ticket ID + + } // Have section detail + + } // Have section ID + + } // Have performance detail + +} // Have performance ID + +$this->templateFile = "Shop/ticketOpt.html"; + + +/* + + + +require_once EVENT_MANAGEMENT_APP_BASE.'models/front/classes/support.php'; +$Support = new EventManagementFrontSupport($this->dbh, $this->config); + +// Check If we're already locked into checkout, if so then go there +$cart = $Support->checkCart(); +if ($cart['forceCheckoutPhase']) { + $this->reason[] = 'You have partially paid for your purchases. We have returned you to checkout to complete your purchase.'; + include EVENT_MANAGEMENT_APP_BASE.'models/front/actions/Shop/checkout.inc'; + return; +} + + +// Get selected ticket information +$perfID = ($_REQUEST['TicketID'] - 0); +if ($perfID == 0) { + $this->reason[] = 'No '.$this->config->term->ticket->norm.' has been selected.'; +} else { + + // Get Tickets and Inventory Information + require_once EVENT_MANAGEMENT_APP_BASE.'classes/data/dataTickets.php'; + $Tickets = new EventManagementDataTickets($this->dbh, $this->config); + $Tickets->optionIncludeSelectListData = false; + $ticketDetail = $Tickets->getTicketDetail($TicketID); + $this->page->ticketDetail = $this->bindArrayToObject($ticketDetail); + + // If we can't find the ticket + if (!$ticketDetail) { + $this->reason[] = 'We were unable to find the selected '.$this->config->term->ticket->norm.' information.'; + } else { + + // Get performance information + require_once EVENT_MANAGEMENT_APP_BASE.'classes/data/dataPerformances.php'; + $Performances = new EventManagementDataPerformances($this->dbh, $this->config); + $Performances->optionIncludeSelectListData = false; + $performanceDetail = $Performances->getPerformanceDetail($ticketDetail['performance_id']); + $this->page->performanceDetail = $this->bindArrayToObject($performanceDetail); + + // If we can't find the performance information + if (!$performanceDetail) { + $this->reason[] = 'We were unable to find the selected '.$this->config->term->event->norm.' information.'; + } else { + + + + } + } +} + + +// Check that Venue has a valid payment method setup +$this->page->havePayPal = false; +$this->page->haveCreditCards = false; +$this->page->havePaymentMethod = false; +if ( + $detail['member']['payment_gateway']['value'] > 0 // Have processor selected + && count($detail['member']['cards_accepted']['names']) > 0 // Have credit cards selected +) { + + // Check for any needed gateway authentication information + $haveAuth = false; + switch($detail['member']['payment_gateway']['value']) { + case $this->config->ccard_processor_numb->authorize_net: + if ($detail['member']['gateway_par1'] != '' && $detail['member']['gateway_par2'] != '') { + $haveAuth = true; + } + break; + case $this->config->ccard_processor_numb->merchant_solutions: + if ($detail['member']['gateway_par1'] != '' && $detail['member']['gateway_par2'] != '') { + $haveAuth = true; + } + break; + case $this->config->ccard_processor_numb->test: + $haveAuth = true; + break; + if ($haveAuth) { + // Have good credit card gateway, have cards, have authentication + $this->page->haveCreditCards = true; + $this->page->havePaymentMethod = true; + } +} +if ( + $detail['member']['paypal']['value'] && + $detail['member']['paypal_client_id'] != '' && + $detail['member']['paypal_secret'] != '' +){ + + $this->page->havePayPal = true; + $this->page->havePaymentMethod = true; + +} + +// If there's no possible payment method +if (!$this->page->havePaymentMethod) { + $detail['reason'][] = 'This '.$this->config->term->prop->norm.' has not configured any payment method. + Please call to purchase '.$this->config->term->ticket->plur.'.'; + $this->page->dissableAddToCart = true; +} + +// Check if member is set to active +if (!$detail['member']['active']['value']) { + $detail['reason'][] = 'This venue is not currently available to sell tickets on-line.'; + $this->page->dissableAddToCart = true; +} + +// Check for sections, tickets, and inventory +$mesg = ''; +if (!$detail['haveSections']) { + $mesg .= ' sections?'; +} +if (!$detail['haveTickets']) { + $mesg .= ' tickets?'; +} +if (!$detail['haveInventory']) { + $mesg .= ' inventory?'; +} +if ($mesg != '') { + $detail['reason'][] = 'No '.$this->config->term->ticket->plur.' are available for this '.$this->config->term->event->norm.". ($mesg )"; +} + +$this->reason = array_merge($this->reason, $detail['reason']); +unset($detail['reason']); + +$this->page->detail = $this->bindArrayToObject($detail); + +$this->templateFile = "Shop/ticketOpt.html"; + +// $this->addDebug("Shop/ticketOpt.inc", 'Array: $detail', print_r($detail,1)); + +?> +*/ diff --git a/models/front/actions/Shop/ticketSelect.inc b/models/front/actions/Shop/ticketSelect.inc new file mode 100644 index 0000000..de0939a --- /dev/null +++ b/models/front/actions/Shop/ticketSelect.inc @@ -0,0 +1,77 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: ticketSelect.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +require_once EVENT_MANAGEMENT_APP_BASE.'models/front/classes/support.php'; +$Support = new EventManagementFrontSupport($this->dbh, $this->config); + +// Check If we're already locked into checkout, if so then go there +$cart = $Support->checkCart(); +if ($cart['forceCheckoutPhase']) { + $this->reason[] = 'You have partially paid for your purchases. We have returned you to checkout to complete your purchase.'; + include EVENT_MANAGEMENT_APP_BASE.'models/front/actions/Shop/checkout.inc'; + return; +} + +// Get performance ID that might have been passed to us - otherwise set to 0 +$perfID = 0; +if (isset($_REQUEST['PerformanceID'])) { + $perfID = ($_REQUEST['PerformanceID'] - 0); + if ($perfID > 0) { + $_SESSION[GLM_EVENT_SESSION]['Performance'] = $perfID; + } +} + +// Get section ID that might have been passed to us - otherwise set to 0 +$sectID = 0; +if (isset($passSectionID)) { // Passed by calling method (i.e. sectionSelect.inc) + $sectID = $passSectionID; +} elseif (isset($_REQUEST['SectionID'])) { + $sectID = ($_REQUEST['SectionID'] - 0); +} +if ($sectID > 0) { + $_SESSION[GLM_EVENT_SESSION]['Section'] = $sectID; +} + +// If we don't have a performance ID then fail this step +if ($perfID == 0) { + $this->reason[] = 'No '.$this->config->term->event->norm.' has been selected.'; +} else { + + // Get all performance data including all tickets prepped for use in a JSON for the front-end + $perfData = $this->support->getAllPerformanceData($perfID, $sectID); + + // Save currently selected performance and member (venue) + $_SESSION[GLM_EVENT_SESSION]['Performance'] = $perfID['id']; + $_SESSION[GLM_EVENT_SESSION]['Member'] = $perfID['member_id']; + + // Pass performance detail and section and ticket information to the template + $this->page->oneSectionOnly = $perfData['oneSectionOnly']; + $this->page->performanceDetail = $this->bindArrayToObject($perfData['performanceDetail']); + $this->page->sections = $this->bindArrayToObject($perfData['sections']); + + // Also supply all ticket inventory as a JSON for the front-end scripts + $this->page->ticketsJSON = json_encode($perfData['inventory'], (int) JSON_PRETTY_PRINT); + + $this->addDebug("Shop/ticketSelect.inc", 'Performance Detail', print_r($perfData['performanceDetail'],1)); + $this->addDebug("Shop/ticketSelect.inc", 'Section and Ticket Data', print_r($perfData['sections'],1)); + $this->addDebug("Shop/ticketSelect.inc", 'Ticket Inventory Data', print_r($perfData['inventory'],1)); + $this->addDebug("Shop/ticketSelect.inc", 'JSON: $ticketsJSON', print_r($this->page->ticketsJSON,1)); + +} // Have performance ID + +$this->templateFile = "Shop/ticketSelect.html"; + + +?> + diff --git a/models/front/classes/checkoutSupport.php b/models/front/classes/checkoutSupport.php new file mode 100644 index 0000000..fe1191f --- /dev/null +++ b/models/front/classes/checkoutSupport.php @@ -0,0 +1,1750 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: classes/checkoutSupport.php,v 1.0 2011/01/25 19:31:47 cscott Exp $ + * @link <> + */ + +/** + * EventManagementFrontCheckoutSupport class + * + * PHP version 5 + * + * @category Event Management Admin Tickets + * @package EventManagement + * @author Chuck Scott + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: classes/checkoutSupport.php,v 1.0 2011/01/25 19:31:47 cscott Exp $ + * @link <> + */ + +class EventManagementFrontCheckoutSupport +{ + + /** + * Configuration information object + * @var $ini + * @access public + */ + protected $config; + /** + * Database Object + * @var $dbh + * @access public + */ + protected $dbh; + /** + * Support class object + * @var $Support + * @access public + */ + protected $Support; + /** + * Checkout Data Array + * @var $cd + * @access public + */ + protected $cd; + /** + * Flag to indicate if there's an input problem + * @var $inputFail + * @access public + */ + protected $inputFail = false; + /** + * SQL Transaction for passing back to calling methods when doing debug + * @var $sqlTransaction + * @access public + */ + protected $sqlTransaction = false; + + function __construct($dbh, $config, $Support) + { + + $this->dbh = $dbh; + $this->config = $config; + $this->Support = $Support; + + } + + /* + * Initialize/reset checkout data array + */ + public function checkoutInit($cart) + { + + // Determine if we're running as an admin user for setting "required" for certain fields. + $admin_user_require = !$_SESSION[GLM_EVENT_SESSION]['AdminUser']; + + // If there's not already checkout contact info in the session, start clean + if ($_SESSION[GLM_EVENT_SESSION]['ContactInput'] == false) { + + if ($this->config->option->checkout_pre_fill) { + + $this->cd = array( + 'contact' => array( + 'fname' => array('value' => 'John', 'required' => true, 'problem' => false), + 'lname' => array('value' => 'Smith', 'required' => true, 'problem' => false), + 'addr1' => array('value' => '120 E. Lake St.', 'required' => $admin_user_require, 'problem' => false), + 'addr2' => array('value' => 'Apt 2', 'required' => false, 'problem' => false), + 'city' => array('value' => 'Petoskey', 'required' => $admin_user_require, 'problem' => false), + 'state' => $this->createStatesArray('state', 'MI', $admin_user_require, false), + 'country' => $this->createCountriesArray('country', 'US', $admin_user_require, false), + 'phone' => array('value' => '231-487-0692', 'required' => true, 'problem' => false), + 'zip' => array('value' => '49770', 'required' => $admin_user_require, 'problem' => false), + 'email' => array('value' => 'info@gaslightmedia.com', 'required' => true, 'problem' => false), + 'email2' => array('value' => 'info@gaslightmedia.com', 'required' => true, 'problem' => false), + 'email_ok' => 'on', + 'opt_field_1' => array('value' => '', 'required' => false, 'problem' => false), + 'opt_field_2' => array('value' => '', 'required' => false, 'problem' => false), + 'opt_field_3' => array('value' => '', 'required' => false, 'problem' => false) + ), + 'payment' => array(), + 'status' => false, + 'centralPayment' => false + ); + } else { + + $this->cd = array( + 'contact' => array( + 'fname' => array('value' => '', 'required' => true, 'problem' => false), + 'lname' => array('value' => '', 'required' => true, 'problem' => false), + 'addr1' => array('value' => '', 'required' => $admin_user_require, 'problem' => false), + 'addr2' => array('value' => '', 'required' => false, 'problem' => false), + 'city' => array('value' => '', 'required' => $admin_user_require, 'problem' => false), + 'state' => $this->createStatesArray('state', false, $admin_user_require, false), + 'country' => $this->createCountriesArray('country', false, $admin_user_require, false), + 'phone' => array('value' => '', 'required' => true, 'problem' => false), + 'zip' => array('value' => '', 'required' => $admin_user_require, 'problem' => false), + 'email' => array('value' => '', 'required' => $admin_user_require, 'problem' => false), + 'email2' => array('value' => '', 'required' => $admin_user_require, 'problem' => false), + 'email_ok' => 'on', + 'opt_field_1' => array('value' => '', 'required' => false, 'problem' => false), + 'opt_field_2' => array('value' => '', 'required' => false, 'problem' => false), + 'opt_field_3' => array('value' => '', 'required' => false, 'problem' => false) + ), + 'payment' => array(), + 'status' => false, + 'centralPayment' => false + ); + } + + // Otherwise use the info stored in the session + } else { + + $ci = &$_SESSION[GLM_EVENT_SESSION]['ContactInput']; + + $this->cd = array( + 'contact' => array( + 'fname' => array('value' => $ci['fname'], 'required' => true, 'problem' => false), + 'lname' => array('value' => $ci['lname'], 'required' => true, 'problem' => false), + 'addr1' => array('value' => $ci['addr1'], 'required' => $admin_user_require, 'problem' => false), + 'addr2' => array('value' => $ci['addr2'], 'required' => false, 'problem' => false), + 'city' => array('value' => $ci['city'], 'required' => $admin_user_require, 'problem' => false), + 'state' => $this->createStatesArray('state', $ci['state'], $admin_user_require, false), + 'country' => $this->createCountriesArray('country', $ci['country'], $admin_user_require, false), + 'phone' => array('value' => $ci['phone'], 'required' => true, 'problem' => false), + 'zip' => array('value' => $ci['zip'], 'required' => $admin_user_require, 'problem' => false), + 'email' => array('value' => $ci['email'], 'required' => $admin_user_require, 'problem' => false), + 'email2' => array('value' => $ci['email2'], 'required' => $admin_user_require, 'problem' => false), + 'email_ok' => ($ci['email_ok'] ? 'on' : ''), + 'opt_field_1' => array('value' => $ci['opt_field_1'], 'required' => false, 'problem' => false), + 'opt_field_2' => array('value' => $ci['opt_field_2'], 'required' => false, 'problem' => false), + 'opt_field_3' => array('value' => $ci['opt_field_3'], 'required' => false, 'problem' => false) + + ), + 'payment' => array(), + 'status' => false, + 'centralPayment' => false + ); + + } + + // Check if there's central payment in use + require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/misc.php'; + $Misc = new EventManagementAdminMisc($this->dbh, $this->config); + $miscDetail = $Misc->getEntry(1); + if ($miscDetail['central_payment_id']) { + + require_once EVENT_MANAGEMENT_APP_BASE.'classes/data/dataMembers.php'; + $Members = new EventManagementDataMembers($this->dbh, $this->config); + $Members->optionIncludeSelectListData = false; + $membData = $Members->getMemberDetail($miscDetail['central_payment_id']); + + $this->cd['centralPayment'] = array( + 'id' => $miscDetail['central_payment_id'], + 'membData' => $membData + ); + + // Build card type array + $cctype = $this->buildCCTypeArray($membData, true, $membData, false, true); + + if ($this->config->option->checkout_pre_fill) { + + // Build expiration date array + $ccexp = $this->buildCCExpArray($required = true, $membData, 2, 2017, true); + + $this->cd['payment'][$membData['id']] = array( + 'id' => $membData['id'], + 'spec_req' => array('value' => 'none', 'required' => false, 'problem' => false), + 'cctype' => $cctype, + 'ccname' => array('value' => 'JOHN SMITH', 'required' => true, 'problem' => false), + 'ccnumb' => array('value' => '0011001100110011', 'required' => true, 'problem' => false), + 'ccexp' => $ccexp, + 'cccode' => array('value' => '123', 'required' => true, 'problem' => false), + ); + + } else { + + // Build expiration date array + $ccexp = $this->buildCCExpArray($required = true, $membData, false, false, true); + + $this->cd['payment'][$membData['id']] = array( + 'id' => $membData['id'], + 'spec_req' => array('value' => '', 'required' => false, 'problem' => false), + 'cctype' => $cctype, + 'ccname' => array('value' => '', 'required' => true, 'problem' => false), + 'ccnumb' => array('value' => '', 'required' => true, 'problem' => false), + 'ccexp' => $ccexp, + 'cccode' => array('value' => '', 'required' => true, 'problem' => false), + ); + + } + + } else { + + // Build payment array for each venue + foreach($cart as $c) { + + // Build card type array + $cctype = $this->buildCCTypeArray($c, true, $c['id'], false, true); + + if ($this->config->option->checkout_pre_fill) { + + // Build expiration date array + $ccexp = $this->buildCCExpArray($required = true, $c['id'], 2, 2017, true); + + $this->cd['payment'][$c['id']] = array( + 'id' => $c['id'], + 'spec_req' => array('value' => 'none', 'required' => false, 'problem' => false), + 'cctype' => $cctype, + 'ccname' => array('value' => 'JOHN SMITH', 'required' => true, 'problem' => false), + 'ccnumb' => array('value' => '0011001100110011', 'required' => true, 'problem' => false), + 'ccexp' => $ccexp, + 'cccode' => array('value' => '123', 'required' => true, 'problem' => false), + ); + + } else { + + // Build expiration date array + $ccexp = $this->buildCCExpArray($required = true, $c['id'], false, false, true); + + $this->cd['payment'][$c['id']] = array( + 'id' => $c['id'], + 'spec_req' => array('value' => '', 'required' => false, 'problem' => false), + 'cctype' => $cctype, + 'ccname' => array('value' => '', 'required' => true, 'problem' => false), + 'ccnumb' => array('value' => '', 'required' => true, 'problem' => false), + 'ccexp' => $ccexp, + 'cccode' => array('value' => '', 'required' => true, 'problem' => false), + ); + + } + } + } + + return $this->cd; + } + + /* + * Get sanitized input data and store results in $this->cd + * + * @param $a Array element to store results - this function creates the entries + * @param $f Name of the parameter + * @param $filter Filter(s) to use + * @param $req Flag indicating if it's a required parameter + * @param $opt Optional filter option to use + * @param $id Optional sub-array id - also used as prefix to parameter + * + */ + private function fieldInput($a, $f, $filter, $req, $opt = false, $id = false) + { + // Setup results + $r = array( + 'value' => false, + 'required' => $req, + 'problem' => '' + ); + + // Check for ID prefix + $fname = $f; + if ($id != false) { + $fname = $id."_".$f; + } + + $in = trim(filter_input(INPUT_POST, $fname, $filter, $opt)); + + // If there's been a filter violation + if ($in === false) { + + // Take what's safe + $r['value'] = filter_input(INPUT_POST, $f, FILTER_SANITIZE_STRING); + + // Mark as bad input + $r['problem'] = 'Input is not valid.'; + $this->inputFail = true; + + // If nothing has been supplied + } elseif ($in === null || $in == '') { + + // There's nothing + $r['value'] = ''; + + // If it's required, then say so + if ($req) { + $r['value'] = ''; + $r['problem'] = 'Required input not provided.'; + $this->inputFail = true; + } + + // Otherwise, the input is valid + } else { + + $r['value'] = $in; + $r['problem'] = false; + + } + + // Store results into destination array + if ($id) { + $this->cd[$a][$id][$f] = $r; + } else { + $this->cd[$a][$f] = $r; + } + + } + + /* + * Collect and validate checkout information + * + * @param $cart Array containing cart information + * + * @return object containing array as sub-objects + */ + public function checkoutInput($cart) + { + + // Determine if we're running as an admin user for setting "required" for certain fields. + $admin_user_require = !$_SESSION[GLM_EVENT_SESSION]['AdminUser']; + + /* + * Initialize Destination Cart Data Array + * Set status to false (indicates fail - set to true later if all is Ok) + * This is where we're going to build the returned data + */ + $this->cd = array( + 'contact' => false, // Where contact information goes + 'payment' => false, // Where payment information goes + 'status' => false, // A status flag + 'centralPayment' => false, // Assume no central payment + 'reason' => array() // Reasons we had problems + ); + + // Set input fail to false - calls below will change this if there's a problem + $this->inputFail = false; + + /* + * Check all of the contact information required for checkout + * The checks below supply the various data to the $this->cd['contact'] array. + */ + $this->fieldInput('contact', 'fname', FILTER_SANITIZE_STRING, true); + $this->fieldInput('contact', 'lname', FILTER_SANITIZE_STRING, true); + $this->fieldInput('contact', 'addr1', FILTER_SANITIZE_STRING, $admin_user_require); + $this->fieldInput('contact', 'addr2', FILTER_SANITIZE_STRING, false); + $this->fieldInput('contact', 'city', FILTER_SANITIZE_STRING, $admin_user_require); + $this->cd['contact']['state'] = $this->createStatesArray('state', false, $admin_user_require); + $this->cd['contact']['country'] = $this->createCountriesArray('country', false, $admin_user_require); + $this->fieldInput('contact', 'zip', FILTER_SANITIZE_STRING, $admin_user_require); + $this->fieldInput('contact', 'phone', FILTER_SANITIZE_STRING, true); + $this->fieldInput('contact', 'email', FILTER_VALIDATE_EMAIL, $admin_user_require); + $this->fieldInput('contact', 'email2', FILTER_VALIDATE_EMAIL, $admin_user_require); + $this->fieldInput('contact', 'opt_field_1', FILTER_SANITIZE_STRING, false); + $this->fieldInput('contact', 'opt_field_2', FILTER_SANITIZE_STRING, false); + $this->fieldInput('contact', 'opt_field_3', FILTER_SANITIZE_STRING, false); + + // Also check the contact E-mail address and that they entered it twice properly + if ($this->cd['contact']['email']['value'] != $this->cd['contact']['email2']['value']) { + $this->cd['contact']['email2']['problem'] = 'Email addresses don\'t match.'; + $this->inputFail = true; + } + + // Say whether the user wanted to be contacted with other offers + $this->cd['contact']['email_ok'] = ($_REQUEST['email_ok'] == 'on'); + + /* + * Store the data values (only) collected so far into the session + * in case we come back to checkout for some reason. + * Only store the values, not all the other status data added to the + * $this->cd['contact'] array. + */ + $ci = &$this->cd['contact']; + $_SESSION[GLM_EVENT_SESSION]['ContactInput'] = array( + 'fname' => $ci['fname']['value'], + 'lname' => $ci['lname']['value'], + 'addr1' => $ci['addr1']['value'], + 'addr2' => $ci['addr2']['value'], + 'city' => $ci['city']['value'], + 'state' => $ci['state']['value'], + 'country' => $ci['country']['value'], + 'zip' => $ci['zip']['value'], + 'phone' => $ci['phone']['value'], + 'email' => $ci['email']['value'], + 'email2' => $ci['email2']['value'], + 'email_ok' => $ci['email_ok'], + 'opt_field_1' => $ci['opt_field_1']['value'], + 'opt_field_2' => $ci['opt_field_2']['value'], + 'opt_field_3' => $ci['opt_field_3']['value'] + ); + + // Check if there's central payment in use (if central payment member id is not 0) + require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/misc.php'; + $Misc = new EventManagementAdminMisc($this->dbh, $this->config); + $miscDetail = $Misc->getEntry(1); + $cpId = $miscDetail['central_payment_id']; + + /* + * Build payment array for each venue - Main index in cart data is Venue + * Note that $c['id'] is used as an index into the payment array + * The Payment array is empty when we first get here - before any payments have been processed. + * If one payment was processed in a previous checkout attempt but another wasn't, the + * completed payment should be in here. + */ + $centralPaymentAdded = false; + if (!is_array($cart)) { + return false; + } + foreach ($cart as $c) { + + // Note: $c contains full info for a single venue with all selected cart data for it + + // If this payment doesn't exist yet or has not yet been approved + if ( !isset($_SESSION[GLM_EVENT_SESSION]['TicketPayments'][$c['id']]) || + !$_SESSION[GLM_EVENT_SESSION]['TicketPayments'][$c['id']]['approved']) { + + // Create a payment entry under the current venue in our destination data with the current venue id + $this->cd['payment'][$c['id']] = array( + 'id' => $c['id'], + 'type' => false + ); + + /* + * Set the payment type the user selected for this venue + * We currently only have PayPal and Credit card. Will have to restructure this if we + * ever accept any other types of payments (comp codes, pay at event, ...) + */ + + if ( isset($_REQUEST[$c['id'].'_payTypeSelect']) && $_REQUEST[$c['id'].'_payTypeSelect'] == 'no' ) { + + // Check for any special request for this venue and save it along with Payment information + $this->fieldInput('payment', 'spec_req', FILTER_SANITIZE_STRING, false, false, $c['id']); + + $this->cd['payment'][$c['id']]['type'] = 'no'; + + + } elseif ($_REQUEST[$c['id'].'_payTypeSelect'] == 'pp') { + + // PayPal payment selected + + // Check for any special request for this venue and save it along with Payment information + $this->fieldInput('payment', 'spec_req', FILTER_SANITIZE_STRING, false, false, $c['id']); + + $this->cd['payment'][$c['id']]['type'] = 'pp'; + + } else { + + if (isset($_REQUEST['AdminNoPayment']) && $_REQUEST['AdminNoPayment'] = 'TRUE') { + + } else { + + // If central credit card payment + if ($cpId) { + + if (!$centralPaymentAdded) { + + // Get the central payment venu and setup payment entry + require_once EVENT_MANAGEMENT_APP_BASE.'classes/data/dataMembers.php'; + $Members = new EventManagementDataMembers($this->dbh, $this->config); + $Members->optionIncludeSelectListData = false; + $cpMembData = $Members->getMemberDetail($miscDetail['central_payment_id']); + + $this->cd['centralPayment'] = array( + 'id' => $miscDetail['central_payment_id'], + 'membData' => $cpMembData + ); + + // Check for any special request for this venue and save it along with Payment information + $this->fieldInput('payment', 'spec_req', FILTER_SANITIZE_STRING, false, false, $cpId); + + /* + * Set the payment type the user selected for this venue + * We currently only have PayPal and Credit card. Will have to restructure this if we + * ever accept any other types of payments (comp codes, pay at event, ...) + */ + + if ($_REQUEST[$cpId.'_payTypeSelect'] == 'pp') { + + // PayPal payment selected + $this->cd['payment'][$cpId]['type'] = 'pp'; + + } else { + + // Credit Card payment selected + $this->cd['payment'][$cpId]['type'] = 'cc'; + + // Collect and verify submitted credit card information + $this->cd['payment'][$cpId]['cctype'] = $this->buildCCTypeArray($cpMembData, true, $cpId); + $this->fieldInput('payment', 'ccname', FILTER_SANITIZE_STRING, true, false, $cpId); + $this->ccnumbInput('payment', 'ccnumb', $this->cd['payment'][$cpId]['cctype']['value'], true, $cpId); + $this->cd['payment'][$cpId]['ccexp'] = $this->buildCCExpArray($required = true, $cpId); + $this->fieldInput('payment', 'cccode', FILTER_SANITIZE_NUMBER_INT, true, false, $cpId); + + } + + } + + $centralPaymentAdded = true; + + } else { + + // Credit Card payment selected + $this->cd['payment'][$c['id']]['type'] = 'cc'; + + // Collect and verify submitted credit card information + $this->cd['payment'][$c['id']]['cctype'] = $this->buildCCTypeArray($c, true, $c['id']); + $this->fieldInput('payment', 'ccname', FILTER_SANITIZE_STRING, true, false, $c['id']); + $this->ccnumbInput('payment', 'ccnumb', $this->cd['payment'][$c['id']]['cctype']['value'], true, $c['id']); + $this->cd['payment'][$c['id']]['ccexp'] = $this->buildCCExpArray($required = true, $c['id']); + $this->fieldInput('payment', 'cccode', FILTER_SANITIZE_NUMBER_INT, true, false, $c['id']); + } + } + } + } + + } + + // If everything is OK, set status to true + if (!$this->inputFail) { + $this->cd['status'] = true; + } else { + // Otherwise let the user know there was a problem + $this->cd['reason'][] = 'Please see fields highlighted in red below.'; + } + + return $this->cd; + } + + /* + * Try to process all payments + * + * Return data from processPayment() calls + * + * $res = array + * status Numeric return status code + * 1 Approved + * 2 Bad data supplied + * 3 Communications failure + * 4 Bad response + * 5 Transaction not valid + * 6 Merchant account problem + * 7 Card declined + * statusText Short name of status + * authCode Authorization code - blank if card not accepted + * description Longer description of result + * + * + * @param $cart Array containing cart information + * @param $contact Array containing contact information + * + * @return object containing array as sub-objects + * + * id ID of cart entry (member ID) + * status True if payment successful + * type Type of transaction ('cc' = Credit Card, 'pp' = PayPal) + * statusText Description of status + * authCode Any Authorization code returned + * description Description of action and result + * newApproval This payment has just been made, not on a previous page submission + * spec_req ? + * approved True if Approved + * cctype Card type name + * ccname Card holder name + * ccexp Expiration date + * ccnumb Card number (may be mudged) + * orderID ID of this order + * + */ + public function checkoutProcessPayments($cart, $formData) + { + + // Array that will take list of all payments + $payments = array(); + + // If this is an admin user and no payment has been selected + if (isset($_REQUEST['AdminNoPayment']) && $_REQUEST['AdminNoPayment'] = 'TRUE') { + while (list($key, $val) = each($formData['payment'])) { + $formData['payment'][$key]['type'] = 'no'; + } + } + + // If Central Payment + $grandTotal = 0; + $allPerf = array(); + if ($formData['centralPayment']) { + foreach ($cart as $c) { + + // If this isn't a no payment location + if ($c['payment_gateway']['value'] != 3) { + + // Build complete payment total + $grandTotal += $c['totalPrice_numb']; + + // Build array of all performances - This will be used to build a single order with all venues + if (count($c['performances']) > 0) { + foreach ($c['performances'] as $perf) { + $allPerf[$perf['id']] = $perf; + } + } + } + + } + } + + // Assume the payment can't be processed + $status = false; + + // Get any previous payment data from the session + // Would be there if payment has already been tried and there was a failure + $ticketPayments = $_SESSION[GLM_EVENT_SESSION]['TicketPayments']; + + // For each venue + reset($cart); + foreach ($cart as $c) { + + // Short form for venue/cart entry ID + $id = $c['id']; + + // If Central Payment then set grand total + if ($formData['centralPayment']) { + $c['totalPrice_numb'] = $grandTotal; + } + + // If not Central Payment or this is not the central payment member (i.e. not consignment) + if (!$formData['centralPayment'] || $formData['centralPayment']['id'] == $c['id'] || $formData['payment'][$id]['type'] == 'no') { + + // Check if payment has been completed for this venue + if (isset($ticketPayments[$id]) && $ticketPayments[$id]['status'] == 1) { + + // If so, then we'll just use that + $payments[$id] = $ticketPayments[$id]; + + // Otheriwse, try to process this payment + } else { + + // If this is a credit card purchase - (note PayPal is processed separately) + switch ($formData['payment'][$id]['type']) { + + // No payment required + case 'no': + + $res = array( + 'type' => 'no', + 'status' => 1, + 'statusText' => 'No Payment', + 'authCode' => '000000', + 'description' => 'No Payment Required', + 'spec_req' => $c['paymentForm']['spec_req']['value'], + 'approved' => true, + 'cctype' => '', + 'ccname' => '', + 'ccexp' => '', + 'ccnumb' => '', + 'newApproval' => true + ); + + $status = true; + + break; + + // Credit Card Payment + case 'cc': + + // Build a more concise array with what we need + $payment = array( + 'gateway' => $c['payment_gateway']['value'], // Payment gateway to use + 'name' => $c['name'], // Name of venue + 'charge' => $c['totalPrice_numb'], // Total charges this venue + 'cctype' => $formData['payment'][$id]['cctype']['name'], // Card Type + 'ccname' => $formData['payment'][$id]['ccname']['value'], // Name on Card + 'ccnumb' => $formData['payment'][$id]['ccnumb']['value'], // Card Number + 'ccexp' => $formData['payment'][$id]['ccexp']['value'], // Expriation Date + 'cccode' => $formData['payment'][$id]['cccode']['value'], // CCV - security code + 'invoice' => $_SESSION[GLM_EVENT_SESSION]['SessionID'] // Invoice # is session ID (or some part thereof) + ); + + // Load selected payment processor and initialize + switch ($payment['gateway']) { + + case $this->config->ccard_processor_numb->no_payment: + + $account = array(); + + // load and initialize - No account data required + require_once COMMON_APP_BASE.'CommonAbstracts/'.$this->config->paymentProcessorsLocation.'/None/no_payment.php'; + $Processor = new NoPaymentGateway(); + + break; + + case $this->config->ccard_processor_numb->authorize_net: + + // Get account data + $account = array( + 'login' => $c['gateway_par1'], + 'key' => $c['gateway_par2'], + 'test' => $c['gateway_par3']['value'], + 'conf' => $c['gateway_par4']['value'], + 'email' => $c['gateway_par5'] + ); + + // load and initialize + require_once COMMON_APP_BASE.'CommonAbstracts/'.$this->config->paymentProcessorsLocation.'/Authorize.Net/AuthorizeNet.php'; + $Processor = new AuthorizeNetPaymentGateway($account); + + break; + + case $this->config->ccard_processor_numb->merchant_solutions: + + // Get account data + $account = array( + 'acctid' => $c['gateway_par1'], + 'merchantpin' => $c['gateway_par2'], + 'test' => $c['gateway_par3']['value'], + 'conf' => $c['gateway_par4']['value'], + 'email' => $c['gateway_par5'] + ); + + // load and initialize + require_once COMMON_APP_BASE.'CommonAbstracts/'.$this->config->paymentProcessorsLocation.'/MerchantSolutions/MerchantSolutions.php'; + $Processor = new MerchantSolutionsPaymentGateway($account); + + break; + + case $this->config->ccard_processor_numb->test: + + $account = array(); + + // load and initialize - No account data required + require_once COMMON_APP_BASE.'CommonAbstracts/'.$this->config->paymentProcessorsLocation.'/Test/Test.php'; + $Processor = new TestPaymentGateway(); + + break; + + } + + // Send payment request to payment processor - Use contact information in session + $res = $Processor->processPayment($payment, $_SESSION[GLM_EVENT_SESSION]['ContactInput']); + + // Assume we don't have a new approval + $res['newApproval'] = false; + + // If payment was successful - update the result with a mudged card number + if ($res['status'] == 1) { + + $status = true; + + $res['spec_req'] = $c['paymentForm']['spec_req']['value']; + $res['approved'] = true; + $res['cctype'] = $payment['cctype']; + $res['ccname'] = $payment['ccname']; + $res['ccexp'] = $payment['ccexp']; + $res['ccnumb'] = '**** **** **** '.substr($payment['ccnumb'], -4); + $res['newApproval'] = true; + + } + + // Add transaction type to result + $res['type'] = 'cc'; + + break; + + } // case payment type + + // If the transaction was successful + if ($status) { + + // If Central Payment, put all performances into this order + if ($formData['centralPayment']) { + $c['performances'] = $allPerf; + } + + // Store the purchase + $orderID = $this->storePurchase($c, $res); + + if ($orderID == false) { + + // Oops, some kind of failure to store purchase. Send Chuck a message + $message = "Event Management System V3\n\n" + ."Failure to store customer purchase - checkoutProcessPayments()\n\n" + ."Contact:\n\n".print_r($contact,1)."\n\n" + ."Cart:\n\n".print_r($c,1)."\n\n" + ."Result:\n\n".print_r($res,1)."\n\n" + ."Payment:\n\n".print_r($payment,1)."\n\n" + ."Gateway Account:\n\n".print_r($account,1)."\n\n"; + mail( + 'cscott@gaslightmedia.com', + 'Event Management V3 Error: Failure to store purchase', + $message, $headers = '', $parameters = '' ); + + } + + $res['orderID'] = $orderID; + + // Add venue id to payment result + $res['id'] = $c['id']; + + // Pass entire SQL Transaction back. If checkout debug isn't enabled this will simply be false; + $res['sqlTransaction'] = $this->sqlTransaction; + + } + + // Add payment information to the payments array + $payments[$c['id']] = $res; + + } // if payment not already processed + + } // if not central payment or member ID is the same as the central payment id + + } // For each venue + + return array( + 'payments' => $payments, + 'status' => $status + ); + + } + + /* + * Attempt to store purchase + * + * @param $c Array of a single venue from the cart - Payment must have been successful + * @return object containing array as sub-objects + */ + public function storePurchase($c, $res) + { + + // Start transaction array + $transaction = array(); + + // Get contact information from the session + $contact = $_SESSION[GLM_EVENT_SESSION]['ContactInput']; + + // Create unique session ID (extended with Date state to ensure it's unique) + $sid = $_SESSION[GLM_EVENT_SESSION]['SessionID'].'-'.time(); + + // Get optional checkout field prompts to store with order + require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/misc.php'; + $Misc = new EventManagementAdminMisc($this->dbh, $this->config); + $miscConfigDetail = $Misc->getEntry(1); + + $user_trace = + $_SERVER["REMOTE_ADDR"]." - " + .date("m/d/Y H:i:s"); + + $pmt = $c['paymentForm']; + $specialNeeds = $res['spec_req']; // **** NEED TO GET THIS INTO CART + + // Check for any no payment info reasons + $notes = ''; + if (isset($_REQUEST['no_payment_reason']) && trim($_REQUEST['no_payment_reason']) != '') { + $notes = htmlspecialchars("Admin no payment info reason:\n".$_REQUEST['no_payment_reason'], ENT_QUOTES); + } + + $transaction[] = " + INSERT INTO eventmgt.ticket_order + ( + user_trace_info, + fname, + lname, + addr1, + addr2, + city, + state, + zip, + country, + phone, + email, + email_ok, + opt_field_1_name, + opt_field_1, + opt_field_2_name, + opt_field_2, + opt_field_3_name, + opt_field_3, + purchase_date, + member, + cctype, + ccnumber, + expire, + ccname, + ccconf, + charge_total, + special_needs, + notes, + session_id + ) + VALUES + ( + '$user_trace', + '".$contact['fname']."', + '".$contact['lname']."', + '".$contact['addr1']."', + '".$contact['addr2']."', + '".$contact['city']."', + '".$contact['state']."', + '".$contact['zip']."', + '".$contact['country']."', + '".$contact['phone']."', + '".$contact['email']."', + ".($contact['email_ok'] ? 'true' : 'false').", + '".addslashes($miscConfigDetail['opt_field_1_name'])."', + '".$contact['opt_field_1']['value']."', + '".addslashes($miscConfigDetail['opt_field_2_name'])."', + '".$contact['opt_field_2']['value']."', + '".addslashes($miscConfigDetail['opt_field_3_name'])."', + '".$contact['opt_field_3']['value']."', + 'today', + ".$c['id'].", + '".$res['cctype']."', + '".$res['ccnumb']."', + '".$res['ccexp']."', + '".$res['ccname']."', + '".$res['authCode']."', + ".$c['totalPrice_numb'].", + '".$specialNeeds."', + '".$notes."', + '".$sid."' + ); + "; + + // For each ticket date + $ticketSequence = 0; + foreach ($c['performances'] as $p) { + + // Do a last validation on likely date + $likelyDate = date('m/d/Y', strtotime($c['likelyDate'])); + if ($likelyDate == '12/31/1969') { + $likelyDate = ''; + } + + // For each performance + foreach ($p['dates'] as $d) { + + // For each Section + foreach ($d['sections'] as $s) { + + // For each ticket type + foreach ($s['tickets'] as $t) { + + // If this ticket is type "package", get package contents for use below. + $isPackageTicket = false; + if ($this->config->option->tickets && $t['ticket_type']['value'] == 20) { + + // get the package contents + require_once EVENT_MANAGEMENT_APP_BASE.'classes/data/dataTicketPackages.php'; + $TicketPackages = new EventManagementDataTicketPackages($this->dbh, $this->config); + $packageData = $TicketPackages->getPackageList("package = ".$t['id']); + $isPackageTicket = true; + + } + + // For each individual ticket + for ($i=1 ; $i<=$t['selected'] ; $i++) { + + // If option "ticket_sold_member_actual" is true, force member for ticket_sold to the memeber listed in the "ticket" table. + // This overrides some of the "assignment" alterations when selling by consignment and forces reports to always point to the actual ticket member. + $ticketSoldMember = $c['id']; + if ($this->config->option->ticket_order->ticket_sold_member_actual) { + $ticketSoldMember = $t['member']; + } + // Check for empty date - Non date specific ticket + $tDate = "'".$d['date']."'"; + if ($d['date'] == '') { + $tDate = 'null'; + } + + // Build text with any policies + $policies = ''; + if (!empty($c['def_ticket_policy'])) { + $policies = $this->config->term->prop->cap." ".$this->config->term->ticket->norm + ." policy:\n".$c['def_ticket_policy']."\n\n"; + } + if (!empty($p['policy'])) { + $policies .= $this->config->term->performance->cap + ." policy:\n".$p['policy']."\n\n"; + } + if (!empty($policies)) { + $policies = addslashes($policies); + } + + // Create a unique package sold ID to link the package ticket with the package contents sold ({ticketID}-{sessionID}-{timestamp}) + $packageSoldID = $sid.'-'.++$ticketSequence; + + // If this is not a package, create a i record - note that ticket_order number will be updated later + $transaction[] = " + INSERT INTO eventmgt.ticket_sold + ( + ticket_order, + member, + member_name, + assigned, + assigned_from, + assigned_from_name, + performance, + performance_name, + entrance, + entrance_name, + entrance_color, + section, + section_name, + ticket, + ticket_name, + is_package, + package_sold_id, + ticket_package, + package_name, + date_specific, + ticket_date, + time_specific, + ticket_time, + start_date, + end_date, + likely_date, + price_paid, + voucher_type, + voucher_text, + policies, + unlimited_use, + numb_uses, + numb_claimed, + time_claimed, + session_id + ) + VALUES + ( + (SELECT currval('eventmgt.ticket_order_id_seq')), + ".$ticketSoldMember.", + '".$c['name']."', + ".($c['assigned'] ? 'true' : 'false').", + ".($c['assigned'] ? $c['assigned_from'] : 'NULL').", + '".($c['assigned'] ? $c['assigned_from_name'] : '')."', + ".$p['id'].", + '".$p['name']."', + ".(!empty($s['entrance']) ? $s['entrance'] : 'NULL').", + '".$s['entranceDetail']['name']."', + '".$s['entranceDetail']['color']['name']."', + ".$s['id'].", + '".$s['name']."', + ".$t['id'].", + '".$t['title']."', + ".($isPackageTicket ? 'true' : 'false').", + '$packageSoldID', + NULL, + '', + ".($t['date_specific']['value'] ? 'true' : 'false').", + $tDate, + ".($t['time_specific']['value'] ? 'true' : 'false').", + '".$t['ticket_timestamp']."', + ".(!empty($t['start_date']['date']) ? "'".$t['start_date']['date']."'" : 'NULL').", + ".(!empty($t['end_date']['date']) ? "'".$t['end_date']['date']."'" : 'NULL').", + ".(!empty($likelyDate) ? "'".$likelyDate."'" : 'NULL').", + ".$t['price_numb'].", + ".$t['voucher_type']['value'].", + '".$t['voucher_text']."', + '$policies', + ".($t['unlimited_use']['value'] ? 'true' : 'false').", + ".$t['uses'].", + 0, + null, + '".$sid."' + ); + "; + + // If this is a package, get package contents and save that as separate tickets sold. + if ($isPackageTicket) { + + reset ($packageData); + foreach ($packageData as $p) { + + // Get information on this package ticket + require_once EVENT_MANAGEMENT_APP_BASE.'classes/data/dataTickets.php'; + $Tickets = new EventManagementDataTickets($this->dbh, $this->config); + $pt = $Tickets->getTicketDetail($p['ticket']); + + // If option "ticket_sold_member_actual" is true, force member for ticket_sold to the memeber listed in the "ticket" table. + // This overrides some of the "assignment" alterations when selling by consignment and forces reports to always point to the actual ticket member. + $ticketSoldMember = $pt['member']; + if ($this->config->option->ticket_order->ticket_sold_member_actual) { + $ticketSoldMember = $t['member']; + } + + require_once EVENT_MANAGEMENT_APP_BASE.'classes/data/dataSections.php'; + $Sections = new EventManagementDataSections($this->dbh, $this->config); + $ps = $Sections->getSectionDetail($pt['section_id']); + + // Get Entrance information for this ticket's section + require_once EVENT_MANAGEMENT_APP_BASE.'classes/data/dataEntrances.php'; + $Entrances = new EventManagementDataEntrances($this->dbh, $this->config); + $pe = $Entrances->getEntranceDetail($ps['entrance']); + + + $transaction[] = " + INSERT INTO eventmgt.ticket_sold + ( + ticket_order, + member, + member_name, + assigned, + assigned_from, + assigned_from_name, + performance, + performance_name, + entrance, + entrance_name, + entrance_color, + section, + section_name, + ticket, + ticket_name, + is_package, + package_sold_id, + ticket_package, + package_name, + date_specific, + ticket_date, + time_specific, + ticket_time, + start_date, + end_date, + likely_date, + price_paid, + voucher_type, + voucher_text, + policies, + unlimited_use, + numb_uses, + numb_claimed, + time_claimed, + session_id + ) + VALUES + ( + (SELECT currval('eventmgt.ticket_order_id_seq')), + ".$ticketSoldMember.", + '".$pt['member_name']."', + false, + NULL, + '', + ".$pt['performance_id'].", + '".$pt['performance']."', + ".(!empty($pt['section_id']) ? $pt['section_id'] : 'NULL').", + '".$pe['name']."', + '".$pe['color']['name']."', + ".$ps['id'].", + '".$ps['name']."', + ".$pt['id'].", + '".$pt['title']."', + false, + '$packageSoldID', + ".$t['id'].", + '".$t['title']."', + false, + NULL, + false, + '".$pt['ticket_timestamp']."', + ".(!empty($pt['start_date']['date']) ? "'".$pt['start_date']['date']."'" : 'NULL').", + ".(!empty($pt['end_date']['date']) ? "'".$pt['end_date']['date']."'" : 'NULL').", + NULL, + 0, + ".$pt['voucher_type']['value'].", + '".$pt['voucher_text']."', + '', + ".($pt['unlimited_use']['value'] ? 'true' : 'false').", + ".$pt['uses'].", + 0, + null, + '".$sid."' + ); + "; + + + } + + } + + // Check for any add-ons included + if (isset($t['addons']) && count($t['addons']) > 0) { + + // For each add-on for this ticket + foreach ($t['addons'] as $a) { + + // If there's a quantity selected + if ($a['selected'] > 0) { + + $transaction[] = " + INSERT INTO eventmgt.add_on_sold + ( + ticket_order, + ticket_sold, + add_on_name, + add_on_type, + add_on_type_name, + unit_name, + unit_price, + quant, + price_paid, + session_id + ) + VALUES + ( + (SELECT currval('eventmgt.ticket_order_id_seq')), + (SELECT currval('eventmgt.ticket_sold_id_seq')), + '".$a['name']."', + ".$a['add_on_type']['value'].", + '".$a['add_on_type']['nameEsc']."', + '".$a['unit_name']."', + ".$a['unit_cost_numb'].", + ".$a['selected'].", + ".($a['unit_cost_numb'] * $a['selected']).", + '".$sid."' + ); + "; + + } // quant selected + } // each add-on + } // have add-ons + + // Check for any promos included + if (isset($t['promo']) && $t['promo']['credit_numb'] < 0) { + + $transaction[] = " + INSERT INTO eventmgt.promo_sold + ( + ticket_order, + ticket_sold, + promo, + promo_name, + promo_type, + promo_type_name, + amount, + session_id + ) + VALUES + ( + (SELECT currval('eventmgt.ticket_order_id_seq')), + (SELECT currval('eventmgt.ticket_sold_id_seq')), + ".$t['promo']['promo'].", + '".$t['promo']['promo_name']."', + ".$t['promo']['promo_type'].", + '".$t['promo']['promo_type_name']."', + ".$t['promo']['credit_each'].", + '".$sid."' + ); + "; + + } // promo + + } // each individual ticket + + // Update inventory + $availDecr = ''; + if (!$t['unlimited_quant']) { + $availDecr = "available = available - ".$t['selected'].","; + } + $transaction[] = " + UPDATE eventmgt.ticket_inventory + SET $availDecr + sold = sold + ".$t['selected']." + WHERE id = ".$t['invID']." + "; + + } // Each ticket type (inventory ID) + + } // Each section + + } // Each performance + + } // Each ticket date + + // Add SQL to clear holds + $transaction[] = "DELETE FROM eventmgt.inven_hold WHERE session_id = '".$sid."';"; + + // Attempt to process as a transaction - If checkout testing is not enabled. + if (!$this->config->option->checkout_testing) { + try { + $this->dbh->beginTransaction(); + foreach ($transaction as $sql) { + $this->dbh->exec($sql); + } + $this->dbh->commit(); + } catch (Exception $e) { + $this->dbh->rollBack(); + $error_msg = $e->getMessage(); + + $trouble_email .= "Error storing request: $error_msg\n\n".print_r($checkout_sql, 1)."\n\n"; + + $this->debug_mail( + 'cscott@gaslightmedia.com', + 'Event Management V3 - Check-Out SQL Failure', + "Event Management V3 - Check-Out SQL Failure\n\n" + ."Error Msg: ".$error_msg."\n\n" + .print_r($sql,1)."\n\n" + ."Entire Transaction:\n\n".print_r($transaction,1), + '' + ); + + // Say we couldn't store the order + return false; + } + + // Get order numbers and assign to proper cart entries + $sql = " + SELECT id + FROM eventmgt.ticket_order + WHERE session_id = '".$sid."' + AND member = ".$c['id']." + ;"; + $stmt = $this->dbh->prepare($sql); + $stmt->execute(); + $order = $stmt->fetch(PDO::FETCH_ASSOC); + + // Say we were able to store the order just fine + return $order['id']; + + } else { + // When checkout testing send the entire transaction to the debug page rather than execute it. + $this->sqlTransaction = $transaction; + } + + } + + /** + * Credit Card Number Input and Validation + * + * @param string $a Array element to store results - this function creates the entries + * @param string $f Name of the parameter + * @param string $cctype Selected card type + * @param string $ccnumb Card Number + * @param bool $req Required field flag + * + * @return array Array containing status and possible message + */ + private function ccnumbInput($a, $f, $cctype, $req, $id) + { + // Check for ID prefix + $fname = $f; + if ($id != false) { + $fname = $id."_".$f; + } + + // Get the card number + $in = preg_replace("/[^0-9.]/", "", trim(filter_input(INPUT_POST, $fname, FILTER_SANITIZE_NUMBER_INT))); + + // Always pass GLM test card number - last digit controls auth response - see classes/paymentProcessors/Test.php + if (substr($in,0,15) == '001100110011001') { + + $match = true; + + // Otherwise we're going to check the card number against the specified card type + } else { + + // Get the matching pattern for the supplied card type + $pattern = $this->config->ccverify->{$cctype}; + + // If we have a pattern then we have a valid card type, so try a match, otherwise it's just false + $match = false; + if ($pattern != '') { + $match = preg_match('/'.$pattern.'/', $in); + } + + } + + // Check the result + if (!$match) { + $problem = 'Card number does not appear to be correct for the selected card type.'; + $this->inputFail = true; + } + + // Setup results + $r = array( + 'value' => $in, + 'required' => $req, + 'problem' => $problem + ); + + // Store results into destination array + if ($id) { + $this->cd[$a][$id][$f] = $r; + } else { + $this->cd[$a][$f] = $r; + } + + } + + /** + * Create credit card type selection array + * + * array( + * 'value' = {selected card name if selected}, + * 'required' = {field is required flag}, + * 'problem' = {Problem description or empty string}, + * 'cccards' = array( + * {month#} => array( + * 'month' => {month#}, + * 'name' => {name of month}, + * 'selected' = {bool} + * ) + * ) + * ) + * + * @param $c Array of credit cards for venue with accepted flags + * @param $required Field is required flag + * @param $venue ID number of venue + * @param $cctype Supplied value of cctype or false if not supplied + * @param $init If set don't expect a value + * + * @return object containing array as sub-objects + */ + private function buildCCTypeArray($c, $required = false, $venue = false, $cctypeVal = false, $init = false) + { + + // Build credit cards accepted array + $cctype = array( + 'value' => '', + 'name' => '', + 'required' => $required, + 'problem' => '', + 'ccards' => array() + ); + + // If card is not specified in the function call, check for input value + if ($cctypeVal == false && isset($_REQUEST[$venue.'_cctype'])) { + $cctypeVal = (string) $_REQUEST[$venue.'_cctype']; + } + + // Scan card types for accepted by venue + foreach ($c['cards_accepted']['bitmap'] as $ca) { + + // If the card is selected for this venue + if ($ca['default']) { + + // Check if this is the selected card + $selected = false; + + // Make sure cctypeVal is not '' since 0 may be a valid card index + if ($cctypeVal != '' && $ca['value'] == $cctypeVal) { + $cctype['value'] = $ca['value']; + $cctype['name'] = $ca['name']; + $selected = true; + } + + // Add it to the array + $cctype['ccards'][$ca['value']] = array( + 'name' => $ca['name'], + 'value' => $ca['value'], + 'selected' => $selected + ); + } + } + + // Check if required value was not supplied + if (!$init && $required && $cctype['value'] === '') { + $cctype['problem'] = 'Required value not supplied'; + $this->inputFail = true; + } + + return $cctype; + + } + + /** + * Create arrays for credit card expiration picks + * + * array( + * 'value' = {text value of expiration if set - i.e. 05/2013}, + * 'required' = {field is required flag}, + * 'problem' = {Problem description or empty string}, + * 'ccmonths' = array( + * {month#} => array( + * 'month' => {month#}, + * 'name' => {name of month}, + * 'selected' = {bool} + * ) + * ), + * 'ccyears' = array( + * {year} => array( + * 'year' => {year - 4 digits}, + * 'selected' => {bool} + * ) + * ) + * + * @return object containing array as sub-objects + */ + private function buildCCExpArray($required = false, $venue = false, $ccmonth = false, $ccyear = false, $init = false) + { + + $monthNames = array( + 1 => 'January', + 2 => 'February', + 3 => 'March', + 4 => 'April', + 5 => 'May', + 6 => 'June', + 7 => 'July', + 8 => 'August', + 9 => 'September', + 10 => 'October', + 11 => 'November', + 12 => 'December' + ); + + $ccexp = array( + 'value' => '', + 'required' => $required, + 'problem' => '', + 'ccmonths' => array(), + 'ccyears' => array() + ); + + // If no month or specified in the function call, check for input values + if ($ccmonth == false && isset($_REQUEST[$venue.'_ccmonth'])) { + $ccmonth = ($_REQUEST[$venue.'_ccmonth'] - 0); + } + if ($ccyear == false && isset($_REQUEST[$venue.'_ccyear'])) { + $ccyear = ($_REQUEST[$venue.'_ccyear'] - 0); + } + + // Build months list + $monthSelected = false; + for ($m=1 ; $m<=12 ; $m++) { + $selected = ($m == $ccmonth); + $ccexp['ccmonths'][$m] = array( + 'month' => $m, + 'name' => $monthNames[$m], + 'selected' => $selected + ); + if ($selected) { + $monthSelected = true; + } + } + + // If the supplied month didn't match anything, make sure it's set to false + if (!$monthSelected) { + $ccmonth = false; + } + + // Build years list + $yearSelected = false; + for ($y=date('Y') ; $y<=date('Y',strtotime('now +10 years')) ; $y++) { + $selected = ($y == $ccyear); + $ccexp['ccyears'][$y] = array( + 'year' => $y, + 'selected' => $selected + ); + if ($selected) { + $yearSelected = true; + } + } + + // If this is an initialization of the field, then no validity checks + if ($init) { + return $ccexp; + } + + // If the supplied year didn't match anything, make sure it's set to false + if (!$yearSelected) { + $ccyear = false; + } + + // If there's a month and year, set the expriation value + if ($ccmonth != false && $ccyear != false) { + $ccexp['value'] = "$ccmonth/$ccyear"; + } + + // Check if required value was not supplied + if (!$init && $required && $ccexp['value'] == '') { + $ccexp['problem'] = 'Required value not supplied'; + $this->inputFail = true; + return $ccexp; + } + + // Check if supplied value is not in the past + $endOfExpMonth = strtotime("$ccmonth/1/$ccyear +1 month -1 day"); + if (time() > $endOfExpMonth) { + $ccexp['problem'] = 'Expiration date has passed.'; + $this->inputFail = true; + return $ccexp; + } + + return $ccexp; + } + + /** + * Build States array for use in pick-lists + * + * @param array $states Array of states + * @param string $selected State code of selected state + * @param boolean $required Is a required parameter + * @param boolean $checkProblem Set to false to prevent triggering problem output on initial setup + * + * @return array Array of states with 'stateID', 'stateName', 'stateSelected' + * @access public + */ + private function createStatesArray($name, $selected = '', $required = false, $checkProblem = true) + { + + $states = $this->config->states->toArray(); + + $value = false; + $problem = ''; + + // If nothing has been provided, check for URI input + if ($selected == '' || $selected == false) { + if (isset($_REQUEST[$name]) && $_REQUEST[$name] != '') { + $selected = $_REQUEST[$name]; + } + } + + $r = array(); + while (list($key, $val) = each($states)) { + $r[$key] = array( + 'stateID' => $key, + 'stateName' => $val, + 'stateSelected' => '' + ); + + if ($key == $selected) { + $r[$key]['stateSelected'] = 'selected'; + $value = $key; + $name = $val; + } + } + + // Check for required + if ($required && $value == false && $checkProblem) { + $problem = 'Required but not selected.'; + $this->inputFail = true; + } + + $r = array( + 'value' => $value, + 'name' => $name, + 'required' => $required, + 'problem' => $problem, + 'states' => $r + ); + + return $r; + } + + /** + * Build Countries array for use in pick-lists + * + * @param array $countries Array of countries + * @param string $selected Country code of selected country + * @param boolean $required Required parameter + * @param boolean $checkProblem Set to false to keep from triggering problem on initial setup + * + * @return array Array of countries with 'countryID', 'countryName', 'countrySelected' + * @access public + */ + private function createCountriesArray($name, $selected = '', $required = false, $checkProblem = true) + { + + $countries = $this->config->countries->toArray(); + + $value = false; + $problem = ''; + + // If nothing has been provided, check for URI input + if ($selected == '' || $selected == false) { + if (isset($_REQUEST[$name]) && $_REQUEST[$name] != '') { + $selected = $_REQUEST[$name]; + } + } + + $r = array(); + while (list($key, $val) = each($countries)) { + $r[$key] = array( + 'countryID' => $key, + 'countryName' => $val, + 'countrySelected' => '' + ); + + if ($key == $selected) { + $r[$key]['countrySelected'] = 'selected'; + $value = $key; + $name = $val; + } + } + + // Check for required + if ($required && $value == false && $checkProblem) { + $problem = 'Required but not selected.'; + $this->inputFail = true; + } + + return array( + 'value' => $value, + 'name' => $name, + 'required' => $required, + 'problem' => $problem, + 'countries' => $r + ); + } + + /** + * If debug for mail turned on, display E-Mail messages rather than send them + * + * @access public + */ + public function debug_mail( $to, $subject, $message, $headers = '', $parameters = '' ) + { + if( $this->config->debug->mail ) + { + echo '

    + + + + + + + +
    MAIL DEBUG
    Recipient(s): '.$to.'
    Subject: '.$subject.'
    Headers:
    '.$headers.'
    Parameters:
    '.$parameters.'
    '.$message.'
    +

    + '; + return( true ); + } else { + return( mail( $to, $subject, $message, $headers, $parameters ) ); + } + } + + + +} + +?> diff --git a/models/front/classes/support.php b/models/front/classes/support.php new file mode 100644 index 0000000..4308f81 --- /dev/null +++ b/models/front/classes/support.php @@ -0,0 +1,1602 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: classes/support.php,v 1.0 2011/01/25 19:31:47 cscott Exp $ + * @link <> + */ + +/** + * EventManagementFrontSupport class + * + * Event Management and Reservations System - Admin Code - Contacts ticket + * + * PHP version 5 + * + * @category Event Management Admin Tickets + * @package EventManagement + * @author Chuck Scott + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: classes/support.php,v 1.0 2011/01/25 19:31:47 cscott Exp $ + * @link <> + */ + +class EventManagementFrontSupport +{ + + /** + * Configuration information object + * @var $ini + * @access public + */ + protected $config; + /** + * Database Object + * @var $dbh + * @access public + */ + protected $dbh; + + function __construct($dbh, $config) + { + + $this->dbh = $dbh; + $this->config = $config; + + } + + /** + * Get list of active members + * + * @return object containing array as sub-objects + */ + public function getMembersList($option = 'all') + { + require_once EVENT_MANAGEMENT_APP_BASE.'classes/data/dataMembers.php'; + $Members = new EventManagementDataMembers($this->dbh, $this->config); + $Members->optionIncludeSelectListData = false; + $membersList = $Members->getMembersList($option, 'TRUE', 'sort, name'); + return $membersList; + } + + /** + * Get list of entrances for a specific member + * + * @return object containing array as sub-objects + */ + public function getEntrancesList($memberID) + { + require_once EVENT_MANAGEMENT_APP_BASE.'classes/data/dataEntrances.php'; + $Entrances = new EventManagementDataEntrances($this->dbh, $this->config); + $Entrances->optionIncludeSelectListData = false; + $entrancesList = $Entrances->getEntrancesList($memberID); + return $entrancesList; + } + + /** + * Get information on a specific entrance + * + * @return object containing array as sub-objects + */ + public function getEntranceData($entranceID) + { + require_once EVENT_MANAGEMENT_APP_BASE.'classes/data/dataEntrances.php'; + $Entrances = new EventManagementDataEntrances($this->dbh, $this->config); + $Entrances->optionIncludeSelectListData = false; + $entranceDetail = $Entrances->getEntranceDetail($entranceID); + return $entranceDetail; + } + + /** + * Get information on a specific venue/member + * + * @return object containing array as sub-objects + */ + public function getMemberData($memberID = false) + { + require_once EVENT_MANAGEMENT_APP_BASE.'classes/data/dataMembers.php'; + $Members = new EventManagementDataMembers($this->dbh, $this->config); + $Members->optionIncludeSelectListData = false; + $memberDetail = $Members->getMemberDetail($memberID); + return $memberDetail; + } + + /** + * Get all information / tickets for a performance + * Organize for ticket selection on front end. + * + * This function returns detail about the performance, + * a list of sections, with a list of tickets under each, + * and a list of ticket inventory by ticket ID. The latter + * is sent to the front-end scripts as a JSON for interactive + * date and quantity selection. + * + * If the optional section ID is not provided, then all sections + * for the performance that have tickets will be included. + * + * @param $perfID integer A required performance ID + * @param $sectionID integer An optional sectionID + * + * @return object containing array of ... + * array( + * 'performanceDetail', + * 'sections', + * 'inventory' + * ); + */ + public function getAllPerformanceData($perfID = 0, $sectionID = 0) + { + + $sections = array(); + $inventory = array(); + $oneSectionOnly = false; + $havePerformanceTickets = false; + + // Check supplied Performance ID + if ($perfID == 0) { + $this->reason[] = 'No '.$this->config->term->event->norm.' has been selected.'; + return false; + } else { + + // Get selected performance data + $performanceDetail = $this->getPerformanceData($perfID); + + // If we can't find the performance + if (!$performanceDetail) { + $this->reason[] = 'We were unable to find the selected '.$this->config->term->event->norm.'.'; + } else { + + // If a specific section is provided, then only do that section + $where = false; + if ($sectionID > 0) { + $where = "T.id = $sectionID"; + } + + // Get sections list for this member + $sectionsList = $this->getSectionList($performanceDetail['member_id'], $where); + + // If there's only one, then note that for the template + if ($sectionsList && count($sectionsList) == 1) { + $oneSectionOnly = true; + } + + // for each of the sections, get the performance data and tickets + foreach ($sectionsList as $section) { + + $sectID = $section['id']; + + // Get selected section data. We'll add this later if there's tickets found + $sectionDetail = $this->getSpecifiedSectionDetail($sectID); + + // Get Ticket List for this performance and in the current section + $ticketList = $this->getSectionTicketList($perfID, $sectID); + + // If no tickets found for this performance and section + if (!$ticketList) { + $this->reason[] = 'We were unable to find any '.$this->config->term->ticket->plur.' for this '.$this->config->term->event->norm.'.'; + } else { + + $havePerformanceTickets = true; + + // Add this section to our sections list + $sections[$sectID] = array(); + $sections[$sectID]['sectionDetail'] = $sectionDetail; + + // Add ticket data to this section + $sections[$sectID]['ticketsData'] = array(); + reset($ticketList); + foreach ($ticketList as $t) { + $sections[$sectID]['ticketsData'][$t['id']] = $t; + } + + // Assemble data for each ticket (date, quant, etc) + $ticketsData = array(); + reset($ticketList); + while (list($k, $v) = each($ticketList)) { + + // Get inventory for this ticket + $inventoryList = $this->getInventoryList($v['id'], 'T.active', true); + + $haveFutureInventory = false; + + // For each inventory item + $invData = array(); + + // If no inventory found for this ticket + if (!$inventoryList) { + + $this->reason[] = 'We were unable to find inventory for the selected '.$this->config->term->ticket->norm.'.'; + } else { + + foreach ($inventoryList as $inv) { + + // Check for bogus inventory + if (($v['date_specific']['value'] == 1 && $inv['ticket_date']['date'] != '') || + ($v['date_specific']['value'] != 1 && $inv['ticket_date']['date'] == '')) { + + $invDate = $inv['ticket_date']['date']; + + // Check if date in the future + if ($inv['ticket_date']['timestamp'] > strtotime('yesterday')) { + $haveFutureInventory = true; + } + + // Trim unwanted data + unset($inv['ticket_name']); + unset($inv['ticket_id']); + + // Determine if any of the dates are too late to buy on-line. + // If no timestamp then it's not a date-specific ticket, so no purchase leadtime issue. + if ($inv['ticket_date']['timestamp']) { + $timeStr = $inv['ticket_date']['date'].' '.$inv['ticket_time']['time']; + $ticketTime = strtotime($timeStr); + $leadTime = $performanceDetail['purch_leadtime']*3600; + + // Admin users can override this + if ($_SESSION[GLM_EVENT_SESSION]['AdminUser']) { + $leadTime = 0; + } + + $inv['tooLate'] = time() > ($ticketTime - $leadTime); + + + } else { + $inv['tooLate'] = false; + } + + // Check for unlimited quantities + if ($inv['unlimited_quant']) { + $inv['available'] = $this->config->option->tickets_select_max; + } + + $invData[$invDate] = $inv; + + } + } + } + + // Add ticket ID, date specific flag, and inventory list to our inventory array + $inventory[$v['id']] = array( + 'id' => $v['id'], + 'haveFutureInventory' => $haveFutureInventory, + 'dateSpecific' => $v['date_specific']['value'], + 'startDate' => $v['start_date']['date'], + 'endDate' => $v['end_date']['date'], + 'inventory' => $invData + ); + + // Check for ticket add-ons + require_once EVENT_MANAGEMENT_APP_BASE.'classes/data/dataAddons.php'; + $Addons = new EventManagementDataAddons($this->dbh, $this->config); + $ticketAddonsList = $Addons->getAddonsList($v['id']); + if ($ticketAddonsList) { + foreach($ticketAddonsList as $ta) { + $ta['selected'] = 0; + $sections[$sectID]['ticketsData'][$v['id']]['addons'][$ta['id']] = $ta; + } + } + + // Check for package data + if ($this->config->option->packages && $v['ticket_type']['value'] == 20) { + require_once EVENT_MANAGEMENT_APP_BASE.'classes/data/dataTicketPackages.php'; + $TicketPackages = new EventManagementDataTicketPackages($this->dbh, $this->config); + $packageData = $TicketPackages->getPackageList("package = ".$v['id']); + $sections[$sectID]['ticketsData'][$v['id']]['packageData'] = $packageData; + } + + // Determine if tickets may or may not be purchased at this time + $mayBuyNow = true; + $tooEarlyToBuy = false; + if ($v['for_sale_start_date']['date'] != null && $v['for_sale_start_date']['date'] != '') { + if (time() < $v['for_sale_start_date']['timestamp']) { + $tooEarlyToBuy = true; + $mayBuyNow = false; + } + } + $tooLateToBuy = false; + if ($v['for_sale_end_date']['date'] != null && $v['for_sale_end_date']['date'] != '') { + if (time() > strtotime($v['for_sale_end_date']['date'].' +1 day')) { + $tooLateToBuy = true; + $mayBuyNow = false; + } + } + $sections[$sectID]['ticketsData'][$v['id']]['mayBuyNow'] = $mayBuyNow; + $sections[$sectID]['ticketsData'][$v['id']]['tooEarlyToBuy'] = $tooEarlyToBuy; + $sections[$sectID]['ticketsData'][$v['id']]['tooLateToBuy'] = $tooLateToBuy; + + $sections[$sectID]['ticketsData'][$v['id']]['start_end_dates_same'] = ($v['start_date'] == $v['end_date']); + + } // each ticket + + } // Have tickets + + } // For each section for this member + + } // Have performance data + + } // Have performance ID + + if (!$havePerformanceTickets) { + return false; + } + + // Assemble return data array + $perfData = array( + 'oneSectionOnly' => $oneSectionOnly, // Flag that indicates if we have more than one section listed + 'performanceDetail' => $performanceDetail, // Detail about requested Performance + 'sections' => $sections, // Array of sections with section detail and ticket data + 'inventory' => $inventory // Array of ticket inventory + + ); + + return $perfData; + + } + + + /** + * Get information on a specific performance based on performance selected in URI or session + * + * @return object containing array as sub-objects + */ + public function getPerformancesList($memberID, $listType = 'member') + { + require_once EVENT_MANAGEMENT_APP_BASE.'classes/data/dataPerformances.php'; + $Performances = new EventManagementDataPerformances($this->dbh, $this->config); + $Performances->optionIncludeSelectListData = false; + $performancesList = $Performances->getPerformancesList($listType, $memberID, $_SESSION[GLM_EVENT_SESSION]['AdminUser']); + return $performancesList; + } + + /** + * Get information on a specific performance based on performance selected in URI or session + * + * @return object containing array as sub-objects + */ + public function getPerformanceData($perfID = false) + { + require_once EVENT_MANAGEMENT_APP_BASE.'classes/data/dataPerformances.php'; + $Performances = new EventManagementDataPerformances($this->dbh, $this->config); + $Performances->optionIncludeSelectListData = false; + $performanceDetail = $Performances->getPerformanceDetail($perfID); + return $performanceDetail; + } + + /** + * Get information on sections for a member + * + * @var $id ID of member + * @return object containing array as sub-objects + */ + public function getSectionList($memberID = false, $where = false) + { + require_once EVENT_MANAGEMENT_APP_BASE.'classes/data/dataSections.php'; + $Sections = new EventManagementDataSections($this->dbh, $this->config); + $Sections->optionIncludeSelectListData = false; + $sectionsList = $Sections->getSectionsList($memberID, $where); + return $sectionsList; + } + + /** + * Get information on a specific section + * + * @var $id ID of section + * @return object containing array as sub-objects + */ + public function getSpecifiedSectionDetail($sectionID = false) + { + require_once EVENT_MANAGEMENT_APP_BASE.'classes/data/dataSections.php'; + $Sections = new EventManagementDataSections($this->dbh, $this->config); + $Sections->optionIncludeSelectListData = false; + $sectionsDetail = $Sections->getSectionDetail($sectionID); + return $sectionsDetail; + } + + /** + * Get section ticket list + * + * @var $id ID of section + * @return object containing array as sub-objects + */ + public function getSectionTicketList($performance, $section) + { + // Get Tickets and Inventory Information + require_once EVENT_MANAGEMENT_APP_BASE.'classes/data/dataTickets.php'; + $Tickets = new EventManagementDataTickets($this->dbh, $this->config); + $Tickets->optionIncludeSelectListData = false; + $ticketsList = $Tickets->getTicketsList(false, $performance, $section, false, true, false, $_SESSION[GLM_EVENT_SESSION]['AdminUser'], false, $this->config->option->packages); + + return $ticketsList; + } + + /** + * Get specific ticket detail + * + * @var $id ID of ticket + * @return object containing array as sub-objects + */ + public function getSpecifiedTicketDetail($ticketID = false) + { + // Get Tickets and Inventory Information + require_once EVENT_MANAGEMENT_APP_BASE.'classes/data/dataTickets.php'; + $Tickets = new EventManagementDataTickets($this->dbh, $this->config); + $Tickets->optionIncludeSelectListData = false; + $ticketDetail = $Tickets->getTicketDetail($ticketID); + + // Check for ticket add-ons + require_once EVENT_MANAGEMENT_APP_BASE.'classes/data/dataAddons.php'; + $Addons = new EventManagementDataAddons($this->dbh, $this->config); + $Addons->optionIncludeSelectListData = false; + $ticketAddonsList = $Addons->getAddonsList($ticketID); + if ($ticketAddonsList) { + foreach($ticketAddonsList as $ta) { + $ta['selected'] = 0; + $ticketDetail['addons'][$ta['id']] = $ta; + } + } + + return $ticketDetail; + } + + /** + * Get inventory for a ticket + * + * @var $id ID of inventory item + * @return object containing array as sub-objects + */ + public function getInventoryList($ticketID = false, $where = 'T.active', $dateKey = false) + { + require_once EVENT_MANAGEMENT_APP_BASE.'classes/data/dataTicketInventory.php'; + $TicketInventory = new EventManagementDataTicketInventory($this->dbh, $this->config); + $TicketInventory->optionIncludeSelectListData = false; + $inventoryList = $TicketInventory->getTicketInventoryList($ticketID, $where, $dateKey); + return $inventoryList; + } + + /** + * Get specific ticket inventory item information + * Optionally get extended data for section and entrance + * + * @var $id ID of inventory item + * @return object containing array as sub-objects + */ + public function getInventoryDetail($invenID = false, $extended = false) + { + require_once EVENT_MANAGEMENT_APP_BASE.'classes/data/dataTicketInventory.php'; + $TicketInventory = new EventManagementDataTicketInventory($this->dbh, $this->config); + $TicketInventory->optionIncludeSelectListData = false; + $inventoryDetail = $TicketInventory->getTicketInventoryDetail($invenID, $extended); + return $inventoryDetail; + } + + /** + * Get list of tickets for a particular promo code + * + * @var $ticketID ID of ticket + * @return object containing array as sub-objects + */ + public function getPromoTicketsList($promoCode) + { + // Get Tickets and Inventory Information + require_once EVENT_MANAGEMENT_APP_BASE.'classes/data/dataPromoTickets.php'; + $promoTickets = new EventManagementDataPromoTickets($this->dbh, $this->config); + $promoTickets->optionIncludeSelectListData = false; + + $promoTicketsList = $promoTickets->getPromoTicketsList(false, $promoCode); + + // Use ticket IDs as the index + $pt = array(); + if ($promoTicketsList && count($promoTicketsList) > 0) { + foreach($promoTicketsList as $p) { + $pt[$p['ticket']] = $p; + } + } + + return $pt; + } + + /** + * Format a number as money + * + * @param $value Value to format + * @param $option Options that control output + * NOPREFIX stops the "$" prefix + * + * @return none + * @access public + */ + private function money($value, $option = "") + { + + if ($option == "NOPREFIX") + $prefix = ""; + else + $prefix = "$"; + + // Do value sanity check + + if (!is_numeric($value)) + return ($prefix."0.00"); + + return ($prefix.number_format($value, 2, ".", ",")); + } + + /* + * Get current number held and number available + * Also return if unlimited quantity ticket + * + * @var $id ID of ticket_inventory item + * @return object containing array as sub-objects + */ + private function getInvenStatus($id) + { + + // Check if inventory ID is sane + if (($id-0) == 0) { + return false; + } + + // Get available and held quantities. + $sql = " + SELECT I.available as available, + T.unlimited_quant as unlimited_quant, + ( + SELECT SUM(quant) + FROM eventmgt.inven_hold + WHERE hold_type = ".$this->config->hold_types->ticket." + AND inventory = $id + AND expire_time > 'now' + ) AS held + FROM eventmgt.ticket_inventory I, + eventmgt.ticket T + WHERE I.id = $id + AND T.id = I.ticket + ;"; + $stmt = $this->dbh->prepare($sql); + $stmt->execute(); + $s = $stmt->fetch(PDO::FETCH_ASSOC); + + // Calculated net available + $s['avail_not_held'] = $s['available'] - ($s['held'] - 0); + + // Check if unlimited quant and if so set to maximum selectable + if ($s['unlimited_quant']) { + $s['available'] = $this->config->option->tickets_select_max; + $s['avail_not_held'] = $this->config->option->tickets_select_max; + } + + // Include inventory item ID for reference + $s['invID'] = $id; + + return $s; + } + + /** + * Check for new cart submission and get all cart data + * + * @param cart Array containing status, reasons, and cart contents + * @return object containing array as sub-objects + */ + private function checkCartAdd($d) + { + + // If there's nothing being added + if (!isset($_REQUEST['cart']) || $_REQUEST['cart'] != 'add') { + return $d; + } + + // Check if we received a single item + if (isset($_REQUEST['ticket_inv'])) { + $invItem = ($_REQUEST['ticket_inv']-0); + $addon = ($_REQUEST['addon']-0); + $quant = ($_REQUEST['quant']-0); + + if (($quant-0) > 0) { + + $d = $this->addItemToCart($d, invItem, $addon, quant); + + } + } + + // Check if we're receiving an array of new additions + if (isset($_REQUEST['ticket_inv_array'])) { + + // Key is ticket ID, value is inventory ID + $tickInvArray = $_REQUEST['ticket_inv_array']; + if (is_array($tickInvArray) && count($tickInvArray) > 0) { + while (list($k, $v) = each($tickInvArray)) { + $invItem = $v; + $quant = $_REQUEST['quant'][$k]; + if (($quant-0) > 0) { + $d = $this->addItemToCart($d, $v, 0, $quant); + } + } + } + + // Check for any add-ons + $GLMaddonTicketInvID = $_REQUEST['GLMaddonTicketInvID']; + if (is_array($GLMaddonTicketInvID) && count($GLMaddonTicketInvID) > 0) { + while (list($k2, $v2) = each($GLMaddonTicketInvID)) { + $addon = $_REQUEST['GLMaddonID'][$k2]; + $quant = $_REQUEST['GLMaddonQuant'][$k2]; + if (($quant-0) > 0) { + $d = $this->addItemToCart($d, $v2, $addon, $quant); + } + } + } + } + + // Update cart in session + $_SESSION[GLM_EVENT_SESSION]['TicketCart'] = $d['cart']; + + return $d; + + } + + /** + * Add a ticket to the cart + * + * @param cart Array containing status, reasons, and cart contents + * other parameters to be determined + * @return object containing array as sub-objects + */ + private function addItemToCart($d, $invItem, $addon, $quant) + { + + // Check if request is sane + if ($invItem > 0 && $quant > 0) { + + // If this is an add-on request + if ($addon > 0) { + + // Check if this addon is the same as another entry and merge + if (isset($d['cart'][$invItem]['addons'][$addon])) { + // Add the new quantity + $d['cart'][$invItem]['addons'][$addon]['quant'] += 1; + } else { + $d['cart'][$invItem]['addons'][$addon] = array( + 'id' => $addon, + 'quant' => $quant + ); + } + + return $d; + + } + + // Get current quantity and number held (also clears old entries) + $ticketQuant = $this->getInvenStatus($invItem); + + // If there's not enough available + if (!$ticketQuant['unlimited_quant'] && $quant > $ticketQuant['avail_not_held']) { + $d['reason'][] = 'The quantity requested was greater than number currently available.'; + return $d; + } + + } else { + $d['reason'][] = 'The request to add to the cart was not complete or an unknown error occurred.'; + return $d; + } + + // Check if the new tickets are the same as another entry and merge + if (isset($d['cart'][$invItem])) { + + // Add the new quantity + $d['cart'][$invItem]['quant'] += $quant; + + } else { + + // Get inventory item data + $invenDetail = $this->getInventoryDetail($invItem); + + // Not same as an existing entry, so add it + $d['cart'][$invItem] = array( + 'invenID' => $invItem, + 'member' => $invenDetail['member'], + 'assigned' => false, + 'quant' => $quant + ); + + } + + return $d; + + } + + /** + * Check for cart update + * + * @param cart Array containing status, reasons, and cart contents + * @return object containing array as sub-objects + */ + private function checkCartUpdate($d) + { + + // If the cart's not being updated + if (!isset($_REQUEST['cart']) || $_REQUEST['cart'] != 'update') { + return $d; + } + + // Get updated ticket data + $invItem = ($_REQUEST['ticket_inv']-0); + $addon = ($_REQUEST['addon']-0); + $quant = ($_REQUEST['quant']-0); + + // Check if request isn't sane + if ($invItem == 0) { + $d['reason'][] = 'The request to change a cart quantity was not complete or an unknown error occurred.'; + return $d; + } + + // If this is an add-on update + if ($addon > 0) { + + $d['cart'][$invItem]['addons'][$addon] = array( + 'id' => $addon, + 'quant' => $quant + ); + + // Otherwise it's a regular ticket update + } else { + + // Get current quantity and number held + $ticketQuant = $this->getInvenStatus($invItem); + + // If there's not enough available (for this session, which is why we add the selected quant back in) + if (!$ticketQuant['unlimited_quant'] && $quant > $ticketQuant['avail_not_held'] + $d['cart'][$invItem]['quant']) { + $d['reason'][] = 'The quantity requested was greater than number currently available.'; + return $d; + } + + // If quantity is 0 then delete the entry unless it's a sticky item, otherwise update it + if ($quant == 0 && !$_SESSION[GLM_EVENT_SESSION]['TicketCart'][$invItem]['sticky']) { + unset($d['cart'][$invItem]); + } else { + $d['cart'][$invItem]['quant'] = $quant; + } + + // If there's still a cart entry and it's 0 now + if (isset($d['cart'][$invItem]) && $d['cart'][$invItem]['quant'] == 0) { + + // Set any addons to 0 + if (isset($d['cart'][$invItem]['addons']) && count($d['cart'][$invItem]['addons']) > 0) { + foreach ($d['cart'][$invItem]['addons'] as $a) { + $d['cart'][$invItem]['addons'][$a['id']]['quant'] = 0; + } + } + + } + + } + + // Update cart in session + $_SESSION[GLM_EVENT_SESSION]['TicketCart'] = $d['cart']; + + return $d; + + } + + /** + * Update holds for the provided cart + * + * @param cart Array containing status, reasons, and cart contents + * @return null + */ + private function updateHolds($cart) + { + + // Start by deleting all holds for this session + $sql = " + BEGIN; + DELETE FROM eventmgt.inven_hold + WHERE session_id = '".$_SESSION[GLM_EVENT_SESSION]['SessionID']."' + ;"; + + $expTime = date('r', strtotime('now +'.$this->config->ticket_hold_time.' minutes')); + + // For each cart entry + if ($cart != false) { + + foreach ($cart as $c) { + + // Check if this is a valid cart entry + if (isset($c['invenID']) && count($c['invenID']) > 0) { + + // Recreate hold with updated expire time + $sql .= " + INSERT INTO eventmgt.inven_hold + ( + hold_type, inventory, quant, expire_time, session_id + ) + VALUES + ( + ".$this->config->hold_types->ticket.", + ".$c['invenID'].", + ".$c['quant'].", + '$expTime', + '".$_SESSION[GLM_EVENT_SESSION]['SessionID']."' + ) + ;"; + + } + } + + } + + $sql .= 'COMMIT;'; + $this->dbh->exec($sql); + + } + + /** + * Check cart for new submissions or updates and return current cart data + * + * Structure of cart array in SESSION + * + * array( + * 'cartID' => array( + * 'invenID' => {ID of the eventmgt.ticket_inventory item}, + * 'quant' => {number requested} + * ) + * ) + * + * @return object containing array as sub-objects + */ + public function checkCart($checkout = false) + { + // Housecleaning: Remove all old hold entries + // If they timed out they don't matter anyway, but this cleans up the table + $this->dbh->exec("DELETE FROM eventmgt.inven_hold WHERE expire_time < 'now';"); + + $r = array( + 'status' => false, + 'reason' => array(), + 'cartHasContents' => false, + 'cartRequiresPayment' => true, + 'cart' => $_SESSION[GLM_EVENT_SESSION]['TicketCart'], + 'cartData' => false, + 'cartDataReorganized' => false, + 'blockCheckout' => false, + 'blockCheckoutNonAssignment' => false, + 'doingAdditionalInfo' => false, + 'forceCheckoutPhase' => false, + 'checkoutComplete' => false + ); + + /* + * Check if any credit cards have been charged for any venues. + * If none are charged then we're not checked out but we aren't forcing checkout phase + * If some were charged and others weren't, then we're forcing checkout phase + * If all were charged, then checkout is complete + */ + if ($_SESSION[GLM_EVENT_SESSION]['TicketPayments'] != false) { + + // Check each payment entry to see if any have been charged and any are not + $charged = false; + $notCharged = false; + foreach ($_SESSION[GLM_EVENT_SESSION]['TicketPayments'] as $pmt) { + if ($pmt['approved']) { + $charged = true; + } else { + $notCharged = true; + } + } + + // if all were charged and none not charged + if ($charged && !$notCharged) { + $r['checkoutComplete'] = true; // Checkout complete + } + + // If some were charged and some weren't + if ($charged && $notCharged) { + $r['forceCheckoutPhase'] = true; // Partial checkout so Set forceCheckoutPhase + } + + } + + // Only check for cart additions or updates if forceCheckoutPhase is not set + if (!$r['forceCheckoutPhase']) { + + // Check if anything is being added to the cart + $r = $this->checkCartAdd($r); + + // Check if there's a cart update + $r = $this->checkCartUpdate($r); + + } + + // Update Holds for this cart + $this->updateHolds($r['cart']); + + // We're here so must be successful + $r['status'] = true; + + /* + * We're now going to build an array of cart contents for output with the following structure + * + * [member & assignment], [date], [perfomance], [section], [ticket], [quant & inventory] + */ + $cartData = array(); + + // Check if there's anything in the cart + $cartItemRemoved = false; // To track whether we had to delete an item from the cart for missing data + if ($r['cart'] != false) { + + $totalVenues = 0; + $totalTickets = 0; + $totalNoPayment = 0; + $grandTotalPrice = 0; + $totalPrice = 0; + + // Check to see if there's an active promo code and return ticket info for that code + $promoTicketsList = false; + if (isset($_SESSION[GLM_EVENT_SESSION]['PromoCode']) && $_SESSION[GLM_EVENT_SESSION]['PromoCode'] != '') { + $promoTicketsList = $this->getPromoTicketsList($_SESSION[GLM_EVENT_SESSION]['PromoCode']); + } + + // Get all data associated with this cart entry + foreach ($r['cart'] as $c) { + + // Get inventory record detail and status + $invID = $c['invenID']; + $invDetail = $this->getInventoryDetail($invID); + $invStatus = $this->getInvenStatus($invID); + + // Get Ticket info + $ticketDetail = $this->getSpecifiedTicketDetail($invDetail['ticket_id']); + + $memb = $ticketDetail['member']; + + // Check for assignment + $assignedFrom = false; + $assigned = false; + $assignedEntrance = false; + if ($checkout && isset($_SESSION[GLM_EVENT_SESSION]['Assignment'][$memb])) { + + // Keep track of original ticket member + $assignedFrom = $memb; + + // Set assignment information for this cart entry + $assigned = $_SESSION[GLM_EVENT_SESSION]['Assignment'][$memb]; + + // And save back into session cart + $_SESSION[GLM_EVENT_SESSION]['TicketCart'][$invID]['assigned'] = $assigned; + + // Now set our current member to the assignment + $memb = $assigned; + + // Also get the assigned from member name + $mDet = $this->getMemberData($assignedFrom); + $assignedFromName = $mDet['name']; + unset($mDet); + + // Also now check if there's been an entrance assignment + if (isset($_SESSION[GLM_EVENT_MGT_FRONT]['AssignmentEntrance'][$assignedFrom])) { + $assignedEntrance = $_SESSION[GLM_EVENT_SESSION]['AssignmentEntrance'][$assignedFrom]; + } + + } + + // Get member info + $memberDetail = $this->getMemberData($memb); + + // Get Section info + $sectionDetail = $this->getSpecifiedSectionDetail($ticketDetail['section_id']); + + // Get performance info + $performanceDetail = $this->getPerformanceData($ticketDetail['performance_id']); + + // Make sure we have all needed information - Perhaps something has been deleted + if ($ticketDetail && $memberDetail && $memberDetail['active']['value'] && $sectionDetail && performanceDetail) { + + // If Venue/Member hasn't been added yet + $membID = $memberDetail['id']; + if (!isset($cartData[$membID])) { + + $cartData[$membID] = $memberDetail; + $cartData[$membID]['assigned'] = ($assignedFrom != false); + $cartData[$membID]['assigned_from'] = $assignedFrom; + $cartData[$membID]['assigned_from_name'] = $assignedFromName; + $cartData[$membID]['needLikelyDate'] = false; + $cartData[$membID]['likelyDate'] = false; + $cartData[$membID]['dates'] = array(); + $cartData[$membID]['totalTickets'] = 0; + $cartData[$membID]['totalPrice'] = 0; + $cartData[$membID]['totalPrice_numb'] = 0; + $cartData[$membID]['no_payment'] = false; + + $totalVenues++; + + // Also check for a completed payment for this member + if (isset($_SESSION[GLM_EVENT_SESSION]['TicketPayments'][$membID]) && $_SESSION[GLM_EVENT_SESSION]['TicketPayments'][$membID]['approved']) { + + // Add this payment information to the cart + $cartData[$membID]['paymentResult'] = $_SESSION[GLM_EVENT_SESSION]['TicketPayments'][$membID]; + } + + } + + // Set alias for dates array + $dates = &$cartData[$membID]['dates']; + + // If Date hasn't been added yet - also check for no date (non date-specific) + $date = $invDetail['ticket_date']['date']; + if ($date == '') { + $date = 0; + } + if (!isset($dates[$date])) { + $dates[$date] = array( + 'date' => $date, + 'fullDate' => date('l F j, Y', strtotime($date)), + 'performances' => array(), + 'dateSpecific' => (trim($date) != '' && strtotime($date) > 0) + ); + } + $performances = &$dates[$date]['performances']; + + // If Performance hasn't been added yet + $perfID = $performanceDetail['id']; + if (!isset($performances[$perfID])) { + $performances[$perfID] = $performanceDetail; + $performances[$perfID]['sections'] = array(); + } + $sections = &$performances[$perfID]['sections']; + + // If Section hasn't been added yet + $sectID = $sectionDetail['id']; + if (!isset($sections[$sectID])) { + $sections[$sectID] = $sectionDetail; + $sections[$sectID]['tickets'] = array(); + + // Check if there's been an Entrance Assignment and use that for the entrance data for the section + if ($assignedEntrance) { + $sections[$sectID]['entrance'] = $assignedEntrance; + } + + // If we have an entrance with this section, get the detail + if ($sections[$sectID]['entrance']) { + $sections[$sectID]['entranceDetail'] = $this->getEntranceData($sections[$sectID]['entrance']); + } + + } + $tickets = &$sections[$sectID]['tickets']; + + // If this ticket hasn't been added yet (shouldn't be) + $ticID = $ticketDetail['id']; + if (!isset($tickets[$ticID])) { + + // Add ticket detail to tickets and set other standard parameters + $tickets[$ticID] = array_merge($ticketDetail, $invStatus); + $tickets[$ticID]['selected'] = $c['quant']; + $tickets[$ticID]['show_price'] = true; // False if only price is with add-ons + $tickets[$ticID]['show_accumulated_total'] = false; // Use when add-ons are included + $tickets[$ticID]['show_addons'] = false; // Use when add-ons are included + $tickets[$ticID]['problem'] = false; + + // Calculate base ticket price + $ext = $c['quant'] * $ticketDetail['price_numb']; + + // Do we have any addons for this ticket? + if (count($ticketDetail['addons']) > 0) { + + // For each add-on associated with this ticket + $addons_ext = 0; + foreach ($ticketDetail['addons'] as $a) { + + // If this addon is in the cart + if (isset($c['addons']) && isset($c['addons'][$a['id']])) { + + // Check if no cost is with the ticket, only in the add-on + if ($ext == 0) { + $tickets[$ticID]['show_price'] = false; + } + + // Set the quantity and tally price + $addon_quant = $c['addons'][$a['id']]['quant']; + $tickets[$ticID]['addons'][$a['id']]['selected'] = $addon_quant; + $addon_ext = $addon_quant * $a['unit_cost_numb'] * $c['quant']; + $tickets[$ticID]['addons'][$a['id']]['ext'] = $addon_ext; + $tickets[$ticID]['addons'][$a['id']]['money'] = $this->money($addon_ext); + + // add to total addons for this ticket + $addons_ext += $addon_ext; + + } + } + + // determine what to show for this ticket + $tickets[$ticID]['show_accumulated_total'] = true; + if ($tickets[$ticID]['price_numb'] == 0) { + $tickets[$ticID]['show_price'] = false; + } + + // If we have a ticket quantity, then show the addons + if ($c['quant'] > 0) { + $tickets[$ticID]['show_addons'] = true; + } + + // Add the add-ons price to this ticket extended total + $ext += $addons_ext; + + // Check if add-ons are required for this ticket type + $tickets[$ticID]['required_addon_not_supplied'] = false; + if ($c['quant'] > 0 && $ticketDetail['addon_required']['value'] && $addons_ext == 0) { + $tickets[$ticID]['required_addon_not_supplied'] = true; + $r['reason'][] = $ticketDetail['performance'].' requires selection of at least one associated add-on item!'; + $r['blockCheckout'] = true; + $r['blockCheckoutNonAssignment'] = true; + $tickets[$ticID]['problem'] = true; + $tickets[$ticID]['problemText'] = $ticketDetail['performance'].' requires selection of at least one of the following!'; + } + + } + + // If there's any ticket price > 0 and we have a promo with this ticket and it's within the date range + $promoCredit = 0; + $today = strtotime('today'); + $tomorrow = strtotime('tomorrow'); + if ($ext > 0 && isset($promoTicketsList[$ticID]) && + strtotime($promoTicketsList[$ticID]['promo_start_date']) <= $today && + strtotime($promoTicketsList[$ticID]['promo_end_date']) >= $today + ) { + + // Promo and dates are valid, so credit accordingly + switch($promoTicketsList[$ticID]['promo_type']['value']) { + + // $ amount + case 1: + $credit_each = $promoTicketsList[$ticID]['amount']; + $credit = -1 * $credit_each * $c['quant']; + break; + + // Percentage + case 2: + $credit_each = $ext * ($promoTicketsList[$ticID]['amount']/100); + $credit = -1 * $credit_each * $c['quant']; + break; + } + + // Add to ticket data + $tickets[$ticID]['promo'] = array( + 'promo' => $promoTicketsList[$ticID]['promo'], + 'promo_name' => $promoTicketsList[$ticID]['promo_name'], + 'promo_type' => $promoTicketsList[$ticID]['promo_type']['value'], + 'promo_type_name' => $promoTicketsList[$ticID]['promo_type']['nameEsc'], + 'credit_each' => $credit_each, + 'credit_numb' => $credit, + 'credit' => $this->money($credit) + ); + + // Update extended price for this ticket + $promoCredit += $credit; + + } + + $tickets[$ticID]['extended'] = $this->money($ext); + $tickets[$ticID]['extended_numb'] = $ext; + + // Add to venue totals + $cartData[$membID]['totalTickets'] += $c['quant']; + $cartData[$membID]['totalPrice_numb'] += $ext + $promoCredit; + $cartData[$membID]['totalPrice'] = $this->money($cartData[$membID]['totalPrice_numb']); + + // Add to master totals + $totalTickets += $c['quant']; + $grandTotalPrice += $ext + $promoCredit; + if ($memberDetail['payment_gateway']['value'] != $this->config->ccard_processor_numb->no_payment) { + $totalPrice += $ext + $promoCredit; + + } else { + $totalNoPayment += $ext + $promoCredit; + $cartData[$membID]['no_payment'] = true; + } + + // Calculate max number this session may select - Number not held + quantity this person has selected + $tickets[$ticID]['thisSessionSelectable'] = $invStatus['avail_not_held'] + $c['quant']; + + } else { + $r['reason'][] = 'There has been a cart error: duplicate cart entries!'; + return $r; + } + + // Check if ticket is non-date-specific, and a voucher type < 80 (a ticket kind of thing), and it's sold, then it needs a likely date + if (!$ticketDetail['date_specific']['value'] && $ticketDetail['voucher_type']['value'] < 80 && $c['quant'] > 0) { + + $cartData[$membID]['needLikelyDate'] = true; + + // Also check if a likely date has been submitted + $dateMemb = $cartData[$membID]['assigned_from']; + if (($dateMemb-0) == 0) { + $dateMemb = $membID; + } + if (isset($_SESSION[GLM_EVENT_SESSION]['LikelyDate'][$dateMemb])) { + $cartData[$membID]['likelyDate'] = $_SESSION[GLM_EVENT_SESSION]['LikelyDate'][$dateMemb]; + } + } + + // Check for package data + if ($this->config->option->packages && $ticketDetail['ticket_type']['value'] == 20) { + require_once EVENT_MANAGEMENT_APP_BASE.'classes/data/dataTicketPackages.php'; + $TicketPackages = new EventManagementDataTicketPackages($this->dbh, $this->config); + $packageData = $TicketPackages->getPackageList("package = ".$ticID); + $tickets[$ticID]['packageData'] = $packageData; + } + + + + // We apparently don't have all needed data for this cart entry + // Something has been turned off or deleted + } else { + + // Remove this item from the cart + unset($_SESSION[GLM_EVENT_SESSION]['TicketCart'][$invID]); + $cartItemRemoved = true; + + } + + } // each cart entry + + // Reorganize cart so dates are under events rather than the other way around + // [Member & Assignments], [Performance], [Date], [Section], [Ticket] + $rCart = array(); + + // For each venue + $venueCount = 0; + foreach($cartData as $c) { + + // Assign venue information but not dates array + $rCart[$c['id']] = $c; + unset($rCart[$c['id']]['dates']); + + // For each date + foreach($c['dates'] as $d) { + + // For each performance + foreach($d['performances'] as $p) { + + // If performance not added yet, do that now + if (!isset($rCart[$c['id']]['performances'][$p['id']])) { + + // Assign performance information but not sections + $rCart[$c['id']]['performances'][$p['id']] = $p; + unset($rCart[$c['id']]['performances'][$p['id']]['sections']); + + } + + // If Date not added yet, do that now + if (!isset($rCart[$c['id']]['performances'][$p['id']]['dates'][$d['date']])) { + + // Assign date information but not performance array + $rCart[$c['id']]['performances'][$p['id']]['dates'][$d['date']] = $d; + unset($rCart[$c['id']]['performances'][$p['id']]['dates'][$d['date']]['performances']); + + } + + // For each section + foreach($p['sections'] as $s) { + + // If section not added, do that now + if (!isset($rCart[$c['id']]['performances'][$p['id']]['dates'][$d['date']]['sections'][$s['id']])) { + + // Assign section information but not tickets + $rCart[$c['id']]['performances'][$p['id']]['dates'][$d['date']]['sections'][$s['id']] = $s; + unset($rCart[$c['id']]['performances'][$p['id']]['dates'][$d['date']]['sections'][$s['id']]['tickets']); + + } + + // For each ticket + foreach($s['tickets'] as $t) { + + // Assign the ticket + $rCart[$c['id']]['performances'][$p['id']]['dates'][$d['date']]['sections'][$s['id']]['tickets'][$t['id']] = $t; + + } + + } // For each Section + + // Determine if this performance has multiple sections + if (count($p['sections']) == 1) { + $rCart[$c['id']]['performances'][$p['id']]['oneSectionOnly'] = true; + } else { + $rCart[$c['id']]['performances'][$p['id']]['oneSectionOnly'] = false; + } + + } // For each Performance + }// For each Date + } // For each Venue + + // Determine if there's multiple venues in the cart + if (count($cartData) == 1) { + $r['cartHasOneVenueOnly'] = true; + } else { + $r['cartHasOneVenueOnly'] = false; + } + + /* + * Sort everything the way it should be + */ + + // Sort Members + uasort ($rCart, function ($a, $b) { + if ($a['sort'] == $b['sort']) { + return 0; + } + return ($a['sort'] < $b['sort']) ? -1 : 1; + }); + // For each Member + while (list($k1, $v1) = each($rCart)) { + + // Flag all cart entries as not central payment member, will update that in the checkout process. + $rCart[$k1]['isCentralPaymentMember'] = false; + + // Sort Performances + uasort ($rCart[$k1]['performances'], function ($a, $b) { + if ($a['sort'] == $b['sort']) { + return 0; + } + return ($a['sort'] < $b['sort']) ? -1 : 1; + }); + + // For each Performance + while (list($k2, $v2) = each($rCart[$k1]['performances'])) { + // Sort Dates + // Dates - Not doing this yet + + //For each Date + while (list($k3, $v3) = each($rCart[$k1]['performances'][$k2]['dates'])) { + + // Sort Sections + uasort ($rCart[$k1]['performances'][$k2]['dates'][$k3]['sections'], function ($a, $b) { + if ($a['sort'] == $b['sort']) { + return 0; + } + return ($a['sort'] < $b['sort']) ? -1 : 1; + }); + + // For each Section + while (list($k4, $v4) = each($rCart[$k1]['performances'][$k2]['dates'][$k3]['sections'])) { + + // Sort Tickets + uasort ($rCart[$k1]['performances'][$k2]['dates'][$k3]['sections'][$k4]['tickets'], function ($a, $b) { + if ($a['sort'] == $b['sort']) { + return 0; + } + return ($a['sort'] < $b['sort']) ? -1 : 1; + }); + + } // Sections + } // Dates + } // Performances + } // Members + + } // have cart entries + +// echo "

    ".print_r($rCart,1)."
    "; + + // If we're not doing checkout, then also check to see if we need assignment selection info + if (!$checkout && is_array($rCart) && count($rCart) > 0) { + + // Check for ticket assignment for sale by another member + foreach ($rCart as $c) { + + $rCart[$c['id']]['needAssignment'] = false; + $rCart[$c['id']]['haveAssignment'] = false; + + // Check if a type 3 + if ($c['member_type']['value'] == 3) { + $r['doingAdditionalInfo'] = true; + } + + // Check if type 3 and not assigned + if ($c['member_type']['value'] == 3 && (!isset($c['assignedTo']) || $c['assignedTo'] < 1)) { + + // Assume we're going to fail to assign this - unless we don't have anything selected + if ($rCart[$c['id']]['totalPrice_numb'] > 0) { + $rCart[$c['id']]['needAssignment'] = true; + } + + // Get list of members who this can be assigned to + $assignmentMembers = $this->getMembersList('type2'); + + if ($assignmentMembers) { + + // Check session to see if there's been an assignment + $assignedTo = false; + $assignedToEntrance = false; + if (isset($_SESSION['GLM_EVENT_MGT_FRONT']['Assignment'][$c['id']])) { + $assignedTo = $_SESSION['GLM_EVENT_MGT_FRONT']['Assignment'][$c['id']]; + } + if ($this->config->option->ticket_selection->select_entrance_on_consignment && + isset($_SESSION['GLM_EVENT_MGT_FRONT']['AssignmentEntrance'][$c['id']])) { + $assignedToEntrance = $_SESSION['GLM_EVENT_MGT_FRONT']['AssignmentEntrance'][$c['id']]; + } + + // If an assignment hasn't been made, block checkout + if (!$assignedTo && $c['totalTickets'] > 0) { + $r['blockCheckout'] = true; + } + + // If a likely date is needed and not supplied, block checkout + if ($this->config->option->ask_for_likely_date && $c['needLikelyDate'] && empty($c['likelyDate'])) { + $r['blockCheckout'] = true; + } + + // If a likely date is required, even one is supplied + if ($this->config->option->ask_for_likely_date && $c['needLikelyDate']) { + $r['doingAdditionalInfo'] = true; + } + + // Provide list of assignment members for this entry + $a = array(); + foreach ($assignmentMembers as $m) { + + // Add this member to the list + $a[$m['id']] = array( + 'id' => $m['id'], + 'name' => $m['name'], + 'city' => $m['city'], + 'selected' => false, + 'entrances' => false + ); + + // Check if we should also look at entrances + if ($this->config->option->ticket_selection->select_entrance_on_consignment) { + + // Get a list of entrances for this assignment member + $entrancesList = $this->getEntrancesList($m['id']); + if ($entrancesList) { + foreach($entrancesList as $e) { + + $a[$m['id']]['entrances'][$e['id']] = $e; + $a[$m['id']]['entrances'][$e['id']]['selected'] = false; + + // Determine if this entrance has been selected + if ($m['id'] == $assignedTo && $e['id'] == $assignedToEntrance) { + $a[$m['id']]['entrances'][$e['id']]['selected'] = true; + } + + } + + } + + } + + // If this is the assigned member + if ($m['id'] == $assignedTo) { + + // Mark this member as assigned + $a[$m['id']]['selected'] = true; + $rCart[$c['id']]['haveAssignment'] = true; + + } + } + + // Add list to cart entry + $rCart[$c['id']]['assignmentMembers'] = $a; + + } else { + + // We've had an assignment problem, so fail this process + $r['reason'][] = 'There has been a system problem: There are no members to which we can assign unassigned cart items.'; + $r['status'] = false; + + } + } + + // Check if we need either assignment or likely date + $rCart[$c['id']]['needAssignemntOrDate'] = false; + if ($rCart[$c['id']]['needAssignment'] || ($this->conf->ask_for_likely_date && $rCart[$c['id']]['needLikelyDate'])) { + $rCart[$c['id']]['needAssignemntOrDate'] = true; + } + + } // For each cart entry + } + + // If cart items have been removed - note that + if ($cartItemRemoved) { + $r['reason'][] = 'A '.$this->config->term->ticket->norm.' or '.$this->config->term->ticket->plur + .' have been removed from your cart because they have become unavailable for some reason.
    + We appolgize for the incovenience.'; + } + + // If the cart has a total price, then there must be cart contents +// if ($totalPrice + $totalNoPayment > 0) { + if (count($r['cartData']) > 0) { + $r['cartHasContents'] = true; + } + + if ($totalPrice == 0) { + $r['cartRequiresPayment'] = false; + } + + // Return cart output data and indicate success + $r['cartData'] = $cartData; + $r['cartItemRemoved'] = $cartItemRemoved; + $r['cartDataReorganized'] = $rCart; + $r['totals'] = array( + 'venues' => $totalVenues, + 'tickets' => $totalTickets, + 'price_numb' => $totalPrice, + 'price' => $this->money($totalPrice), + 'grand_total_numb' => $grandTotalPrice, + 'grand_total_price' => $this->money($grandTotalPrice) + ); + + return $r; + + } + + /** + * Get Cart Sticky Inventory + * + * Cart-Sticky tickets are tickets that always show in the cart whether there's + * a selected quantity or 0 quantity. This permits a short 2-step process + * for the shop that includes only Cart and Checkout. It can also be used + * to ask users to select something you want them to buy. + * + * This method will look for active cart-sticky tickets and will return + * a list of inventory items and data useable to insert into a session cart. + * + * Cart-Sticky tickets may not be date-specific at this time. They must have + * only one inventory entry. + * + * @return object containing array as sub-objects + */ + public function getCartStickyInventory() + { + + require_once EVENT_MANAGEMENT_APP_BASE.'classes/data/dataTicketInventory.php'; + $TicketInventory = new EventManagementDataTicketInventory($this->dbh, $this->config); + + // Look only for members that are of type 3, are active, and where the performance is active + $where = " + (SELECT cart_sticky FROM eventmgt.ticket WHERE id = T.ticket) + AND (SELECT active FROM eventmgt.performance WHERE id = (SELECT performance FROM eventmgt.ticket WHERE id = T.ticket)) + "; +//T.member IN (SELECT id FROM eventmgt.member WHERE member_type = 3 AND active) +// AND + + // Get sticky inventory for all matching members (-1) + $inv = $TicketInventory->getTicketInventoryList(-1, $where); + + // Order by ticket order field + uasort ($inv , function ($a, $b) { + if ($a['ticket_sort'] == $b['ticket_sort']) { + return 0; + } + return ($a['ticket_sort'] < $b['ticket_sort']) ? -1 : 1; + } + ); + + return $inv; + } + + /** + * Get performances set for promotion on cart page + * + * Returns an array of performances that are set to be promoted on the cart page. + * + * @return object containing array as sub-objects + */ + public function getCartPromotions() + { + + require_once EVENT_MANAGEMENT_APP_BASE.'classes/data/dataPerformances.php'; + $Performances = new EventManagementDataPerformances($this->dbh, $this->config); + $Performances->optionIncludeSelectListData = false; + $performancesList = $Performances->getPerformancesList('cart_promotions'); + return $performancesList; + + } + +} + +?> diff --git a/models/vouchers/Gaslight/voucher.php b/models/vouchers/Gaslight/voucher.php new file mode 100644 index 0000000..1f7184c --- /dev/null +++ b/models/vouchers/Gaslight/voucher.php @@ -0,0 +1,614 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: printVoucher.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +require_once PDF_ABSTRACT; +$Pdf = new GlmPdf(); + +/** + * PdfVoucher class + * + * @category PdfVoucher + * @package PDFLib + * @author Chuck Scott + * @license http://www.gaslightmedia.com Gaslightmedia + * @link <> +*/ +class PdfVoucher extends GlmPdf +{ + + public $borderWidth = 1; + public $borderColor = 'black'; + public $pdfCouponInterval = 5; + public $pdfMinCoupons = 3; + public $config; + public $companyContact = false; + public $venueContact = false; + + function __construct($order, $vouchers, $member, $dbh, $config) + { + + $this->config = $config; + + // if debug.glmpdf is set in the configs/common.ini file in the CommonApp directory, do grids on PDFs + define ('GLMPDF_DEBUG', $this->config->debug->glmpdf); + + // The following produces a color test sheet. There is no return from that call. + // $this->glmpdfShowValidColors(); + + // Start with cover page. + $this->glmpdfSetForms( + 1, + array( + 1 => array( 'x' => 0, 'y' => 0, 'xs' => 613, 'ys' => 792 ) + ), + 'US Letter' + ); + + // Start page + $this->glmpdfStart( $this->config->owner->name, "Gaslight Media", "Ticket System Receipt/Vouchers" ); + + if( !$this->glmpdfAddFont( 'barcode', 'barcode/FREE3OF9.TTF' ) ) + { + echo 'ERROR: Unable to add barcode font.

    + Did you place the barcode font provided in docs/BarcodeFonts into + a system fonts directory ("/usr/share/fonts/truetype/Barcode")? + Also check the GLMPDF_PDF_FONT_DIR setting in GlmPdf.php.'; + exit; + } + + // If coupon test is selected, print them all now. +// if( isset($_REQUEST['test_coupons']) ) +// { +// for( $i=1 ; $i<=count($coupons) ; $i++ ) +// $this->printCoupon( $i ); +// +// glmpdf_send_to_browser( '', 'voucher.pdf' ); +// exit; +// } + + // Get images to tmp files + require_once IMAGE_SERVER_ABSTRACT; + $imServer = new ImageServerAbstract(); + + if (trim($member['image']) != '') { + $venueImageFile = $imServer->saveImageToTemp(IMAGE_SERVER_PREFIX.'original/'.$member['image']); + if ($venueImageFile) { + $venueImage = $this->glmpdfOpenImage($venueImageFile); + + // If failure getting the image + if ($venueImage == false) { + $venueImageFile = false; + } + } + } else { + $venueImageFile = false; + } + + if (trim($member['parking_map']) != '') { + $parkingImageFile = $imServer->saveImageToTemp(IMAGE_SERVER_PREFIX.'original/'.$member['parking_map']); + if ($parkingImageFile) { + $parkingImage = $this->glmpdfOpenImage($parkingImageFile); + + // If failure getting the image + if ($parkingImage == false) { + $parkingImageFile = false; + } + } + } else { + $parkingImageFile = false; + } + + if (trim($member['ticket_sec_map']) != '') { + $sectionImageFile = $imServer->saveImageToTemp(IMAGE_SERVER_PREFIX.'original/'.$member['ticket_sec_map']); + if ($sectionImageFile) { + $sectionImage = $this->glmpdfOpenImage($sectionImageFile); + + // If failure getting the image + if ($sectionImage == false) { + $sectionImageFile = false; + } + } + } else { + $sectionImageFile = false; + } + + // Load entrance class + require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/entrances.php'; + $Entrances = new EventManagementAdminEntrances($dbh, $config); + + // Load performance class + require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/performances.php'; + $Performances = new EventManagementAdminPerformances($dbh, $config); + + // Setup additional information + // Company contact info + if ($config->option->voucher->show_company_contact) { + $companyContact = ''; + $sep = ''; + if ($config->option->voucher->show_company_name) { + $companyContact .= $config->owner->name; + $sep = ' - '; + } + if ($config->option->voucher->show_company_addr && $config->owner->addr1) { + $companyContact .= $sep.$config->owner->addr1; + $sep = ' - '; + if ($config->owner->addr2) { + $companyContact .= ', '.$config->owner->addr2; + } + } + if ($config->option->voucher->show_company_citystate) { + $companyContact .= $sep.$config->owner->city.', '.$config->owner->state; + $sep = ' - '; + } + if ($config->option->voucher->show_company_phone) { + if ($config->owner->toll_free) { + $companyContact .= $sep.$config->owner->toll_free; + } else { + $companyContact .= $sep.$config->owner->phone; + } + } + } + // Venue/Location contact info + $venueContact = false; + if ($config->option->voucher->show_venue_contact) { + $venueContact = ''; + $sep = ''; + if ($config->option->voucher->show_venue_name) { + $venueContact .= $member['name']; + $sep = ' - '; + } + if ($config->option->voucher->show_venue_addr && $member['addr1']) { + $venueContact .= $sep.$member['addr1']; + $sep = ' - '; + if ($member['addr2']) { + $venueContact .= ', '.$member['addr2']; + } + } + if ($config->option->voucher->show_venue_citystate) { + $venueContact .= $sep.$member['city'].', '.$member['state']['name']; + $sep = ' - '; + } + if ($config->option->voucher->show_venue_phone) { + $venueContact .= $sep.$member['phone']; + } + } + + // START VOUCHER PRINTOUT + + $this->glmpdfNextForm(); + + /* Cover Page */ + + // Header + if ($venueImageFile) { + $coverImage = $this->glmpdfOpenImage($venueImageFile); + $this->glmpdfPlaceImage($coverImage, 30, 690, .5, false, 'center', 280, 140); + } + $this->glmpdfSetFont( "Helvetica-Bold", 18.0 ); // Header Text + $this->glmpdfPlaceText( $config->owner->name, 340, 750, "center", 'black', -400 ); + $this->glmpdfSetFont( "Helvetica", 14.0 ); + $this->glmpdfPlaceText( $config->owner->short_name." - ".$member['name'], 340, $this->glmpdfCurrentY-10, "center", 'black', -400 ); + $this->glmpdfPlaceText( $member['addr1'], 340, $this->glmpdfCurrentY, "center", 'black', -400 ); + $this->glmpdfPlaceText( $member['city'].", ".$member['state']['name']." ".$member['zip'], 340, $this->glmpdfCurrentY, "center", 'black', -400 ); + + // Sold To Information + $valCol = 60; + $this->glmpdfSetFont( "Helvetica", 10.0 ); + $this->glmpdfPlaceText( $this->config->term->order->cap." ID: ".trim($order['id']), $valCol, 650, "left", 'black' ); + $this->glmpdfPlaceText( trim($order['fname'].' '.$order['lname']), $valCol, $this->glmpdfCurrentY-5, "left", 'black', -200 ); + $this->glmpdfPlaceText( trim($order['addr1']), $valCol, $this->glmpdfCurrentY-5, "left", 'black', -200 ); + if( trim($order['addr2']) != '' ) + $this->glmpdfPlaceText( trim($order['addr2']), $valCol, $this->glmpdfCurrentY-5, "left", 'black', -200 ); + $this->glmpdfPlaceText( trim($order['city']).', '.$order['state']['value'].' '.trim($order['zip']).' '.$order['country']['value'], $valCol, $this->glmpdfCurrentY-5, "left", 'black', -200 ); + + // Purchace/Charge information + $this->glmpdfSetFont( "Helvetica", 10.0 ); + $promptCol = 330; + $valCol = 420; + $this->glmpdfPlaceText( "Date of Purchase:", $promptCol, 650, "left", 'black' ); + $this->glmpdfPlaceText( $order['purchase_date']['date'], $valCol, $this->glmpdfLastY, "left", 'black', -160 ); + $this->glmpdfPlaceText( "Card Type:", $promptCol, $this->glmpdfCurrentY-5, "left", 'black' ); + $this->glmpdfPlaceText( $order['cctype'], $valCol, $this->glmpdfLastY, "left", 'black', -160 ); + $this->glmpdfPlaceText( "Name on Card:", $promptCol, $this->glmpdfCurrentY-5, "left", 'black' ); + $this->glmpdfPlaceText( $order['ccname'], $valCol, $this->glmpdfLastY, "left", 'black', -160 ); + $this->glmpdfPlaceText( "Card Number:", $promptCol, $this->glmpdfCurrentY-5, "left", 'black' ); + $this->glmpdfPlaceText( $order['ccnumber'], $valCol, $this->glmpdfLastY, "left", 'black', -160 ); + $this->glmpdfPlaceText( "Confirmation:", $promptCol, $this->glmpdfCurrentY-5, "left", 'black' ); + $this->glmpdfPlaceText( $order['ccconf'], $valCol, $this->glmpdfLastY, "left", 'black', -160 ); + $this->glmpdfPlaceText( "Total Charged:", $promptCol, $this->glmpdfCurrentY-5, "left", 'black' ); + $this->glmpdfPlaceText( $order['charge_total'], $valCol, $this->glmpdfLastY, "left", 'black', -160 ); + + // Purchase Summary + $ticNumbCol = 20; + $perfNameCol = 80; + $ticNameCol = 200; + $secNameCol = 370; + $dateCol = 440; + $this->glmpdfPlaceText( '', $ticNumbCol, 550, "center", 'black', 0, ''); + + $this->glmpdfSetFont( "Helvetica", 8.0 ); + $this->glmpdfPlaceText( $this->config->term->voucher->cap, $ticNumbCol, $this->glmpdfCurrentY, "left", 'black', -52, ''); + $this->glmpdfPlaceText( $this->config->term->performance->cap, $perfNameCol, $this->glmpdfLastY, "left", 'black', -110, ''); + $this->glmpdfPlaceText( $this->config->term->ticket->cap, $ticNameCol, $this->glmpdfLastY, "left", 'black', -160, ''); + $this->glmpdfPlaceText( $this->config->term->section->cap, $secNameCol, $this->glmpdfLastY, "left", 'black', -60, ''); + $this->glmpdfPlaceText( 'Date / Time', $dateCol, $this->glmpdfLastY, "left", 'black', -160, ''); + + $this->glmpdfPlaceText( '', $ticNumbCol, $this->glmpdfCurrentY-3, "center", 'black', 0, ''); + + foreach( $vouchers as $t ) { + + $voucherCode = $this->addCheckCode($t['id']); + + $this->glmpdfSetFont( "Helvetica", 8.0 ); + $this->glmpdfPlaceText( $voucherCode, $ticNumbCol, $this->glmpdfCurrentY, "left", 'black', -52, ''); + $this->glmpdfPlaceText( html_entity_decode($t['performance_name'],ENT_QUOTES,"utf-8"), $perfNameCol, $this->glmpdfLastY, "left", 'black', -110, ''); + $this->glmpdfPlaceText( html_entity_decode($t['ticket_name'],ENT_QUOTES,"utf-8"), $ticNameCol, $this->glmpdfLastY, "left", 'black', -160, ''); + $this->glmpdfPlaceText( html_entity_decode($t['section_name'],ENT_QUOTES,"utf-8"), $secNameCol, $this->glmpdfLastY, "left", 'black', -60, ''); + if ($t['date_specific']['value']) { + $this->glmpdfPlaceText( $t['ticket_date']['date'].' '.$t['ticket_time']['time'], $dateCol, $this->glmpdfLastY, "left", 'black', -160, ''); + } else { + $dateRange = 'Valid From '.$t['start_date']['date'].' through '.$t['end_date']['date']; + $this->glmpdfPlaceText( $dateRange, $dateCol, $this->glmpdfLastY, "left", 'black', -160, ''); + } + + // Check for Ticket add-ons + if (isset($t['addons_sold']) && count($t['addons_sold']) > 0) { + foreach($t['addons_sold'] as $a) { + + $addonText = $a['add_on_name']; + if (($a['add_on_type']['value']-0) == 2) { + $addonText = $addonText.', '.$a['quant'].' '.$a['unit_name']; + } + $this->glmpdfPlaceText( html_entity_decode($addonText,ENT_QUOTES,"utf-8"), $ticNameCol+10, $this->glmpdfCurrentY, "left", 'black', -240, ''); + } + } + + } + + // Special Needs + $this->glmpdfSetFont( "Helvetica", 9.0 ); + if (trim($order['special_needs']) != '') { + $this->glmpdfPlaceText( "Special Needs:", 20, $this->glmpdfCurrentY-30, "left", 'black' ); + $this->glmpdfPlaceTextBox( $order['special_needs'], 100, $this->glmpdfCurrentY+16, 450, 50, "left", 'black' ); + } + + // General Member Policies + if (trim($member['def_ticket_pol']) != '') { + $this->glmpdfPlaceText( "Policies:", 20, $this->glmpdfCurrentY-30, "left", 'black' ); + $this->glmpdfPlaceTextBox( $member['def_ticket_pol'], 100, $this->glmpdfCurrentY+16, 450, 50, "left", 'black' ); + } + + // Now setup ticket forms + $this->glmpdfSetForms( + 1, + array( + 1 => array( 'x' => 25, 'y' => 495, 'xs' => 560, 'ys' => 275 ) +// 2 => array( 'x' => 25, 'y' => 210, 'xs' => 560, 'ys' => 275 ) + ), + 'US Letter' + ); + // Also reset form count + $this->glmpdfNextPage(); + + // Display Footer + $this->glmpdfSetFont( "Helvetica-Bold", 8.5 ); + $this->glmpdfPlaceText( $footer, 140.5, 2, "center", 'darkblue' ); +/*********CPS + // Display Parking Map + if ($parkingImage) { + $this->glmpdfNextForm(); + $this->glmpdfPlaceImage( $parkingImage, 0, 2, 0, 'meet', 'center', 280, 125); + $this->glmpdfSetFont( "Helvetica-Bold", 10.0 ); + $this->glmpdfPlaceText( 'Parking Map', 140, 130, "center", 'black' ); + } + + // Display Section Map + if ($sectionImage) { + $this->glmpdfNextForm(); + $this->glmpdfPlaceImage( $sectionImage, 0, 2, 0, 'meet', 'center', 280, 125); + $this->glmpdfSetFont( "Helvetica-Bold", 10.0 ); + $this->glmpdfPlaceText( 'Section Map', 140, 130, "center", 'black' ); + } +*/ + + // Load mask for darkening the bottom portion of the tickets +// $ticketMask = $this->glmpdfOpenImage(EVENT_MANAGEMENT_APP_BASE.'web/custom/greatlakesbaymag/assets/ticket-gradient.png'); + + // Clear performance image loaded flag + $performanceLoaded = false; + + // Process Vouchers - For each type of ticket purchased + $numb_tickets = 0; + foreach( $vouchers as $t ) + { + + if ($numb_tickets++ > 0) { + $this->glmpdfNextForm(); + } + $this->glmpdfPlaceBox( $this->borderWidth, 0, 275, 560, 275, $this->borderColor ); + + // Display Logo - Only get performance image if it's not currently loaded + if ($performanceLoaded != $t['performance']) { + + $performanceDetail = $Performances->getPerformanceDetail($t['performance']); + + // If we have an image but it's the wrong one, dump the temp file + if ($performanceImageFile) { + unlink($performanceImageFile); + } + + // This performance image is not currently loaded - so do that now + + $performanceImageFile = $imServer->saveImageToTemp(IMAGE_SERVER_PREFIX.'original/'.$performanceDetail['image']); + if ($performanceImageFile) { + // If we have the image, then load it + $performanceImage = $this->glmpdfOpenImage($performanceImageFile); + $performanceLoaded = $t['performance']; + } else { + + // otherwise, try the venue image + $performanceLoaded = $venueImage; + } + + } + + // If we have the performance image, display it + $haveTopImage = false; + if ($performanceImage) { + $this->glmpdfPlaceImage( $performanceImage, 85, 195, 1, 'meet', 'center', 70, 75); + $haveTopImage = true; + } elseif ($venueImageFile) { + $this->glmpdfPlaceImage($coverImage, 85, 195, 1, 'meet', 'center', 70, 75); + $haveTopImage = true; + } + + // Place owner name at top possitioned by whether or not there's an image supplied + $this->glmpdfSetFont( "Helvetica-Bold", 24.0 ); + if ($haveTopImage) { + +// $this->glmpdfPlaceText( $config->owner->name, 315, 227, "center", 'black', -300, ''); + $this->glmpdfPlaceText( html_entity_decode($t['member_name'],ENT_QUOTES,"utf-8"), 315, 227, "center", 'black', -300, ''); + } else { +// $this->glmpdfPlaceText( $config->owner->name, 280, 227, "center", 'black', -350, ''); + $this->glmpdfPlaceText( html_entity_decode($t['member_name'],ENT_QUOTES,"utf-8"), 280, 227, "center", 'black', -350, ''); + } + + // Place mask + //$this->glmpdfPlaceImage($ticketMask, 0, 52, .25, false, 'center', 280, 140); + + // If ticket has already been claimed, then mark ticket + if ($t['time_claimed']['date'] != '') { + $this->glmpdfSetFont( "Times-Bold", 72.0 ); + $this->glmpdfPlaceText( "CLAIMED", 110, 80, "left", 'orangered', 0, '' ); // last parameter can be things like "rotate=90" + } + + // Ticket Information Area + $this->glmpdfSetFont( "Helvetica-Bold", 24.0 ); + $this->glmpdfPlaceLine(1, 80, 0, 80, 275, $color = "black", $dash = false, $d_a = 1, $d_b = 1); + $this->glmpdfPlaceLine(1, 480, 0, 480, 275, $color = "black", $dash = false, $d_a = 1, $d_b = 1); + + // Left End of Ticket - NOTE: use only "left" in glmpdfPlaceText - use "position=..." in optlist instead. + if (($t['entrance']-0) > 0) { + $entranceDetail = $Entrances->getEntranceDetail($t['entrance']); + $this->glmpdfPlaceBox(1, 0, 0, 80, -275, '', $entranceDetail['color']['name'], 'miter'); + } + $this->glmpdfSetFont( "Helvetica-Bold", 10.0 ); +// $this->glmpdfPlaceText( 'Departing from:', 7, 40, 'left', 'black', 0, 'position=center rotate=90'); + $this->glmpdfSetFont( "Helvetica-Bold", 20.0 ); + $this->glmpdfPlaceText( strtoupper(html_entity_decode($t['entrance_name'],ENT_QUOTES,"utf-8")), 40, 138, 'left', 'black', -250, 'position=center rotate=90'); +// $this->glmpdfPlaceText( strtoupper(html_entity_decode($t['member_name'],ENT_QUOTES,"utf-8")), 60, 138, 'left', 'black', -250, 'position=center rotate=90'); + + // Display values + $this->glmpdfSetFont( "Helvetica-Bold", 26.0 ); + $this->glmpdfPlaceText( html_entity_decode($t['performance_name'],ENT_QUOTES,"utf-8"), 280, 170, "center", 'black', -370, ''); + $this->glmpdfSetFont( "Helvetica-Bold", 24.0 ); + $this->glmpdfPlaceText( html_entity_decode($t['ticket_name'],ENT_QUOTES,"utf-8"), 280, 140, "center", 'black', -370, '' ); + $this->glmpdfSetFont( "Helvetica-Bold", 20.0 ); +// $this->glmpdfPlaceText( html_entity_decode($t['section_name'],ENT_QUOTES,"utf-8"), 280, 130, "center", 'black', -370, '' ); + $this->glmpdfSetFont( "Helvetica", 18.0 ); + if ($t['date_specific']['value']) { + $thisTime = ''; + if ($t['time_specific']['value']) { + $thisTime = ' - '.$t['ticket_time']['time']; + } + $this->glmpdfPlaceText( $t['ticket_date']['date'].$thisTime, 280, 110, "center", 'black', -370, '' ); + } else { + $dateRange = 'Valid From '.$t['start_date']['date'].' through '.$t['end_date']['date']; + $this->glmpdfPlaceText( $dateRange, 280, 110, "center", 'black', -370, '' ); + } + + $this->glmpdfSetFont( "Helvetica", 16.0 ); + + // Check for Ticket add-ons + if (isset($t['addons_sold']) && count($t['addons_sold']) > 0) { + $this->glmpdfSetFont( "Helvetica", 14.0 ); + foreach($t['addons_sold'] as $a) { + $addonText = $a['add_on_name']; + if (($a['add_on_type']['value']-0) == 2) { + $addonText = $addonText.', '.$a['quant'].' '.$a['unit_name']; + } + $this->glmpdfPlaceText( $addonText, 280, $this->glmpdfCurrentY, "center", 'black', -370, '' ); + } + } + + // Display NON-REFUNDABLE MESSAGE + $this->glmpdfSetFont( "Helvetica", 14.0 ); + $this->glmpdfPlaceText( "NON-REFUNDABLE", 280, $this->glmpdfCurrentY, "center", 'black', -300, ''); + + // Display address and contact information + if ($venueContact) { + $this->glmpdfSetFont( "Helvetica", 10.0 ); + $this->glmpdfPlaceText( html_entity_decode($this->config->term->prop->cap.' contact information',ENT_QUOTES,"utf-8"), 280, $this->glmpdfCurrentY-5, "center", 'black', -300, ''); + $this->glmpdfPlaceText( html_entity_decode($venueContact,ENT_QUOTES,"utf-8"), 280, $this->glmpdfCurrentY, "center", 'black', -300, ''); + } + + // Display address and contact information + if ($companyContact) { + $this->glmpdfSetFont( "Helvetica", 10.0 ); + $this->glmpdfPlaceText( html_entity_decode($companyContact,ENT_QUOTES,"utf-8"), 280, 25, "center", 'black', -380, ''); + } + + // Display additional voucher text at the bottom of the voucher if provided + $voucherText = ''; + if (trim($t['ticket_voucher_text']) != '') { + $voucherText = trim(html_entity_decode($t['ticket_voucher_text'],ENT_QUOTES,"utf-8")); + } elseif (trim($performanceDetail['voucher_text']) != '') { + $voucherText = trim(html_entity_decode($performanceDetail['voucher_text'],ENT_QUOTES,"utf-8")); + } + if ($voucherText != '') { + $this->glmpdfPlaceLine(1, 80, 20, 480, 20, 'black', false); + $this->glmpdfSetFont( "Helvetica-Bold", 14.0 ); +// $this->glmpdfPlaceBox(1, 80, 20, 400, 20, "black", "black"); + $this->glmpdfPlaceText( html_entity_decode($voucherText,ENT_QUOTES,"utf-8"), 280, 6, "center", 'black', -370, '' ); + } + + // $this->glmpdfPlaceText( $t['ticket_date']['date'].' - '.$t['ticket_time']['time'], 120, $this->glmpdfCurrentY, "left", 'black', 0, '' ); + + // Print barcode = {ticket_sold ID}-{person type}-{person_sequence} + $barcode = $this->addCheckCode($t['id']); + // If we're supposed to print barcode and voucher number on ticket + switch ($t['ticket_voucher_type']) { + + case 11: // Voucher/Ticket for Pickup - no Barcode + $this->glmpdfSetFont( "Helvetica-Bold", 20.0 ); + $this->glmpdfPlaceText( "Pickup at ".$this->config->term->prop->norm, 510, 140, 'left', 'black', -260, 'position=center rotate=90'); + $this->glmpdfSetFont( "Courier", 12.0 ); + $this->glmpdfPlaceText( $this->config->term->voucher->cap." $barcode", 540, 140, 'left', 'black', -260, 'position=center rotate=90'); + break; + + case 12; // Voucher/Ticket to be mailed Mailed - no Barcode + case 82; // Object Sold (i.e. books) to be mailed - no Barcode + $this->glmpdfSetFont( "Helvetica-Bold", 20.0 ); + $this->glmpdfPlaceText( "You will receive this by mail", 510, 140, 'left', 'black', -260, 'position=center rotate=90'); + $this->glmpdfSetFont( "Courier", 12.0 ); + $this->glmpdfPlaceText( $this->config->term->voucher->cap." $barcode", 540, 140, 'left', 'black', -260, 'position=center rotate=90'); + break; + + case 1: // Standard Voucher/Ticket with Barcode + case 81; // Object Sold (i.e. books) to be claimed - with Barcode + default: + $this->glmpdfSetFont( 'barcode', 54 ); + $this->glmpdfPlaceText( "*$barcode*", 510, 140, 'left', 'black', 0, 'position=center rotate=90'); + $this->glmpdfSetFont( "Courier", 12.0 ); + $this->glmpdfPlaceText( $this->config->term->voucher->cap." $barcode", 540, 140, 'left', 'black', -260, 'position=center rotate=90'); + break; + + } + + $this->glmpdfPlaceText( "Order #".$order['id'], 552, 140, 'left', 'black', 0, 'position=center rotate=90'); + + // Check if we need to display a coupon +// if( ++$numb_tickets % $this->pdfCouponInterval == 0 ) +// $this->printCoupon(); + + } // Each voucher + + // Make sure we print the minimum number of coupons +// $numb_coupons = 0; +// while( $numb_coupons < $this->pdfMinCoupons ) { +// $this->printCoupon(); +// $numb_coupons++; +// } + + // Close PDF setup and send to user's browser + $this->glmpdfSendToBrowser( '', 'voucher.pdf' ); + + if ($venueImageFile) { + unlink($venueImageFile); + } + if ($parkingImageFile) { + unlink($parkingImageFile); + } + if ($sectionImageFile) { + unlink($sectionImageFile); + } + if ($sectionImageFile) { + unlink($sectionImageFile); + } + + } + + + // function to print a coupon + function printCoupon() + { + // Print a Coupon + $this->glmpdfNextForm(); + $this->glmpdfPlaceBox( $this->borderWidth, 0, 142, 281, 142, $this->borderColor ); + + // Place Coupon Image + $this->glmpdfSetFont( "Helvetica-Bold", 10.0 ); + $this->glmpdfPlaceText( 'Coupon Title', 85, 130, "center", 'black' ); + $this->glmpdfPlaceText( 'Expires on: 1/1/2020', 85, 75 ); + $this->glmpdfSetFont( "Times-Bold", 30.0 ); + $this->glmpdfPlaceText( "COUPON", 85, 95, "center", 'lightgrey' ); + $this->glmpdfSetFont( "Helvetica", 8.0 ); + $this->glmpdfPlaceTextBox( 'This is a coupon description. It describes this coupon.', 5, 55, 274, 40, "left", 'black' ); + $this->glmpdfSetFont( "Helvetica-Bold", 8.5 ); + $this->glmpdfPlaceText( "Mackinaw Area Visitors Bureau - Mackinaw City, MI - 800-666-0160", 140.5, 2, "center", 'darkblue' ); + + } + + /* + * Function to add check character to end of voucher number + * + * Uses config->voucher_check_secret and voucher # to create MD5 string + * then takes last hex character off of that string and shifts it up to + * always be a character (adds 16 to numbers and 10 to the upper-case + * version of the character). + * i.e. 0 = A, 9 = J, A = K, F = + * + */ + public function addCheckCode($voucherNumb) + { + + // Create MD5 string using voucher number and secret + $md5 = md5($voucherNumb.$this->config->voucher_check_secret); + + // Get last character code of the last character in the MD5 + $cc = strtoupper(substr($md5, -2)); + $cc[0] = $this->shiftCheckCodeCharacter($cc[0]); + $cc[1] = $this->shiftCheckCodeCharacter($cc[1]); + + // Return voucher number with the new character on the end + $voucherNumb .= $cc; + return $voucherNumb; + + } + + private function shiftCheckCodeCharacter($c) { + + $x = ord($c); + + // If it's a digit, add 16 + if ($x < 65) { + $x += 17; + // otherwise, add 10 + } else { + $x += 10; + } + + // Also skip the letter O + if (x >= ord('O')) { + $x += 1; + } + + return chr($x); + } + +} // class + +// Absolutely nothing after next line +?> \ No newline at end of file diff --git a/models/vouchers/Generic/voucher.php b/models/vouchers/Generic/voucher.php new file mode 100644 index 0000000..6f06214 --- /dev/null +++ b/models/vouchers/Generic/voucher.php @@ -0,0 +1,607 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: printVoucher.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +require_once PDF_ABSTRACT; +$Pdf = new GlmPdf(); + +/** + * PdfVoucher class + * + * @category PdfVoucher + * @package PDFLib + * @author Chuck Scott + * @license http://www.gaslightmedia.com Gaslightmedia + * @link <> +*/ +class PdfVoucher extends GlmPdf +{ + + public $borderWidth = 1; + public $borderColor = 'black'; + public $pdfCouponInterval = 5; + public $pdfMinCoupons = 3; + public $config; + public $companyContact = false; + public $venueContact = false; + + function __construct($order, $vouchers, $member, $dbh, $config) + { + + $this->config = $config; + + // if debug.glmpdf is set in the configs/common.ini file in the CommonApp directory, do grids on PDFs + define ('GLMPDF_DEBUG', $this->config->debug->glmpdf); + + // The following produces a color test sheet. There is no return from that call. + // $this->glmpdfShowValidColors(); + + // Start with cover page. + $this->glmpdfSetForms( + 1, + array( + 1 => array( 'x' => 0, 'y' => 0, 'xs' => 613, 'ys' => 792 ) + ), + 'US Letter' + ); + + // Start page + $this->glmpdfStart( $this->config->owner->name, "Gaslight Media", "Ticket System Receipt/Vouchers" ); + + if( !$this->glmpdfAddFont( 'barcode', 'barcode/FREE3OF9.TTF' ) ) + { + echo 'ERROR: Unable to add barcode font.

    + Did you place the barcode font provided in docs/BarcodeFonts into + a system fonts directory ("/usr/share/fonts/truetype/Barcode")? + Also check the GLMPDF_PDF_FONT_DIR setting in GlmPdf.php.'; + exit; + } + + // If coupon test is selected, print them all now. +// if( isset($_REQUEST['test_coupons']) ) +// { +// for( $i=1 ; $i<=count($coupons) ; $i++ ) +// $this->printCoupon( $i ); +// +// glmpdf_send_to_browser( '', 'voucher.pdf' ); +// exit; +// } + + // Get images to tmp files + require_once IMAGE_SERVER_ABSTRACT; + $imServer = new ImageServerAbstract(); + + if (trim($member['image']) != '') { + $venueImageFile = $imServer->saveImageToTemp(IMAGE_SERVER_PREFIX.'original/'.$member['image']); + if ($venueImageFile) { + $venueImage = $this->glmpdfOpenImage($venueImageFile); + + // If failure getting the image + if ($venueImage == false) { + $venueImageFile = false; + } + } + } else { + $venueImageFile = false; + } + + if (trim($member['parking_map']) != '') { + $parkingImageFile = $imServer->saveImageToTemp(IMAGE_SERVER_PREFIX.'original/'.$member['parking_map']); + if ($parkingImageFile) { + $parkingImage = $this->glmpdfOpenImage($parkingImageFile); + + // If failure getting the image + if ($parkingImage == false) { + $parkingImageFile = false; + } + } + } else { + $parkingImageFile = false; + } + + if (trim($member['ticket_sec_map']) != '') { + $sectionImageFile = $imServer->saveImageToTemp(IMAGE_SERVER_PREFIX.'original/'.$member['ticket_sec_map']); + if ($sectionImageFile) { + $sectionImage = $this->glmpdfOpenImage($sectionImageFile); + + // If failure getting the image + if ($sectionImage == false) { + $sectionImageFile = false; + } + } + } else { + $sectionImageFile = false; + } + + // Load entrance class + require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/entrances.php'; + $Entrances = new EventManagementAdminEntrances($dbh, $config); + + // Load performance class + require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/performances.php'; + $Performances = new EventManagementAdminPerformances($dbh, $config); + + // Setup additional information + // Company contact info + if ($config->option->voucher->show_company_contact) { + $companyContact = ''; + $sep = ''; + if ($config->option->voucher->show_company_name) { + $companyContact .= $config->owner->name; + $sep = ' - '; + } + if ($config->option->voucher->show_company_addr && $config->owner->addr1) { + $companyContact .= $sep.$config->owner->addr1; + $sep = ' - '; + if ($config->owner->addr2) { + $companyContact .= ', '.$config->owner->addr2; + } + } + if ($config->option->voucher->show_company_citystate) { + $companyContact .= $sep.$config->owner->city.', '.$config->owner->state; + $sep = ' - '; + } + if ($config->option->voucher->show_company_phone) { + if ($config->owner->toll_free) { + $companyContact .= $sep.$config->owner->toll_free; + } else { + $companyContact .= $sep.$config->owner->phone; + } + } + } + // Venue/Location contact info + $venueContact = false; + if ($config->option->voucher->show_venue_contact) { + $venueContact = ''; + $sep = ''; + if ($config->option->voucher->show_venue_name) { + $venueContact .= $member['name']; + $sep = ' - '; + } + if ($config->option->voucher->show_venue_addr && $member['addr1']) { + $venueContact .= $sep.$member['addr1']; + $sep = ' - '; + if ($member['addr2']) { + $venueContact .= ', '.$member['addr2']; + } + } + if ($config->option->voucher->show_venue_citystate) { + $venueContact .= $sep.$member['city'].', '.$member['state']['name']; + $sep = ' - '; + } + if ($config->option->voucher->show_venue_phone) { + $venueContact .= $sep.$member['phone']; + } + } + + // START VOUCHER PRINTOUT + + $this->glmpdfNextForm(); + + /* Cover Page */ + + // Header + if ($venueImageFile) { + $coverImage = $this->glmpdfOpenImage($venueImageFile); + $this->glmpdfPlaceImage($coverImage, 30, 690, .5, false, 'center', 280, 140); + } + $this->glmpdfSetFont( "Helvetica-Bold", 18.0 ); // Header Text + $this->glmpdfPlaceText( $config->owner->name, 340, 750, "center", 'black', -400 ); + $this->glmpdfSetFont( "Helvetica", 14.0 ); + $this->glmpdfPlaceText( $config->owner->short_name." - ".$member['name'], 340, $this->glmpdfCurrentY-10, "center", 'black', -400 ); + $this->glmpdfPlaceText( $member['addr1'], 340, $this->glmpdfCurrentY, "center", 'black', -400 ); + $this->glmpdfPlaceText( $member['city'].", ".$member['state']['name']." ".$member['zip'], 340, $this->glmpdfCurrentY, "center", 'black', -400 ); + + // Sold To Information + $valCol = 60; + $this->glmpdfSetFont( "Helvetica", 10.0 ); + $this->glmpdfPlaceText( $this->config->term->order->cap." ID: ".trim($order['id']), $valCol, 650, "left", 'black' ); + $this->glmpdfPlaceText( trim($order['fname'].' '.$order['lname']), $valCol, $this->glmpdfCurrentY-5, "left", 'black', -200 ); + $this->glmpdfPlaceText( trim($order['addr1']), $valCol, $this->glmpdfCurrentY-5, "left", 'black', -200 ); + if( trim($order['addr2']) != '' ) + $this->glmpdfPlaceText( trim($order['addr2']), $valCol, $this->glmpdfCurrentY-5, "left", 'black', -200 ); + $this->glmpdfPlaceText( trim($order['city']).', '.$order['state']['value'].' '.trim($order['zip']).' '.$order['country']['value'], $valCol, $this->glmpdfCurrentY-5, "left", 'black', -200 ); + + // Purchace/Charge information + $this->glmpdfSetFont( "Helvetica", 10.0 ); + $promptCol = 330; + $valCol = 420; + $this->glmpdfPlaceText( "Date of Purchase:", $promptCol, 650, "left", 'black' ); + $this->glmpdfPlaceText( $order['purchase_date']['date'], $valCol, $this->glmpdfLastY, "left", 'black', -160 ); + $this->glmpdfPlaceText( "Card Type:", $promptCol, $this->glmpdfCurrentY-5, "left", 'black' ); + $this->glmpdfPlaceText( $order['cctype'], $valCol, $this->glmpdfLastY, "left", 'black', -160 ); + $this->glmpdfPlaceText( "Name on Card:", $promptCol, $this->glmpdfCurrentY-5, "left", 'black' ); + $this->glmpdfPlaceText( $order['ccname'], $valCol, $this->glmpdfLastY, "left", 'black', -160 ); + $this->glmpdfPlaceText( "Card Number:", $promptCol, $this->glmpdfCurrentY-5, "left", 'black' ); + $this->glmpdfPlaceText( $order['ccnumber'], $valCol, $this->glmpdfLastY, "left", 'black', -160 ); + $this->glmpdfPlaceText( "Confirmation:", $promptCol, $this->glmpdfCurrentY-5, "left", 'black' ); + $this->glmpdfPlaceText( $order['ccconf'], $valCol, $this->glmpdfLastY, "left", 'black', -160 ); + $this->glmpdfPlaceText( "Total Charged:", $promptCol, $this->glmpdfCurrentY-5, "left", 'black' ); + $this->glmpdfPlaceText( $order['charge_total'], $valCol, $this->glmpdfLastY, "left", 'black', -160 ); + + // Purchase Summary + $ticNumbCol = 20; + $perfNameCol = 80; + $ticNameCol = 200; + $secNameCol = 370; + $dateCol = 440; + $this->glmpdfPlaceText( '', $ticNumbCol, 550, "center", 'black', 0, ''); + + $this->glmpdfSetFont( "Helvetica", 8.0 ); + $this->glmpdfPlaceText( $this->config->term->voucher->cap, $ticNumbCol, $this->glmpdfCurrentY, "left", 'black', -52, ''); + $this->glmpdfPlaceText( $this->config->term->performance->cap, $perfNameCol, $this->glmpdfLastY, "left", 'black', -110, ''); + $this->glmpdfPlaceText( $this->config->term->ticket->cap, $ticNameCol, $this->glmpdfLastY, "left", 'black', -160, ''); + $this->glmpdfPlaceText( $this->config->term->section->cap, $secNameCol, $this->glmpdfLastY, "left", 'black', -60, ''); + $this->glmpdfPlaceText( 'Date / Time', $dateCol, $this->glmpdfLastY, "left", 'black', -160, ''); + + $this->glmpdfPlaceText( '', $ticNumbCol, $this->glmpdfCurrentY-3, "center", 'black', 0, ''); + + foreach( $vouchers as $t ) { + + $voucherCode = $this->addCheckCode($t['id']); + + $this->glmpdfSetFont( "Helvetica", 8.0 ); + $this->glmpdfPlaceText( $voucherCode, $ticNumbCol, $this->glmpdfCurrentY, "left", 'black', -52, ''); + $this->glmpdfPlaceText( html_entity_decode($t['performance_name'],ENT_QUOTES,"utf-8"), $perfNameCol, $this->glmpdfLastY, "left", 'black', -110, ''); + $this->glmpdfPlaceText( html_entity_decode($t['ticket_name'],ENT_QUOTES,"utf-8"), $ticNameCol, $this->glmpdfLastY, "left", 'black', -160, ''); + $this->glmpdfPlaceText( html_entity_decode($t['section_name'],ENT_QUOTES,"utf-8"), $secNameCol, $this->glmpdfLastY, "left", 'black', -60, ''); + if ($t['date_specific']['value']) { + $this->glmpdfPlaceText( $t['ticket_date']['date'], $dateCol, $this->glmpdfLastY, "left", 'black', -160, ''); + } else { + $dateRange = 'Valid From '.$t['start_date']['date'].' through '.$t['end_date']['date']; + $this->glmpdfPlaceText( $dateRange, $dateCol, $this->glmpdfLastY, "left", 'black', -160, ''); + } + + // Check for Ticket add-ons + if (isset($t['addons_sold']) && count($t['addons_sold']) > 0) { + foreach($t['addons_sold'] as $a) { + + $addonText = $a['add_on_name']; + if (($a['add_on_type']['value']-0) == 2) { + $addonText = $addonText.', '.$a['quant'].' '.$a['unit_name']; + } + $this->glmpdfPlaceText( html_entity_decode($addonText,ENT_QUOTES,"utf-8"), $ticNameCol+10, $this->glmpdfCurrentY, "left", 'black', -240, ''); + } + } + + } + + // Special Needs + $this->glmpdfSetFont( "Helvetica", 9.0 ); + if (trim($order['special_needs']) != '') { + $this->glmpdfPlaceText( "Special Needs:", 20, $this->glmpdfCurrentY-30, "left", 'black' ); + $this->glmpdfPlaceTextBox( $order['special_needs'], 100, $this->glmpdfCurrentY+16, 450, 50, "left", 'black' ); + } + + // General Member Policies + if (trim($member['def_ticket_pol']) != '') { + $this->glmpdfPlaceText( "Policies:", 20, $this->glmpdfCurrentY-30, "left", 'black' ); + $this->glmpdfPlaceTextBox( $member['def_ticket_pol'], 100, $this->glmpdfCurrentY+16, 450, 50, "left", 'black' ); + } + + // Now setup ticket forms + $this->glmpdfSetForms( + 1, + array( + 1 => array( 'x' => 25, 'y' => 495, 'xs' => 560, 'ys' => 275 ) +// 2 => array( 'x' => 25, 'y' => 210, 'xs' => 560, 'ys' => 275 ) + ), + 'US Letter' + ); + // Also reset form count + $this->glmpdfNextPage(); + + // Display Footer + $this->glmpdfSetFont( "Helvetica-Bold", 8.5 ); + $this->glmpdfPlaceText( $footer, 140.5, 2, "center", 'darkblue' ); +/*********CPS + // Display Parking Map + if ($parkingImage) { + $this->glmpdfNextForm(); + $this->glmpdfPlaceImage( $parkingImage, 0, 2, 0, 'meet', 'center', 280, 125); + $this->glmpdfSetFont( "Helvetica-Bold", 10.0 ); + $this->glmpdfPlaceText( 'Parking Map', 140, 130, "center", 'black' ); + } + + // Display Section Map + if ($sectionImage) { + $this->glmpdfNextForm(); + $this->glmpdfPlaceImage( $sectionImage, 0, 2, 0, 'meet', 'center', 280, 125); + $this->glmpdfSetFont( "Helvetica-Bold", 10.0 ); + $this->glmpdfPlaceText( 'Section Map', 140, 130, "center", 'black' ); + } +*/ + + // Load mask for darkening the bottom portion of the tickets +// $ticketMask = $this->glmpdfOpenImage(EVENT_MANAGEMENT_APP_BASE.'web/custom/greatlakesbaymag/assets/ticket-gradient.png'); + + // Clear performance image loaded flag + $performanceLoaded = false; + + // Process Vouchers - For each type of ticket purchased + $numb_tickets = 0; + foreach( $vouchers as $t ) + { + + if ($numb_tickets++ > 0) { + $this->glmpdfNextForm(); + } + $this->glmpdfPlaceBox( $this->borderWidth, 0, 275, 560, 275, $this->borderColor ); + + // Display Logo - Only get performance image if it's not currently loaded + if ($performanceLoaded != $t['performance']) { + + $performanceDetail = $Performances->getPerformanceDetail($t['performance']); + + // If we have an image but it's the wrong one, dump the temp file + if ($performanceImageFile) { + unlink($performanceImageFile); + } + + // This performance image is not currently loaded - so do that now + + $performanceImageFile = $imServer->saveImageToTemp(IMAGE_SERVER_PREFIX.'original/'.$performanceDetail['image']); + if ($performanceImageFile) { + // If we have the image, then load it + $performanceImage = $this->glmpdfOpenImage($performanceImageFile); + $performanceLoaded = $t['performance']; + } else { + + // otherwise, try the venue image + $performanceLoaded = $venueImage; + } + + } + + // If we have the performance image, display it + $haveTopImage = false; + if ($performanceImage) { + $this->glmpdfPlaceImage( $performanceImage, 85, 195, 1, 'meet', 'center', 70, 75); + $haveTopImage = true; + } elseif ($venueImageFile) { + $this->glmpdfPlaceImage($coverImage, 85, 195, 1, 'meet', 'center', 70, 75); + $haveTopImage = true; + } + + // Place owner name at top possitioned by whether or not there's an image supplied + $this->glmpdfSetFont( "Helvetica-Bold", 24.0 ); + if ($haveTopImage) { + $this->glmpdfPlaceText( $config->owner->name, 315, 227, "center", 'black', -300, ''); + } else { + $this->glmpdfPlaceText( $config->owner->name, 280, 227, "center", 'black', -350, ''); + } + + // Place mask + //$this->glmpdfPlaceImage($ticketMask, 0, 52, .25, false, 'center', 280, 140); + + // If ticket has already been claimed, then mark ticket + if ($t['time_claimed']['date'] != '') { + $this->glmpdfSetFont( "Times-Bold", 72.0 ); + $this->glmpdfPlaceText( "CLAIMED", 110, 80, "left", 'orangered', 0, '' ); // last parameter can be things like "rotate=90" + } + + // Ticket Information Area + $this->glmpdfSetFont( "Helvetica-Bold", 24.0 ); + $this->glmpdfPlaceLine(1, 80, 0, 80, 275, $color = "black", $dash = false, $d_a = 1, $d_b = 1); + $this->glmpdfPlaceLine(1, 480, 0, 480, 275, $color = "black", $dash = false, $d_a = 1, $d_b = 1); + + // Left End of Ticket - NOTE: use only "left" in glmpdfPlaceText - use "position=..." in optlist instead. + if (($t['entrance']-0) > 0) { + $entranceDetail = $Entrances->getEntranceDetail($t['entrance']); + $this->glmpdfPlaceBox(1, 0, 0, 80, -275, '', $entranceDetail['color']['name'], 'miter'); + } + $this->glmpdfSetFont( "Helvetica-Bold", 10.0 ); + $this->glmpdfPlaceText( 'Departing from:', 7, 40, 'left', 'black', 0, 'position=center rotate=90'); + $this->glmpdfSetFont( "Helvetica-Bold", 20.0 ); + $this->glmpdfPlaceText( strtoupper(html_entity_decode($t['entrance_name'],ENT_QUOTES,"utf-8")), 30, 138, 'left', 'black', -250, 'position=center rotate=90'); + $this->glmpdfPlaceText( strtoupper(html_entity_decode($t['member_name'],ENT_QUOTES,"utf-8")), 60, 138, 'left', 'black', -250, 'position=center rotate=90'); + + // Display values + $this->glmpdfSetFont( "Helvetica-Bold", 26.0 ); + $this->glmpdfPlaceText( html_entity_decode($t['performance_name'],ENT_QUOTES,"utf-8"), 280, 170, "center", 'black', -370, ''); + $this->glmpdfSetFont( "Helvetica-Bold", 24.0 ); + $this->glmpdfPlaceText( html_entity_decode($t['ticket_name'],ENT_QUOTES,"utf-8"), 280, 140, "center", 'black', -370, '' ); + $this->glmpdfSetFont( "Helvetica-Bold", 20.0 ); +// $this->glmpdfPlaceText( html_entity_decode($t['section_name'],ENT_QUOTES,"utf-8"), 280, 130, "center", 'black', -370, '' ); + $this->glmpdfSetFont( "Helvetica", 18.0 ); + if ($t['date_specific']['value']) { + $this->glmpdfPlaceText( $t['ticket_date']['date'], 280, 110, "center", 'black', -370, '' ); + } else { + $dateRange = 'Valid From '.$t['start_date']['date'].' through '.$t['end_date']['date']; + $this->glmpdfPlaceText( $dateRange, 280, 110, "center", 'black', -370, '' ); + } + + $this->glmpdfSetFont( "Helvetica", 16.0 ); + + // Check for Ticket add-ons + if (isset($t['addons_sold']) && count($t['addons_sold']) > 0) { + $this->glmpdfSetFont( "Helvetica", 14.0 ); + foreach($t['addons_sold'] as $a) { + $addonText = $a['add_on_name']; + if (($a['add_on_type']['value']-0) == 2) { + $addonText = $addonText.', '.$a['quant'].' '.$a['unit_name']; + } + $this->glmpdfPlaceText( $addonText, 280, $this->glmpdfCurrentY, "center", 'black', -370, '' ); + } + } + + // Display NON-REFUNDABLE MESSAGE + $this->glmpdfSetFont( "Helvetica", 14.0 ); + $this->glmpdfPlaceText( "NON-REFUNDABLE", 280, $this->glmpdfCurrentY, "center", 'black', -300, ''); + + // Display address and contact information + if ($venueContact) { + $this->glmpdfSetFont( "Helvetica", 10.0 ); + $this->glmpdfPlaceText( html_entity_decode($this->config->term->prop->cap.' contact information',ENT_QUOTES,"utf-8"), 280, $this->glmpdfCurrentY-5, "center", 'black', -300, ''); + $this->glmpdfPlaceText( html_entity_decode($venueContact,ENT_QUOTES,"utf-8"), 280, $this->glmpdfCurrentY, "center", 'black', -300, ''); + } + + // Display address and contact information + if ($companyContact) { + $this->glmpdfSetFont( "Helvetica", 10.0 ); + $this->glmpdfPlaceText( html_entity_decode($companyContact,ENT_QUOTES,"utf-8"), 280, 25, "center", 'black', -380, ''); + } + + // Display additional voucher text at the bottom of the voucher if provided + $voucherText = ''; + if (trim($t['ticket_voucher_text']) != '') { + $voucherText = trim(html_entity_decode($t['ticket_voucher_text'],ENT_QUOTES,"utf-8")); + } elseif (trim($performanceDetail['voucher_text']) != '') { + $voucherText = trim(html_entity_decode($performanceDetail['voucher_text'],ENT_QUOTES,"utf-8")); + } + if ($voucherText != '') { + $this->glmpdfPlaceLine(1, 80, 20, 480, 20, 'black', false); + $this->glmpdfSetFont( "Helvetica-Bold", 14.0 ); +// $this->glmpdfPlaceBox(1, 80, 20, 400, 20, "black", "black"); + $this->glmpdfPlaceText( html_entity_decode($voucherText,ENT_QUOTES,"utf-8"), 280, 6, "center", 'black', -370, '' ); + } + + // $this->glmpdfPlaceText( $t['ticket_date']['date'].' - '.$t['ticket_time']['time'], 120, $this->glmpdfCurrentY, "left", 'black', 0, '' ); + + // Print barcode = {ticket_sold ID}-{person type}-{person_sequence} + $barcode = $this->addCheckCode($t['id']); + // If we're supposed to print barcode and voucher number on ticket + switch ($t['ticket_voucher_type']) { + + case 11: // Voucher/Ticket for Pickup - no Barcode + $this->glmpdfSetFont( "Helvetica-Bold", 20.0 ); + $this->glmpdfPlaceText( "Pickup at ".$this->config->term->prop->norm, 510, 140, 'left', 'black', -260, 'position=center rotate=90'); + $this->glmpdfSetFont( "Courier", 12.0 ); + $this->glmpdfPlaceText( $this->config->term->voucher->cap." $barcode", 540, 140, 'left', 'black', -260, 'position=center rotate=90'); + break; + + case 12; // Voucher/Ticket to be mailed Mailed - no Barcode + case 82; // Object Sold (i.e. books) to be mailed - no Barcode + $this->glmpdfSetFont( "Helvetica-Bold", 20.0 ); + $this->glmpdfPlaceText( "You will receive this by mail", 510, 140, 'left', 'black', -260, 'position=center rotate=90'); + $this->glmpdfSetFont( "Courier", 12.0 ); + $this->glmpdfPlaceText( $this->config->term->voucher->cap." $barcode", 540, 140, 'left', 'black', -260, 'position=center rotate=90'); + break; + + case 1: // Standard Voucher/Ticket with Barcode + case 81; // Object Sold (i.e. books) to be claimed - with Barcode + default: + $this->glmpdfSetFont( 'barcode', 54 ); + $this->glmpdfPlaceText( "*$barcode*", 510, 140, 'left', 'black', 0, 'position=center rotate=90'); + $this->glmpdfSetFont( "Courier", 12.0 ); + $this->glmpdfPlaceText( $this->config->term->voucher->cap." $barcode", 540, 140, 'left', 'black', -260, 'position=center rotate=90'); + break; + + } + + $this->glmpdfPlaceText( "Order #".$order['id'], 552, 140, 'left', 'black', 0, 'position=center rotate=90'); + + // Check if we need to display a coupon +// if( ++$numb_tickets % $this->pdfCouponInterval == 0 ) +// $this->printCoupon(); + + } // Each voucher + + // Make sure we print the minimum number of coupons +// $numb_coupons = 0; +// while( $numb_coupons < $this->pdfMinCoupons ) { +// $this->printCoupon(); +// $numb_coupons++; +// } + + // Close PDF setup and send to user's browser + $this->glmpdfSendToBrowser( '', 'voucher.pdf' ); + + if ($venueImageFile) { + unlink($venueImageFile); + } + if ($parkingImageFile) { + unlink($parkingImageFile); + } + if ($sectionImageFile) { + unlink($sectionImageFile); + } + if ($sectionImageFile) { + unlink($sectionImageFile); + } + + } + + + // function to print a coupon + function printCoupon() + { + // Print a Coupon + $this->glmpdfNextForm(); + $this->glmpdfPlaceBox( $this->borderWidth, 0, 142, 281, 142, $this->borderColor ); + + // Place Coupon Image + $this->glmpdfSetFont( "Helvetica-Bold", 10.0 ); + $this->glmpdfPlaceText( 'Coupon Title', 85, 130, "center", 'black' ); + $this->glmpdfPlaceText( 'Expires on: 1/1/2020', 85, 75 ); + $this->glmpdfSetFont( "Times-Bold", 30.0 ); + $this->glmpdfPlaceText( "COUPON", 85, 95, "center", 'lightgrey' ); + $this->glmpdfSetFont( "Helvetica", 8.0 ); + $this->glmpdfPlaceTextBox( 'This is a coupon description. It describes this coupon.', 5, 55, 274, 40, "left", 'black' ); + $this->glmpdfSetFont( "Helvetica-Bold", 8.5 ); + $this->glmpdfPlaceText( "Mackinaw Area Visitors Bureau - Mackinaw City, MI - 800-666-0160", 140.5, 2, "center", 'darkblue' ); + + } + + /* + * Function to add check character to end of voucher number + * + * Uses config->voucher_check_secret and voucher # to create MD5 string + * then takes last hex character off of that string and shifts it up to + * always be a character (adds 16 to numbers and 10 to the upper-case + * version of the character). + * i.e. 0 = A, 9 = J, A = K, F = + * + */ + public function addCheckCode($voucherNumb) + { + + // Create MD5 string using voucher number and secret + $md5 = md5($voucherNumb.$this->config->voucher_check_secret); + + // Get last character code of the last character in the MD5 + $cc = strtoupper(substr($md5, -2)); + $cc[0] = $this->shiftCheckCodeCharacter($cc[0]); + $cc[1] = $this->shiftCheckCodeCharacter($cc[1]); + + // Return voucher number with the new character on the end + $voucherNumb .= $cc; + return $voucherNumb; + + } + + private function shiftCheckCodeCharacter($c) { + + $x = ord($c); + + // If it's a digit, add 16 + if ($x < 65) { + $x += 17; + // otherwise, add 10 + } else { + $x += 10; + } + + // Also skip the letter O + if (x >= ord('O')) { + $x += 1; + } + + return chr($x); + } + +} // class + +// Absolutely nothing after next line +?> \ No newline at end of file diff --git a/models/vouchers/MMM/voucher.php b/models/vouchers/MMM/voucher.php new file mode 100644 index 0000000..5f541cd --- /dev/null +++ b/models/vouchers/MMM/voucher.php @@ -0,0 +1,1146 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: printVoucher.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +require_once PDF_ABSTRACT; +$Pdf = new GlmPdf(); + +/** + * PdfVoucher class + * + * @category PdfVoucher + * @package PDFLib + * @author Chuck Scott + * @license http://www.gaslightmedia.com Gaslightmedia + * @link <> +*/ +class PdfVoucher extends GlmPdf +{ + + public $borderWidth = 1; + public $borderColor = 'black'; + public $pdfCouponInterval = 5; + public $pdfMinCoupons = 3; + public $config; + private $is; + private $dbh; + + function __construct($order, $vouchers, $member, $dbh, $config, $couponTest = false) + { + + $this->dbh = $dbh; + $this->config = $config; + + // Load image server support + require_once IMAGE_SERVER_ABSTRACT; + $this->is = new ImageServerAbstract(); + + // if debug.glmpdf is set in the configs/common.ini file in the CommonApp directory, do grids on PDFs + define ('GLMPDF_DEBUG', $this->config->debug->glmpdf); + + // The following produces a color test sheet. There is no return from that call. + // $this->glmpdfShowValidColors(); exit; + + // Start with cover page. + $this->glmpdfSetForms( + 1, + array( + 1 => array( 'x' => 0, 'y' => 0, 'xs' => 613, 'ys' => 792 ) + ), + 'US Letter' + ); + + // Start page + $this->glmpdfStart( $this->config->owner->name, "Gaslight Media", "Ticket System Receipt/Vouchers" ); + + if( !$this->glmpdfAddFont( 'barcode', 'barcode/FREE3OF9.TTF' ) ) + { + echo 'ERROR: Unable to add barcode font.

    + Did you place the barcode font provided in docs/BarcodeFonts into + a system fonts directory ("/usr/share/fonts/truetype/Barcode")? + Also check the GLMPDF_PDF_FONT_DIR setting in GlmPdf.php.'; + exit; + } + + // Get images to tmp files + if (trim($member['image']) != '') { + $venueImageFile = $this->is->saveImageToTemp(IMAGE_SERVER_PREFIX.'original/'.$member['image']); + if ($venueImageFile) { + $venueImage = $this->glmpdfOpenImage($venueImageFile); + + // If failure getting the image + if ($venueImage == false) { + $venueImageFile = false; + } + } + } else { + $venueImageFile = false; + } + + if (trim($member['parking_map']) != '') { + $parkingImageFile = $this->is->saveImageToTemp(IMAGE_SERVER_PREFIX.'original/'.$member['parking_map']); + if ($parkingImageFile) { + $parkingImage = $this->glmpdfOpenImage($parkingImageFile); + + // If failure getting the image + if ($parkingImage == false) { + $parkingImageFile = false; + } + } + } else { + $parkingImageFile = false; + } + + if (trim($member['ticket_sec_map']) != '') { + $sectionImageFile = $this->is->saveImageToTemp(IMAGE_SERVER_PREFIX.'original/'.$member['ticket_sec_map']); + if ($sectionImageFile) { + $sectionImage = $this->glmpdfOpenImage($sectionImageFile); + + // If failure getting the image + if ($sectionImage == false) { + $sectionImageFile = false; + } + } + } else { + $sectionImageFile = false; + } + + // Load entrance class + require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/entrances.php'; + $Entrances = new EventManagementAdminEntrances($dbh, $config); + + // Load performance class + require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/performances.php'; + $Performances = new EventManagementAdminPerformances($dbh, $config); + + // Load Voucher Coupons class and get coupons list for display + require_once EVENT_MANAGEMENT_APP_BASE.'classes/data/dataVoucherCoupons.php'; + $VoucherCoupons = new EventManagementDataVoucherCoupons($dbh, $config); + + // Load ticket packages data class + require_once EVENT_MANAGEMENT_APP_BASE.'classes/data/dataTicketPackages.php'; + $TicketPackages = new EventManagementDataTicketPackages($dbh, $config); + + + // If no date has been supplied - make it today + if (isset($_REQUEST['date']) && $_REQUEST['date'] != '') { + $date = $_REQUEST['date']; + } else { + $date = date('m/d/Y', time()); + } + + $vc = $VoucherCoupons->getCouponsForDisplay($date); + + // Setup footers +/* + $footer = 'For assistance call '.$this->config->owner->phone; + if ($this->config->owner->toll_free != '') { + $footer .= ' or '.$this->config->owner->toll_free; + } +*/ + + if (!$couponTest) { + + $this->glmpdfNextForm(); + + + /* Cover Page */ + + // Header + if ($venueImageFile) { + $coverImage = $this->glmpdfOpenImage($venueImageFile); + $this->glmpdfPlaceImage($coverImage, 30, 690, .5, false, 'center', 280, 140); + } + $this->glmpdfSetFont( "Helvetica-Bold", 18.0 ); // Header Text + $this->glmpdfPlaceText( $config->owner->name, 340, 750, "center", 'black', -400 ); + $this->glmpdfSetFont( "Helvetica", 14.0 ); + $this->glmpdfPlaceText( $config->owner->short_name." - ".$member['name'], 340, $this->glmpdfCurrentY-10, "center", 'black', -400 ); + $this->glmpdfPlaceText( $member['addr1'], 340, $this->glmpdfCurrentY, "center", 'black', -400 ); + $this->glmpdfPlaceText( $member['city'].", ".$member['state']['name']." ".$member['zip'], 340, $this->glmpdfCurrentY, "center", 'black', -400 ); + + // Sold To Information + $valCol = 60; + $this->glmpdfSetFont( "Helvetica", 10.0 ); + $this->glmpdfPlaceText( $this->config->term->order->cap." ID: ".trim($order['id']), $valCol, 650, "left", 'black' ); + $this->glmpdfPlaceText( trim($order['fname'].' '.$order['lname']), $valCol, $this->glmpdfCurrentY-5, "left", 'black', -200 ); + $this->glmpdfPlaceText( trim($order['addr1']), $valCol, $this->glmpdfCurrentY-5, "left", 'black', -200 ); + if( trim($order['addr2']) != '' ) + $this->glmpdfPlaceText( trim($order['addr2']), $valCol, $this->glmpdfCurrentY-5, "left", 'black', -200 ); + $this->glmpdfPlaceText( trim($order['city']).', '.$order['state']['value'].' '.trim($order['zip']).' '.$order['country']['value'], $valCol, $this->glmpdfCurrentY-5, "left", 'black', -200 ); + + // Purchace/Charge information + $this->glmpdfSetFont( "Helvetica", 10.0 ); + $promptCol = 330; + $valCol = 420; + $this->glmpdfPlaceText( "Date of Purchase:", $promptCol, 650, "left", 'black' ); + $this->glmpdfPlaceText( $order['purchase_date']['date'], $valCol, $this->glmpdfLastY, "left", 'black', -160 ); + $this->glmpdfPlaceText( "Card Type:", $promptCol, $this->glmpdfCurrentY-5, "left", 'black' ); + $this->glmpdfPlaceText( $order['cctype'], $valCol, $this->glmpdfLastY, "left", 'black', -160 ); + $this->glmpdfPlaceText( "Name on Card:", $promptCol, $this->glmpdfCurrentY-5, "left", 'black' ); + $this->glmpdfPlaceText( $order['ccname'], $valCol, $this->glmpdfLastY, "left", 'black', -160 ); + $this->glmpdfPlaceText( "Card Number:", $promptCol, $this->glmpdfCurrentY-5, "left", 'black' ); + $this->glmpdfPlaceText( $order['ccnumber'], $valCol, $this->glmpdfLastY, "left", 'black', -160 ); + $this->glmpdfPlaceText( "Confirmation:", $promptCol, $this->glmpdfCurrentY-5, "left", 'black' ); + $this->glmpdfPlaceText( $order['ccconf'], $valCol, $this->glmpdfLastY, "left", 'black', -160 ); + $this->glmpdfPlaceText( "Total Charged:", $promptCol, $this->glmpdfCurrentY-5, "left", 'black' ); + $this->glmpdfPlaceText( $order['charge_total'], $valCol, $this->glmpdfLastY, "left", 'black', -160 ); + + // Purchase Summary + $ticNumbCol = 20; + $perfNameCol = 80; + $ticNameCol = 300; + $secNameCol = 450; + $dateCol = 500; + $this->glmpdfPlaceText( '', $ticNumbCol, 550, "center", 'black', 0, ''); + + $this->glmpdfSetFont( "Helvetica", 8.0 ); + $this->glmpdfPlaceText( $this->config->term->voucher->cap, $ticNumbCol, $this->glmpdfCurrentY, "left", 'black', -52, ''); + $this->glmpdfPlaceText( $this->config->term->performance->cap, $perfNameCol, $this->glmpdfLastY, "left", 'black', -110, ''); + $this->glmpdfPlaceText( $this->config->term->ticket->cap, $ticNameCol, $this->glmpdfLastY, "left", 'black', -160, ''); +// $this->glmpdfPlaceText( $this->config->term->section->cap, $secNameCol, $this->glmpdfLastY, "left", 'black', -60, ''); + $this->glmpdfPlaceText( 'Date / Time', $dateCol, $this->glmpdfLastY, "left", 'black', -160, ''); + + $this->glmpdfPlaceText( '', $ticNumbCol, $this->glmpdfCurrentY-3, "center", 'black', 0, ''); + + foreach( $vouchers as $t ) { + + $voucherCode = $this->addCheckCode($t['id']); + + $this->glmpdfSetFont( "Helvetica", 8.0 ); + if (!$t['ticket_package']) { + $this->glmpdfPlaceText( $voucherCode, $ticNumbCol, $this->glmpdfCurrentY, "left", 'black', -52, ''); + } else { + $this->glmpdfPlaceText( '', $ticNumbCol, $this->glmpdfCurrentY, "left", 'black', -52, ''); + } + $memberPerformance = $t['real_member_name'].': '.$t['performance_name']; + $this->glmpdfPlaceText( html_entity_decode($memberPerformance,ENT_QUOTES,"utf-8"), $perfNameCol, $this->glmpdfLastY, "left", 'black', -110, ''); + $this->glmpdfPlaceText( html_entity_decode($t['ticket_name'],ENT_QUOTES,"utf-8"), $ticNameCol, $this->glmpdfLastY, "left", 'black', -160, ''); + if (!$t['is_package']['value']) { +// $this->glmpdfPlaceText( html_entity_decode($t['section_name'],ENT_QUOTES,"utf-8"), $secNameCol, $this->glmpdfLastY, "left", 'black', -60, ''); + if ($t['date_specific']['value']) { +//echo "

    ".print_r($t,1)."
    ";exit; + $datetime = $t['ticket_date']['date']; + if ($t['time_specific']['value']) { + $datetime .= ' '.$t['ticket_time']['time']; + } +// $this->glmpdfPlaceText( $t['ticket_date']['date'].".", $dateCol, $this->glmpdfLastY, "left", 'black', -160, ''); + $this->glmpdfPlaceText( $datetime, $dateCol, $this->glmpdfLastY, "left", 'black', -160, ''); + } else { + $dateRange = 'Valid From '.$t['start_date']['date'].' through '.$t['end_date']['date']; + $this->glmpdfPlaceText( $dateRange, $dateCol, $this->glmpdfLastY, "left", 'black', -160, ''); + } + } + + // Check for Ticket add-ons + if (isset($t['addons_sold']) && count($t['addons_sold']) > 0) { + foreach($t['addons_sold'] as $a) { + + $addonText = $a['add_on_name']; + if (($a['add_on_type']['value']-0) == 2) { + $addonText = $addonText.', '.$a['quant'].' '.$a['unit_name']; + } + $this->glmpdfPlaceText( html_entity_decode($addonText,ENT_QUOTES,"utf-8"), $ticNameCol+10, $this->glmpdfCurrentY, "left", 'black', -240, ''); + } + } + + } + + // Special Needs + $this->glmpdfSetFont( "Helvetica", 9.0 ); + if (trim($order['special_needs']) != '') { + $this->glmpdfPlaceText( "Special Needs:", 20, $this->glmpdfCurrentY-30, "left", 'black' ); + $this->glmpdfPlaceTextBox( $order['special_needs'], 100, $this->glmpdfCurrentY+16, 450, 50, "left", 'black' ); + } + + // General Member Policies + if (trim($member['def_ticket_pol']) != '') { + $this->glmpdfPlaceText( "Policies:", 20, $this->glmpdfCurrentY-30, "left", 'black' ); + $this->glmpdfPlaceTextBox( $member['def_ticket_pol'], 100, $this->glmpdfCurrentY+16, 450, 50, "left", 'black' ); + } + + } + + // Standard voucher & coupon form - 1 Voucher, 8 coupons + $voucher1_coupon8 = array( + 'forms' => 10, + 'layout' => array( + 1 => array( 'x' => 25, 'y' => 515, 'xs' => 560, 'ys' => 232 ), + 2 => array( 'x' => 25, 'y' => 325, 'xs' => 375, 'ys' => 150 ), + 3 => array( 'x' => 415, 'y' => 325, 'xs' => 170, 'ys' => 150 ), + 4 => array( 'x' => 25, 'y' => 160, 'xs' => 170, 'ys' => 150 ), + 5 => array( 'x' => 210, 'y' => 160, 'xs' => 375, 'ys' => 150 ), + 6 => array( 'x' => 25, 'y' => 25, 'xs' => 137, 'ys' => 120 ), + 7 => array( 'x' => 166, 'y' => 25, 'xs' => 137, 'ys' => 120 ), + 8 => array( 'x' => 307, 'y' => 25, 'xs' => 137, 'ys' => 120 ), + 9 => array( 'x' => 448, 'y' => 25, 'xs' => 137, 'ys' => 120 ), + 10 => array( 'x' => 25, 'y' => 25, 'xs' => 419, 'ys' => 120 ), + ) + ); + + // Package vouchers - 3 vouchers, no coupons + $voucher3_coupon0 = array( + 'forms' => 3, + 'layout' => array( + 1 => array( 'x' => 25, 'y' => 561, 'xs' => 560, 'ys' => 176 ), + 2 => array( 'x' => 25, 'y' => 308, 'xs' => 560, 'ys' => 176 ), + 3 => array( 'x' => 25, 'y' => 55, 'xs' => 560, 'ys' => 176 ) + ) + ); + + // Now setup ticket forms + $this->glmpdfSetForms( + $voucher1_coupon8['forms'], + $voucher1_coupon8['layout'], + 'US Letter' + ); + +/*********CPS + // Display Parking Map + if ($parkingImage) { + $this->glmpdfNextForm(); + $this->glmpdfPlaceImage( $parkingImage, 0, 2, 0, 'meet', 'center', 280, 125); + $this->glmpdfSetFont( "Helvetica-Bold", 10.0 ); + $this->glmpdfPlaceText( 'Parking Map', 140, 130, "center", 'black' ); + } + + // Display Section Map + if ($sectionImage) { + $this->glmpdfNextForm(); + $this->glmpdfPlaceImage( $sectionImage, 0, 2, 0, 'meet', 'center', 280, 125); + $this->glmpdfSetFont( "Helvetica-Bold", 10.0 ); + $this->glmpdfPlaceText( 'Section Map', 140, 130, "center", 'black' ); + } +*/ + + // Clear performance image loaded flag + $performanceLoaded = false; + +// $this->glmpdfNextPage(); + $firstVoucherPageSet = false; + + // Process Vouchers - For each type of ticket purchased + $numb_tickets = 0; + $counterSQL = ''; + $packageVouchersPrintedSeparately = ''; + $allPackageVouchersSeparate = true; + $packageVoucher = false; + $packageTicketName = ''; + $doDashes = false; + $skipNextFormAdvance = false; + + foreach( $vouchers as $t ) + { + + // Flag to determine if this voucher will be displayed (vouchers not displayed if it's a package ticket) + $displaying_this_voucher = false; + + if (!$couponTest) { + + // Check if the current voucher is a new package that has vouchers that print + if ($t['is_package']['value']) { + + $packageVoucher = true; + + // Check if any vouchers for this package print separately + $ticketPackage = $TicketPackages->getList('package = '.$t['ticket']); + if (is_array($ticketPackage) && count($ticketPackage) > 0) { + + // For each ticket in the package + foreach ($ticketPackage as $tp) { + + // Check if it requires a separate voucher + if ($tp['separate_voucher']['value']) { + + // Set this flag to the package sold ID (same for all vouchers for a package) so we can tell if we hit the end of the package + $packageVouchersPrintedSeparately = $t['package_sold_id']; + $packagePerformanceName = $t['performance_name']; + $packageTicketName = $t['ticket_name']; + } else { + $allPackageVouchersSeparate = false; + } + } + } + + // If we found one, then switch layouts. + if ($packageVouchersPrintedSeparately != '') { + $this->glmpdfSetForms( + $voucher3_coupon0['forms'], + $voucher3_coupon0['layout'], + 'US Letter' + ); + $voucherPageStarted = false; + $skipNextFormAdvance = false; + $doDashes = true; + if ($numb_tickets) { + $skipNextFormAdvance = true; + } + } + + // If we have a package with separate vouchers + } else { + $packageVoucher = false; + } + + if ($packageVouchersPrintedSeparately != '') { + + // Check if we're now past the package that had vouchers printed separately + if ($t['package_sold_id'] != $packageVouchersPrintedSeparately) { + + $this->glmpdfSetForms( + $voucher1_coupon8['forms'], + $voucher1_coupon8['layout'], + 'US Letter' + ); + $voucherPageStarted = false; + $packageVouchersPrintedSeparately = ''; + $skipNextFormAdvance = true; + } + + } + + // Check if this voucher is a print separate voucher for a package + $printVoucher = false; + if ($t['ticket_package']) { + + // Get ticket_package data + $ticketPackage = $TicketPackages->getList('package = '.$t['ticket_package'].' AND ticket = '.$t['ticket']); + + // If Separate Voucher, override and display voucher. + if ($ticketPackage[0]['separate_voucher']['value']) { + $printVoucher = true; + } + + } else { + $printVoucher = true; + } + + // Check if this is a package voucher and we are printing all package tickets separately + if ($packageVoucher && $allPackageVouchersSeparate) { + $printVoucher = false; + } + + // If this isn't a package ticket (we're not printing separate vouchers at this time) + if ($printVoucher) { + + + if ($packageVouchersPrintedSeparately) { + + // If the first voucher page hasn't been set + if (!$voucherPageStarted) { + $this->glmpdfNextPage(); + $voucherPageStarted = true; + + if ($doDashes) { + // Print perforations + $this->glmpdfPlaceLine(1, 0, -38, 560, -38, $color = "dimgray", $dash = true, $d_a = 1, $d_b = 5); + $this->glmpdfPlaceLine(1, 0, -291, 560, -291, $color = "dimgray", $dash = true, $d_a = 1, $d_b = 5); + $doDashes = false; + } + + } + + $displaying_this_voucher = true; + + if ($numb_tickets++ > 0) { + + if ($skipNextFormAdvance) { + $skipNextFormAdvance = false; + } else { + $this->glmpdfNextForm(); + } + } + $this->glmpdfPlaceBox( $this->borderWidth, 0, 176, 560, 176, $this->borderColor ); + + // Display Logo - Only get performance image if it's not currently loaded + if ($performanceLoaded != $t['performance']) { + + $performanceDetail = $Performances->getPerformanceDetail($t['performance']); + + // If we have an image but it's the wrong one, dump the temp file + if ($performanceImageFile) { + unlink($performanceImageFile); + } + + // This performance image is not currently loaded - so do that now + + $performanceImageFile = $this->is->saveImageToTemp(IMAGE_SERVER_PREFIX.'original/'.$performanceDetail['image']); + if ($performanceImageFile) { + // If we have the image, then load it + $performanceImage = $this->glmpdfOpenImage($performanceImageFile); + $performanceLoaded = $t['performance']; + } else { + + // otherwise, try the venue image + $performanceLoaded = $venueImage; + } + + } + + // If we have the performance image, display it + $haveTopImage = false; + if ($performanceImage) { + $this->glmpdfPlaceImage( $performanceImage, 85, 100, 1, 'meet', 'center', 70, 75); + $haveTopImage = true; + } elseif ($venueImageFile) { + $this->glmpdfPlaceImage($coverImage, 85, 100, 1, 'meet', 'center', 70, 75); + $haveTopImage = true; + } + + // Place owner name at top possitioned by whether or not there's an image supplied + $this->glmpdfSetFont( "Helvetica-Bold", 20.0 ); + if ($haveTopImage) { + $this->glmpdfPlaceText( $config->owner->name, 315, 131, "center", 'black', -300, ''); + } else { + $this->glmpdfPlaceText( $config->owner->name, 280, 131, "center", 'black', -350, ''); + } + + // If ticket has already been claimed, then mark ticket + if ($t['time_claimed']['date'] != '') { + $this->glmpdfSetFont( "Times-Bold", 72.0 ); + $this->glmpdfPlaceText( "CLAIMED", 110, 80, "left", 'orangered', 0, '' ); // last parameter can be things like "rotate=90" + } + + // Ticket Information Area + $this->glmpdfPlaceLine(1, 80, 0, 80, 176, $color = "black", $dash = false, $d_a = 1, $d_b = 1); + $this->glmpdfPlaceLine(1, 480, 0, 480, 176, $color = "black", $dash = false, $d_a = 1, $d_b = 1); + + // If part of a package, print the package name it's part of. + if ($packageTicketName && !$t['is_package']['value']) { + + $this->glmpdfSetFont( "Helvetica-Bold", 10.0 ); + $this->glmpdfPlaceText( 'Part of:', 7, 40, 'left', 'black', 0, 'position=center rotate=90'); + $this->glmpdfSetFont( "Helvetica-Bold", 12.0 ); + $this->glmpdfPlaceText( $packagePerformanceName, 30, 88, 'left', 'black', -165, 'position=center rotate=90'); + $this->glmpdfPlaceText( $packageTicketName, 60, 88, 'left', 'black', -165, 'position=center rotate=90'); + + } else { + + // Left End of Ticket - NOTE: use only "left" in glmpdfPlaceText - use "position=..." in optlist instead. + if (($t['entrance']-0) > 0) { + $entranceDetail = $Entrances->getEntranceDetail($t['entrance']); + $this->glmpdfPlaceBox(1, 0, 0, 80, -232, '', $entranceDetail['color']['name'], 'miter'); + } + + $this->glmpdfSetFont( "Helvetica-Bold", 10.0 ); + $this->glmpdfPlaceText( 'Departing from:', 7, 40, 'left', 'black', 0, 'position=center rotate=90'); + $this->glmpdfSetFont( "Helvetica-Bold", 16.0 ); + $this->glmpdfPlaceText( strtoupper(html_entity_decode($t['entrance_name'],ENT_QUOTES,"utf-8")), 30, 116, 'left', 'black', -224, 'position=center rotate=90'); + $this->glmpdfPlaceText( strtoupper(html_entity_decode($t['member_name'],ENT_QUOTES,"utf-8")), 60, 116, 'left', 'black', -224, 'position=center rotate=90'); + + } + + // Display values + $this->glmpdfSetFont( "Helvetica-Bold", 16.0 ); + $this->glmpdfPlaceText( html_entity_decode($t['performance_name'],ENT_QUOTES,"utf-8"), 280, 91, "center", 'black', -370, ''); + $this->glmpdfSetFont( "Helvetica-Bold", 12.0 ); + $this->glmpdfPlaceText( html_entity_decode($t['ticket_name'],ENT_QUOTES,"utf-8"), 280, 77, "center", 'black', -370, '' ); + + $this->glmpdfSetFont( "Helvetica", 10.0 ); + if ($t['date_specific']['value']) { + $this->glmpdfPlaceText( $t['ticket_date']['date'], 280, 65, "center", 'black', -370, '' ); + } else { + $dateRange = 'Valid From '.$t['start_date']['date'].' through '.$t['end_date']['date']; + $this->glmpdfPlaceText( $dateRange, 280, 65, "center", 'black', -370, '' ); + } + + $this->glmpdfSetFont( "Helvetica", 16.0 ); + + // Put package line for voucher here + + // Check for Ticket add-ons +/* No addons for packages + if (isset($t['addons_sold']) && count($t['addons_sold']) > 0) { + $this->glmpdfSetFont( "Helvetica", 14.0 ); + foreach($t['addons_sold'] as $a) { + $addonText = $a['add_on_name']; + if (($a['add_on_type']['value']-0) == 2) { + $addonText = $addonText.', '.$a['quant'].' '.$a['unit_name']; + } + $this->glmpdfPlaceText( $addonText, 280, $this->glmpdfCurrentY, "center", 'black', -370, '' ); + } + } +*/ + // Non-Refundable and other Fixed text for body of Voucher + $this->glmpdfSetFont( "Helvetica", 10.0 ); + $this->glmpdfPlaceText( "NON-REFUNDABLE", 280, $this->glmpdfCurrentY, "center", 'black', -300, ''); + + // Display address and contact information + $this->glmpdfSetFont( "Helvetica", 10.0 ); + $contactInfo = $this->config->owner->name.' - ' + .$this->config->owner->address1.' - ' + .($this->config->owner->address2 != '' ? ', '.$this->config->owner->address2 : '') + .$this->config->owner->city.', ' + .$this->config->owner->state.' ' + .$this->config->owner->zip.' - ' + .$this->config->owner->phone + .($this->config->owner->toll_free != '' ? ' - '.$this->config->owner->toll_free : ''); + $this->glmpdfPlaceText( html_entity_decode($contactInfo,ENT_QUOTES,"utf-8"), 280, 25, "center", 'black', -380, ''); + + // Display additional voucher text at the bottom of the voucher if provided + $voucherText = ''; + if (trim($t['ticket_voucher_text']) != '') { + $voucherText = trim(html_entity_decode($t['ticket_voucher_text'],ENT_QUOTES,"utf-8")); + } elseif (trim($performanceDetail['voucher_text']) != '') { + $voucherText = trim(html_entity_decode($performanceDetail['voucher_text'],ENT_QUOTES,"utf-8")); + } + if ($voucherText != '') { + $this->glmpdfPlaceLine(1, 80, 20, 480, 20, 'black', false); + $this->glmpdfSetFont( "Helvetica-Bold", 10.0 ); + // $this->glmpdfPlaceBox(1, 80, 20, 400, 20, "black", "black"); + $this->glmpdfPlaceText( html_entity_decode($voucherText,ENT_QUOTES,"utf-8"), 280, 6, "center", 'black', -370, '' ); + } + + // $this->glmpdfPlaceText( $t['ticket_date']['date'].' - '.$t['ticket_time']['time'], 120, $this->glmpdfCurrentY, "left", 'black', 0, '' ); + + // Print barcode = {ticket_sold ID}-{person type}-{person_sequence} + $barcode = $this->addCheckCode($t['id']); + + // If we're supposed to print barcode and voucher number on ticket + switch ($t['ticket_voucher_type']) { + case 11: + $this->glmpdfSetFont( "Courier-Bold", 10.0 ); + $this->glmpdfPlaceText( "Pickup ".$this->config->term->voucher->norm." at ".$this->config->term->prop->norm, 510, 88, 'left', 'red', -170, 'position=center rotate=90'); + $this->glmpdfSetFont( "Courier", 12.0 ); + $this->glmpdfPlaceText( $this->config->term->voucher->cap." $barcode", 540, 88, 'left', 'black', -170, 'position=center rotate=90'); + break; + case 12; + $this->glmpdfSetFont( "Courier-Bold", 10.0 ); + $this->glmpdfPlaceText( "You will receive ".$this->config->term->voucher->cap." by mail", 510, 88, 'left', 'red', -170, 'position=center rotate=90'); + $this->glmpdfSetFont( "Courier", 12.0 ); + $this->glmpdfPlaceText( $this->config->term->voucher->cap." $barcode", 540, 88, 'left', 'black', -170, 'position=center rotate=90'); + break; + case 1: + default: + $this->glmpdfSetFont( 'barcode', 40 ); + $this->glmpdfPlaceText( "*$barcode*", 510, 88, 'left', 'black', 0, 'position=center rotate=90'); + $this->glmpdfSetFont( "Courier", 10.0 ); + $this->glmpdfPlaceText( $this->config->term->voucher->cap." $barcode", 540, 88, 'left', 'black', -224, 'position=center rotate=90'); + break; + } + + $this->glmpdfPlaceText( "Order #".$order['id'], 552, 88, 'left', 'black', 0, 'position=center rotate=90'); + + // Display Footer + $this->glmpdfSetFont( "Helvetica-Bold", 8.5 ); + $this->glmpdfPlaceText( $footer, 140.5, 2, "center", 'darkblue' ); + + + // Print a normal voucher + } else { + + // If the first voucher page hasn't been set + if (!$voucherPageStarted) { + $this->glmpdfNextPage(); + $voucherPageStarted = true; + + if ($doDashes) { + // Print perforations + $this->glmpdfPlaceLine(1, 0, -11, 560, -11, $color = "dimgray", $dash = true, $d_a = 1, $d_b = 5); + $this->glmpdfPlaceLine(1, 0, -265, 560, -265, $color = "dimgray", $dash = true, $d_a = 1, $d_b = 5); + $doDashes = false; + } + + } + + $displaying_this_voucher = true; + + if ($numb_tickets++ > 0) { + + if ($skipNextFormAdvance) { + $skipNextFormAdvance = false; + } else { + $this->glmpdfNextForm(); + } + } + $this->glmpdfPlaceBox( $this->borderWidth, 0, 232, 560, 232, $this->borderColor ); + + // Display Logo - Only get performance image if it's not currently loaded + if ($performanceLoaded != $t['performance']) { + + $performanceDetail = $Performances->getPerformanceDetail($t['performance']); + + // If we have an image but it's the wrong one, dump the temp file + if ($performanceImageFile) { + unlink($performanceImageFile); + } + + // This performance image is not currently loaded - so do that now + + $performanceImageFile = $this->is->saveImageToTemp(IMAGE_SERVER_PREFIX.'original/'.$performanceDetail['image']); + if ($performanceImageFile) { + // If we have the image, then load it + $performanceImage = $this->glmpdfOpenImage($performanceImageFile); + $performanceLoaded = $t['performance']; + } else { + + // otherwise, try the venue image + $performanceLoaded = $venueImage; + } + + } + + // If we have the performance image, display it + $haveTopImage = false; + if ($performanceImage) { + $this->glmpdfPlaceImage( $performanceImage, 85, 154, 1, 'meet', 'center', 70, 75); + $haveTopImage = true; + } elseif ($venueImageFile) { + $this->glmpdfPlaceImage($coverImage, 85, 154, 1, 'meet', 'center', 70, 75); + $haveTopImage = true; + } + + // Place owner name at top possitioned by whether or not there's an image supplied + $this->glmpdfSetFont( "Helvetica-Bold", 20.0 ); + if ($haveTopImage) { + $this->glmpdfPlaceText( $config->owner->name, 315, 185, "center", 'black', -300, ''); + } else { + $this->glmpdfPlaceText( $config->owner->name, 280, 185, "center", 'black', -350, ''); + } + + // If ticket has already been claimed, then mark ticket + if ($t['time_claimed']['date'] != '') { + $this->glmpdfSetFont( "Times-Bold", 72.0 ); + $this->glmpdfPlaceText( "CLAIMED", 110, 80, "left", 'orangered', 0, '' ); // last parameter can be things like "rotate=90" + } + + // Ticket Information Area + $this->glmpdfPlaceLine(1, 80, 0, 80, 232, $color = "black", $dash = false, $d_a = 1, $d_b = 1); + $this->glmpdfPlaceLine(1, 480, 0, 480, 232, $color = "black", $dash = false, $d_a = 1, $d_b = 1); + + // If part of a package, print the package name it's part of. + if ($packageTicketName && !$t['is_package']['value']) { + + $this->glmpdfSetFont( "Helvetica-Bold", 10.0 ); + $this->glmpdfPlaceText( 'Part of:', 7, 40, 'left', 'black', 0, 'position=center rotate=90'); + $this->glmpdfSetFont( "Helvetica-Bold", 16.0 ); + $this->glmpdfPlaceText( $packagePerformanceName, 30, 116, 'left', 'black', -224, 'position=center rotate=90'); + $this->glmpdfPlaceText( $packageTicketName, 60, 116, 'left', 'black', -224, 'position=center rotate=90'); + + } else { + + // Voucher left end text overrides departing from text + if ($t['ticket_voucher_leftend_text'] != '') { + $this->glmpdfPlaceBox(1, 0, 0, 80, -232, '', 'lightlilac', 'miter'); + $this->glmpdfSetFont( "Helvetica-Bold", 16.0 ); + $this->glmpdfPlaceText( strtoupper(html_entity_decode($t['ticket_voucher_leftend_text'],ENT_QUOTES,"utf-8")), 40, 116, 'left', 'black', -224, 'position=center rotate=90'); + } else { + // Left End of Ticket - NOTE: use only "left" in glmpdfPlaceText - use "position=..." in optlist instead. + if (($t['entrance']-0) > 0) { + $entranceDetail = $Entrances->getEntranceDetail($t['entrance']); + $this->glmpdfPlaceBox(1, 0, 0, 80, -232, '', $entranceDetail['color']['name'], 'miter'); + } + + $this->glmpdfSetFont( "Helvetica-Bold", 10.0 ); + $this->glmpdfPlaceText( 'Departing from:', 7, 40, 'left', 'black', 0, 'position=center rotate=90'); + $this->glmpdfSetFont( "Helvetica-Bold", 16.0 ); +// $this->glmpdfPlaceText( strtoupper(html_entity_decode($t['entrance_name'],ENT_QUOTES,"utf-8")), 30, 116, 'left', 'black', -224, 'position=center rotate=90'); + $this->glmpdfPlaceText( strtoupper(html_entity_decode($t['member_name'],ENT_QUOTES,"utf-8")), 45, 116, 'left', 'black', -224, 'position=center rotate=90'); + } + } + + // Display values + $this->glmpdfSetFont( "Helvetica-Bold", 20.0 ); + $this->glmpdfPlaceText( html_entity_decode($t['real_member_name'],ENT_QUOTES,"utf-8"), 280, 135, "center", 'black', -370, ''); + $this->glmpdfSetFont( "Helvetica-Bold", 18.0 ); + $this->glmpdfPlaceText( html_entity_decode($t['ticket_name'],ENT_QUOTES,"utf-8"), 280, 114, "center", 'black', -370, '' ); + + $this->glmpdfSetFont( "Helvetica", 14.0 ); + if ($t['date_specific']['value']) { + + $datetime = $t['ticket_date']['date']; + if ($t['time_specific']['value']) { + $datetime .= ' '.$t['ticket_time']['time']; + } +// $this->glmpdfPlaceText( $t['ticket_date']['date'], 280, 96, "center", 'black', -370, '' ); + $this->glmpdfPlaceText( $datetime, 280, 96, "center", 'black', -370, '' ); + } else { + $dateRange = 'Valid From '.$t['start_date']['date'].' through '.$t['end_date']['date']; + $this->glmpdfPlaceText( $dateRange, 280, 96, "center", 'black', -370, '' ); + } + + $this->glmpdfSetFont( "Helvetica", 16.0 ); + + // Put package line for voucher here + + // Check for Ticket add-ons + if (isset($t['addons_sold']) && count($t['addons_sold']) > 0) { + $this->glmpdfSetFont( "Helvetica", 14.0 ); + foreach($t['addons_sold'] as $a) { + $addonText = $a['add_on_name']; + if (($a['add_on_type']['value']-0) == 2) { + $addonText = $addonText.', '.$a['quant'].' '.$a['unit_name']; + } + $this->glmpdfPlaceText( $addonText, 280, $this->glmpdfCurrentY, "center", 'black', -370, '' ); + } + } + + // Non-Refundable and other Fixed text for body of Voucher + $this->glmpdfSetFont( "Helvetica", 12.0 ); + $this->glmpdfPlaceText( "NON-REFUNDABLE", 280, $this->glmpdfCurrentY, "center", 'black', -300, ''); + + // Display address and contact information + $this->glmpdfSetFont( "Helvetica", 12.0 ); + $contactInfo = $this->config->owner->name.' - ' + .$this->config->owner->address1.' - ' + .($this->config->owner->address2 != '' ? ', '.$this->config->owner->address2 : '') + .$this->config->owner->city.', ' + .$this->config->owner->state.' ' + .$this->config->owner->zip.' - ' + .$this->config->owner->phone + .($this->config->owner->toll_free != '' ? ' - '.$this->config->owner->toll_free : ''); + $this->glmpdfPlaceText( html_entity_decode($contactInfo,ENT_QUOTES,"utf-8"), 280, 25, "center", 'black', -380, ''); + + // Display additional voucher text at the bottom of the voucher if provided + $voucherText = ''; + if (trim($t['ticket_voucher_text']) != '') { + $voucherText = trim(html_entity_decode($t['ticket_voucher_text'],ENT_QUOTES,"utf-8")); + } elseif (trim($performanceDetail['voucher_text']) != '') { + $voucherText = trim(html_entity_decode($performanceDetail['voucher_text'],ENT_QUOTES,"utf-8")); + } + if ($voucherText != '') { + $this->glmpdfPlaceLine(1, 80, 20, 480, 20, 'black', false); + $this->glmpdfSetFont( "Helvetica-Bold", 14.0 ); + // $this->glmpdfPlaceBox(1, 80, 20, 400, 20, "black", "black"); + $this->glmpdfPlaceText( html_entity_decode($voucherText,ENT_QUOTES,"utf-8"), 280, 6, "center", 'black', -370, '' ); + } + + // $this->glmpdfPlaceText( $t['ticket_date']['date'].' - '.$t['ticket_time']['time'], 120, $this->glmpdfCurrentY, "left", 'black', 0, '' ); + + // Print barcode = {ticket_sold ID}-{person type}-{person_sequence} + $barcode = $this->addCheckCode($t['id']); + + // If we're supposed to print barcode and voucher number on ticket + switch ($t['ticket_voucher_type']) { + case 11: + $this->glmpdfSetFont( "Courier-Bold", 12.0 ); + $this->glmpdfPlaceText( "Pickup ".$this->config->term->voucher->norm." at ".$this->config->term->prop->norm, 510, 116, 'left', 'red', -224, 'position=center rotate=90'); + $this->glmpdfSetFont( "Courier", 12.0 ); + $this->glmpdfPlaceText( $this->config->term->voucher->cap." $barcode", 540, 116, 'left', 'black', -224, 'position=center rotate=90'); + break; + case 12; + $this->glmpdfSetFont( "Courier-Bold", 12.0 ); + $this->glmpdfPlaceText( "You will receive ".$this->config->term->voucher->cap." by mail", 510, 116, 'left', 'red', -224, 'position=center rotate=90'); + $this->glmpdfSetFont( "Courier", 12.0 ); + $this->glmpdfPlaceText( $this->config->term->voucher->cap." $barcode", 540, 116, 'left', 'black', -224, 'position=center rotate=90'); + break; + case 1: + default: + $this->glmpdfSetFont( 'barcode', 48 ); + $this->glmpdfPlaceText( "*$barcode*", 510, 116, 'left', 'black', 0, 'position=center rotate=90'); + $this->glmpdfSetFont( "Courier", 12.0 ); + $this->glmpdfPlaceText( $this->config->term->voucher->cap." $barcode", 540, 116, 'left', 'black', -224, 'position=center rotate=90'); + break; + } + + $this->glmpdfPlaceText( "Order #".$order['id'], 552, 116, 'left', 'black', 0, 'position=center rotate=90'); + + // Display Footer + $this->glmpdfSetFont( "Helvetica-Bold", 8.5 ); + $this->glmpdfPlaceText( $footer, 140.5, 2, "center", 'darkblue' ); + + } // End of normal voucher + + } // Printing Voucher + + } + + if ($displaying_this_voucher) { + + if (!$packageVouchersPrintedSeparately) { + + $this->glmpdfNextForm(); + + // Get table of Ads/Coupons + if (isset($vc[1])) { + + // Get the key for the current ad/coupon for position 1 + $k = key($vc[1]); + + // If the max count is -1 (unlimited) or more than the current display count + if ($vc[1][$k]['max_display_count'] < 0 || $vc[1][$k]['max_display_count'] > $vc[1][$k]['display_count']) { + + // Display the ad/coupon and save SQL to update the display count + $counterSQL .= $this->displayCoupon(current($vc[1]), 375, 150); + + // Incriment the local display count + $vc[1][$k]['display_count']++; + } + + // Advance to the next ad/coupon for this position. If all used, start over. + if (next($vc[1]) === false) { + reset($vc[1]); + } + } + + // Advance to the next form + $this->glmpdfNextForm(); + + // Do the same for the remaining ad/coupon forms + + if (isset($vc[2])) { + $k = key($vc[2]); + if ($vc[2][$k]['max_display_count'] < 0 || $vc[2][$k]['max_display_count'] > $vc[2][$k]['display_count']) { + $counterSQL .= $this->displayCoupon(current($vc[2]), 170, 150); + $vc[2][$k]['display_count']++; + } + if (next($vc[2]) === false) { + reset($vc[2]); + } + } + $this->glmpdfNextForm(); + + if (isset($vc[3])) { + $k = key($vc[3]); + if ($vc[3][$k]['max_display_count'] < 0 || $vc[3][$k]['max_display_count'] > $vc[3][$k]['display_count']) { + $counterSQL .= $this->displayCoupon(current($vc[3]), 170, 150); + $vc[3][$k]['display_count']++; + } + if (next($vc[3]) === false) { + reset($vc[3]); + } + } + $this->glmpdfNextForm(); + + if (isset($vc[4])) { + $k = key($vc[4]); + if ($vc[4][$k]['max_display_count'] < 0 || $vc[4][$k]['max_display_count'] > $vc[4][$k]['display_count']) { + $counterSQL .= $this->displayCoupon(current($vc[4]), 375, 150); + $vc[4][$k]['display_count']++; + } + if (next($vc[4]) === false) { + reset($vc[4]); + } + } + $this->glmpdfNextForm(); + + if (isset($vc[5])) { + $k = key($vc[5]); + if ($vc[5][$k]['max_display_count'] < 0 || $vc[5][$k]['max_display_count'] > $vc[5][$k]['display_count']) { + $counterSQL .= $this->displayCoupon(current($vc[5]), 137, 120); + $vc[5][$k]['display_count']++; + } + if (next($vc[5]) === false) { + reset($vc[5]); + } + } + $this->glmpdfNextForm(); + + if (isset($vc[6])) { + $k = key($vc[6]); + if ($vc[6][$k]['max_display_count'] < 0 || $vc[6][$k]['max_display_count'] > $vc[6][$k]['display_count']) { + $counterSQL .= $this->displayCoupon(current($vc[6]), 137, 120); + $vc[6][$k]['display_count']++; + } + if (next($vc[6]) === false) { + reset($vc[6]); + } + } + $this->glmpdfNextForm(); + + if (isset($vc[7])) { + $k = key($vc[7]); + if ($vc[7][$k]['max_display_count'] < 0 || $vc[7][$k]['max_display_count'] > $vc[7][$k]['display_count']) { + $counterSQL .= $this->displayCoupon(current($vc[7]), 137, 120); + $vc[7][$k]['display_count']++; + } + if (next($vc[7]) === false) { + reset($vc[7]); + } + } + $this->glmpdfNextForm(); + + if (isset($vc[8])) { + $k = key($vc[8]); + if ($vc[8][$k]['max_display_count'] < 0 || $vc[8][$k]['max_display_count'] > $vc[8][$k]['display_count']) { + $counterSQL .= $this->displayCoupon(current($vc[8]), 137, 120); + $vc[8][$k]['display_count']++; + } + if (next($vc[8]) === false) { + reset($vc[8]); + } + } + $this->glmpdfNextForm(); + + if (isset($vc[9])) { + $k = key($vc[9]); + if ($vc[9][$k]['max_display_count'] < 0 || $vc[9][$k]['max_display_count'] > $vc[9][$k]['display_count']) { + $counterSQL .= $this->displayCoupon(current($vc[9]), 419, 120); + $vc[9][$k]['display_count']++; + } + if (next($vc[9]) === false) { + reset($vc[9]); + } + } + } + } + + } // Each voucher + + if ($vc != false) { + $this->dbh->exec("BEGIN;\n".$counterSQL."COMMIT;\n"); + } + + // Close PDF setup and send to user's browser + $this->glmpdfSendToBrowser( '', 'Star_Line_Ticket_Vouchers.pdf' ); + + if ($venueImageFile) { + unlink($venueImageFile); + } + if ($parkingImageFile) { + unlink($parkingImageFile); + } + if ($sectionImageFile) { + unlink($sectionImageFile); + } + if ($sectionImageFile) { + unlink($sectionImageFile); + } + + } + + private function displayCoupon($coupon, $xs, $ys) + { + + // Attempt to get the coupon image + $im = $this->getCouponImage( $this->is, $coupon['coupon_image']); + + // Check for stretch + $fit = 'auto'; + if ($coupon['stretch_to_fit']['value']) { + $fit = 'entire'; + } + + // Check for padding - enforce a minimum size + $pad = $coupon['padding']; + + $x = $xs - ($pad * 2); + if ($x < 10) { + $x == 10; + } + $y = $ys - ($pad * 2); + if ($y < 10) { + $y = 10; + } + + // If the image exists + if ($im) { + + // Place the image + $this->glmpdfPlaceImage($im, $pad, $pad, 1, $fit, 'center', $x, $y); + + + // If a border is requested display that + if ($coupon['show_border']['value']) { + $this->glmpdfPlaceBox( $this->borderWidth, 0, $ys, $xs, $ys, $this->borderColor ); + } + + } + + // SQL to Update Counters + $sql = "UPDATE eventmgt.voucher_coupons SET display_count = display_count + 1 WHERE id = ".$coupon['id'].";\n"; + + return $sql; + + } + + /* + * Function to load an image for use in Voucher Ads or Coupons + * + * This function maintains a static array of loaded images. It + * first checks to see if the image has already been loaded and + * returns the existing object if it is. Otherwise it will + * attempt to load the image, store the open image object in the + * static array for future use, and return it. + * + * @param $is object Image Server Object + * @param $imageName string Name of the image to load + * + * @return object Loaded and opened image object or false if not loaded + * + */ + private function getCouponImage( $is, $imageName ) + { + static $images = array(); + + // Check if image has already been loaded + if (isset($images[$imageName])) { + return $images[$imageName]; + } + + // Try to load the image + $imageFile = $is->saveImageToTemp(IMAGE_SERVER_PREFIX.'original/'.$imageName); + if ($imageFile) { + + // Open the image and save it in case it's needeed again + $images[$imageName] = $this->glmpdfOpenImage($imageFile); + + return $images[$imageName]; + + } + + return false; + + } + + /* + * Function to add check character to end of voucher number + * + * Uses config->voucher_check_secret and voucher # to create MD5 string + * then takes last hex character off of that string and shifts it up to + * always be a character (adds 16 to numbers and 10 to the upper-case + * version of the character). + * i.e. 0 = A, 9 = J, A = K, F = + * + */ + public function addCheckCode($voucherNumb) + { + + // Create MD5 string using voucher number and secret + $md5 = md5($voucherNumb.$this->config->voucher_check_secret); + + // Get last character code of the last character in the MD5 + $cc = strtoupper(substr($md5, -2)); + $cc[0] = $this->shiftCheckCodeCharacter($cc[0]); + $cc[1] = $this->shiftCheckCodeCharacter($cc[1]); + + // Return voucher number with the new character on the end + $voucherNumb .= $cc; + return $voucherNumb; + + } + + private function shiftCheckCodeCharacter($c) { + + $x = ord($c); + + // If it's a digit, add 16 + if ($x < 65) { + $x += 17; + // otherwise, add 10 + } else { + $x += 10; + } + + // Also skip the letter O + if (x >= ord('O')) { + $x += 1; + } + + return chr($x); + } + +} // class + +// Absolutely nothing after next line +?> diff --git a/models/vouchers/MMM/voucher.php.SAVE b/models/vouchers/MMM/voucher.php.SAVE new file mode 100644 index 0000000..a80de57 --- /dev/null +++ b/models/vouchers/MMM/voucher.php.SAVE @@ -0,0 +1,614 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: printVoucher.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +require_once PDF_ABSTRACT; +$Pdf = new GlmPdf(); + +/** + * PdfVoucher class + * + * @category PdfVoucher + * @package PDFLib + * @author Chuck Scott + * @license http://www.gaslightmedia.com Gaslightmedia + * @link <> +*/ +class PdfVoucher extends GlmPdf +{ + + public $borderWidth = 1; + public $borderColor = 'black'; + public $pdfCouponInterval = 5; + public $pdfMinCoupons = 3; + public $config; + public $companyContact = false; + public $venueContact = false; + + function __construct($order, $vouchers, $member, $dbh, $config) + { + + $this->config = $config; + + // if debug.glmpdf is set in the configs/common.ini file in the CommonApp directory, do grids on PDFs + define ('GLMPDF_DEBUG', $this->config->debug->glmpdf); + + // The following produces a color test sheet. There is no return from that call. + // $this->glmpdfShowValidColors(); + + // Start with cover page. + $this->glmpdfSetForms( + 1, + array( + 1 => array( 'x' => 0, 'y' => 0, 'xs' => 613, 'ys' => 792 ) + ), + 'US Letter' + ); + + // Start page + $this->glmpdfStart( $this->config->owner->name, "Michigan Maritime Museum", "Ticket System Receipt/Vouchers" ); + + if( !$this->glmpdfAddFont( 'barcode', 'barcode/FREE3OF9.TTF' ) ) + { + echo 'ERROR: Unable to add barcode font.

    + Did you place the barcode font provided in docs/BarcodeFonts into + a system fonts directory ("/usr/share/fonts/truetype/Barcode")? + Also check the GLMPDF_PDF_FONT_DIR setting in GlmPdf.php.'; + exit; + } + + // If coupon test is selected, print them all now. + if( isset($_REQUEST['test_coupons']) ) + { + for( $i=1 ; $i<=count($coupons) ; $i++ ) + $this->printCoupon( $i ); + + glmpdf_send_to_browser( '', 'voucher.pdf' ); + exit; + } + + // Get images to tmp files + require_once IMAGE_SERVER_ABSTRACT; + $imServer = new ImageServerAbstract(); + + if (trim($member['image']) != '') { + $venueImageFile = $imServer->saveImageToTemp(IMAGE_SERVER_PREFIX.'original/'.$member['image']); + if ($venueImageFile) { + $venueImage = $this->glmpdfOpenImage($venueImageFile); + + // If failure getting the image + if ($venueImage == false) { + $venueImageFile = false; + } + } + } else { + $venueImageFile = false; + } + + if (trim($member['parking_map']) != '') { + $parkingImageFile = $imServer->saveImageToTemp(IMAGE_SERVER_PREFIX.'original/'.$member['parking_map']); + if ($parkingImageFile) { + $parkingImage = $this->glmpdfOpenImage($parkingImageFile); + + // If failure getting the image + if ($parkingImage == false) { + $parkingImageFile = false; + } + } + } else { + $parkingImageFile = false; + } + + if (trim($member['ticket_sec_map']) != '') { + $sectionImageFile = $imServer->saveImageToTemp(IMAGE_SERVER_PREFIX.'original/'.$member['ticket_sec_map']); + if ($sectionImageFile) { + $sectionImage = $this->glmpdfOpenImage($sectionImageFile); + + // If failure getting the image + if ($sectionImage == false) { + $sectionImageFile = false; + } + } + } else { + $sectionImageFile = false; + } + + // Load entrance class + require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/entrances.php'; + $Entrances = new EventManagementAdminEntrances($dbh, $config); + + // Load performance class + require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/performances.php'; + $Performances = new EventManagementAdminPerformances($dbh, $config); + + // Setup additional information + // Company contact info + if ($config->option->voucher->show_company_contact) { + $companyContact = ''; + $sep = ''; + if ($config->option->voucher->show_company_name) { + $companyContact .= $config->owner->name; + $sep = ' - '; + } + if ($config->option->voucher->show_company_addr && $config->owner->addr1) { + $companyContact .= $sep.$config->owner->addr1; + $sep = ' - '; + if ($config->owner->addr2) { + $companyContact .= ', '.$config->owner->addr2; + } + } + if ($config->option->voucher->show_company_citystate) { + $companyContact .= $sep.$config->owner->city.', '.$config->owner->state; + $sep = ' - '; + } + if ($config->option->voucher->show_company_phone) { + if ($config->owner->toll_free) { + $companyContact .= $sep.$config->owner->toll_free; + } else { + $companyContact .= $sep.$config->owner->phone; + } + } + } + // Venue/Location contact info + $venueContact = false; + if ($config->option->voucher->show_venue_contact) { + $venueContact = ''; + $sep = ''; + if ($config->option->voucher->show_venue_name) { + $venueContact .= $member['name']; + $sep = ' - '; + } + if ($config->option->voucher->show_venue_addr && $member['addr1']) { + $venueContact .= $sep.$member['addr1']; + $sep = ' - '; + if ($member['addr2']) { + $venueContact .= ', '.$member['addr2']; + } + } + if ($config->option->voucher->show_venue_citystate) { + $venueContact .= $sep.$member['city'].', '.$member['state']['name']; + $sep = ' - '; + } + if ($config->option->voucher->show_venue_phone) { + $venueContact .= $sep.$member['phone']; + } + } + + // START VOUCHER PRINTOUT + + $this->glmpdfNextForm(); + + /* Cover Page */ + + // Header + if ($venueImageFile) { + $coverImage = $this->glmpdfOpenImage($venueImageFile); + $this->glmpdfPlaceImage($coverImage, 30, 690, .5, false, 'center', 280, 140); + } + $this->glmpdfSetFont( "Helvetica-Bold", 18.0 ); // Header Text + $this->glmpdfPlaceText( $config->owner->name, 340, 750, "center", 'black', -400 ); + $this->glmpdfSetFont( "Helvetica", 14.0 ); + $this->glmpdfPlaceText( $config->owner->short_name." - ".$member['name'], 340, $this->glmpdfCurrentY-10, "center", 'black', -400 ); + $this->glmpdfPlaceText( $member['addr1'], 340, $this->glmpdfCurrentY, "center", 'black', -400 ); + $this->glmpdfPlaceText( $member['city'].", ".$member['state']['name']." ".$member['zip'], 340, $this->glmpdfCurrentY, "center", 'black', -400 ); + + // Sold To Information + $valCol = 60; + $this->glmpdfSetFont( "Helvetica", 10.0 ); + $this->glmpdfPlaceText( $this->config->term->order->cap." ID: ".trim($order['id']), $valCol, 650, "left", 'black' ); + $this->glmpdfPlaceText( trim($order['fname'].' '.$order['lname']), $valCol, $this->glmpdfCurrentY-5, "left", 'black', -200 ); + $this->glmpdfPlaceText( trim($order['addr1']), $valCol, $this->glmpdfCurrentY-5, "left", 'black', -200 ); + if( trim($order['addr2']) != '' ) + $this->glmpdfPlaceText( trim($order['addr2']), $valCol, $this->glmpdfCurrentY-5, "left", 'black', -200 ); + $this->glmpdfPlaceText( trim($order['city']).', '.$order['state']['value'].' '.trim($order['zip']).' '.$order['country']['value'], $valCol, $this->glmpdfCurrentY-5, "left", 'black', -200 ); + + // Purchace/Charge information + $this->glmpdfSetFont( "Helvetica", 10.0 ); + $promptCol = 330; + $valCol = 420; + $this->glmpdfPlaceText( "Date of Purchase:", $promptCol, 650, "left", 'black' ); + $this->glmpdfPlaceText( $order['purchase_date']['date'], $valCol, $this->glmpdfLastY, "left", 'black', -160 ); + $this->glmpdfPlaceText( "Card Type:", $promptCol, $this->glmpdfCurrentY-5, "left", 'black' ); + $this->glmpdfPlaceText( $order['cctype'], $valCol, $this->glmpdfLastY, "left", 'black', -160 ); + $this->glmpdfPlaceText( "Name on Card:", $promptCol, $this->glmpdfCurrentY-5, "left", 'black' ); + $this->glmpdfPlaceText( $order['ccname'], $valCol, $this->glmpdfLastY, "left", 'black', -160 ); + $this->glmpdfPlaceText( "Card Number:", $promptCol, $this->glmpdfCurrentY-5, "left", 'black' ); + $this->glmpdfPlaceText( $order['ccnumber'], $valCol, $this->glmpdfLastY, "left", 'black', -160 ); + $this->glmpdfPlaceText( "Confirmation:", $promptCol, $this->glmpdfCurrentY-5, "left", 'black' ); + $this->glmpdfPlaceText( $order['ccconf'], $valCol, $this->glmpdfLastY, "left", 'black', -160 ); + $this->glmpdfPlaceText( "Total Charged:", $promptCol, $this->glmpdfCurrentY-5, "left", 'black' ); + $this->glmpdfPlaceText( $order['charge_total'], $valCol, $this->glmpdfLastY, "left", 'black', -160 ); + + // Purchase Summary + $ticNumbCol = 20; + $perfNameCol = 80; + $ticNameCol = 200; + $secNameCol = 370; + $dateCol = 440; + $this->glmpdfPlaceText( '', $ticNumbCol, 550, "center", 'black', 0, ''); + + $this->glmpdfSetFont( "Helvetica", 8.0 ); + $this->glmpdfPlaceText( $this->config->term->voucher->cap, $ticNumbCol, $this->glmpdfCurrentY, "left", 'black', -52, ''); + $this->glmpdfPlaceText( $this->config->term->performance->cap, $perfNameCol, $this->glmpdfLastY, "left", 'black', -110, ''); + $this->glmpdfPlaceText( $this->config->term->ticket->cap, $ticNameCol, $this->glmpdfLastY, "left", 'black', -160, ''); + $this->glmpdfPlaceText( $this->config->term->section->cap, $secNameCol, $this->glmpdfLastY, "left", 'black', -60, ''); + $this->glmpdfPlaceText( 'Date / Time', $dateCol, $this->glmpdfLastY, "left", 'black', -160, ''); + + $this->glmpdfPlaceText( '', $ticNumbCol, $this->glmpdfCurrentY-3, "center", 'black', 0, ''); + + foreach( $vouchers as $t ) { + + $voucherCode = $this->addCheckCode($t['id']); + + $this->glmpdfSetFont( "Helvetica", 8.0 ); + $this->glmpdfPlaceText( $voucherCode, $ticNumbCol, $this->glmpdfCurrentY, "left", 'black', -52, ''); + $this->glmpdfPlaceText( html_entity_decode($t['performance_name'],ENT_QUOTES,"utf-8"), $perfNameCol, $this->glmpdfLastY, "left", 'black', -110, ''); + $this->glmpdfPlaceText( html_entity_decode($t['ticket_name'],ENT_QUOTES,"utf-8"), $ticNameCol, $this->glmpdfLastY, "left", 'black', -160, ''); + $this->glmpdfPlaceText( html_entity_decode($t['section_name'],ENT_QUOTES,"utf-8"), $secNameCol, $this->glmpdfLastY, "left", 'black', -60, ''); + if ($t['date_specific']['value']) { + $this->glmpdfPlaceText( $t['ticket_date']['date'].' '.$t['ticket_time']['time'], $dateCol, $this->glmpdfLastY, "left", 'black', -160, ''); + } else { + $dateRange = 'Valid From '.$t['start_date']['date'].' through '.$t['end_date']['date']; + $this->glmpdfPlaceText( $dateRange, $dateCol, $this->glmpdfLastY, "left", 'black', -160, ''); + } + + // Check for Ticket add-ons + if (isset($t['addons_sold']) && count($t['addons_sold']) > 0) { + foreach($t['addons_sold'] as $a) { + + $addonText = $a['add_on_name']; + if (($a['add_on_type']['value']-0) == 2) { + $addonText = $addonText.', '.$a['quant'].' '.$a['unit_name']; + } + $this->glmpdfPlaceText( html_entity_decode($addonText,ENT_QUOTES,"utf-8"), $ticNameCol+10, $this->glmpdfCurrentY, "left", 'black', -240, ''); + } + } + + } + + // Special Needs + $this->glmpdfSetFont( "Helvetica", 9.0 ); + if (trim($order['special_needs']) != '') { + $this->glmpdfPlaceText( "Special Needs:", 20, $this->glmpdfCurrentY-30, "left", 'black' ); + $this->glmpdfPlaceTextBox( $order['special_needs'], 100, $this->glmpdfCurrentY+16, 450, 50, "left", 'black' ); + } + + // General Member Policies + if (trim($member['def_ticket_pol']) != '') { + $this->glmpdfPlaceText( "Policies:", 20, $this->glmpdfCurrentY-30, "left", 'black' ); + $this->glmpdfPlaceTextBox( $member['def_ticket_pol'], 100, $this->glmpdfCurrentY+16, 450, 50, "left", 'black' ); + } + + // Now setup ticket forms + $this->glmpdfSetForms( + 1, + array( + 1 => array( 'x' => 25, 'y' => 495, 'xs' => 560, 'ys' => 275 ) +// 2 => array( 'x' => 25, 'y' => 210, 'xs' => 560, 'ys' => 275 ) + ), + 'US Letter' + ); + // Also reset form count + $this->glmpdfNextPage(); + + // Display Footer + $this->glmpdfSetFont( "Helvetica-Bold", 8.5 ); + $this->glmpdfPlaceText( $footer, 140.5, 2, "center", 'darkblue' ); +/*********CPS + // Display Parking Map + if ($parkingImage) { + $this->glmpdfNextForm(); + $this->glmpdfPlaceImage( $parkingImage, 0, 2, 0, 'meet', 'center', 280, 125); + $this->glmpdfSetFont( "Helvetica-Bold", 10.0 ); + $this->glmpdfPlaceText( 'Parking Map', 140, 130, "center", 'black' ); + } + + // Display Section Map + if ($sectionImage) { + $this->glmpdfNextForm(); + $this->glmpdfPlaceImage( $sectionImage, 0, 2, 0, 'meet', 'center', 280, 125); + $this->glmpdfSetFont( "Helvetica-Bold", 10.0 ); + $this->glmpdfPlaceText( 'Section Map', 140, 130, "center", 'black' ); + } +*/ + + // Load mask for darkening the bottom portion of the tickets +// $ticketMask = $this->glmpdfOpenImage(EVENT_MANAGEMENT_APP_BASE.'web/custom/greatlakesbaymag/assets/ticket-gradient.png'); + + // Clear performance image loaded flag + $performanceLoaded = false; + + // Process Vouchers - For each type of ticket purchased + $numb_tickets = 0; + foreach( $vouchers as $t ) + { + + if ($numb_tickets++ > 0) { + $this->glmpdfNextForm(); + } + $this->glmpdfPlaceBox( $this->borderWidth, 0, 275, 560, 275, $this->borderColor ); + + // Display Logo - Only get performance image if it's not currently loaded + if ($performanceLoaded != $t['performance']) { + + $performanceDetail = $Performances->getPerformanceDetail($t['performance']); + + // If we have an image but it's the wrong one, dump the temp file + if ($performanceImageFile) { + unlink($performanceImageFile); + } + + // This performance image is not currently loaded - so do that now + + $performanceImageFile = $imServer->saveImageToTemp(IMAGE_SERVER_PREFIX.'original/'.$performanceDetail['image']); + if ($performanceImageFile) { + // If we have the image, then load it + $performanceImage = $this->glmpdfOpenImage($performanceImageFile); + $performanceLoaded = $t['performance']; + } else { + + // otherwise, try the venue image + $performanceLoaded = $venueImage; + } + + } + + // If we have the performance image, display it + $haveTopImage = false; + if ($performanceImage) { + $this->glmpdfPlaceImage( $performanceImage, 85, 195, 1, 'meet', 'center', 70, 75); + $haveTopImage = true; + } elseif ($venueImageFile) { + $this->glmpdfPlaceImage($coverImage, 85, 195, 1, 'meet', 'center', 70, 75); + $haveTopImage = true; + } + + // Place owner name at top possitioned by whether or not there's an image supplied + $this->glmpdfSetFont( "Helvetica-Bold", 24.0 ); + if ($haveTopImage) { + +// $this->glmpdfPlaceText( $config->owner->name, 315, 227, "center", 'black', -300, ''); + $this->glmpdfPlaceText( html_entity_decode($t['member_name'],ENT_QUOTES,"utf-8"), 315, 227, "center", 'black', -300, ''); + } else { +// $this->glmpdfPlaceText( $config->owner->name, 280, 227, "center", 'black', -350, ''); + $this->glmpdfPlaceText( html_entity_decode($t['member_name'],ENT_QUOTES,"utf-8"), 280, 227, "center", 'black', -350, ''); + } + + // Place mask + //$this->glmpdfPlaceImage($ticketMask, 0, 52, .25, false, 'center', 280, 140); + + // If ticket has already been claimed, then mark ticket + if ($t['time_claimed']['date'] != '') { + $this->glmpdfSetFont( "Times-Bold", 72.0 ); + $this->glmpdfPlaceText( "CLAIMED", 110, 80, "left", 'orangered', 0, '' ); // last parameter can be things like "rotate=90" + } + + // Ticket Information Area + $this->glmpdfSetFont( "Helvetica-Bold", 24.0 ); + $this->glmpdfPlaceLine(1, 80, 0, 80, 275, $color = "black", $dash = false, $d_a = 1, $d_b = 1); + $this->glmpdfPlaceLine(1, 480, 0, 480, 275, $color = "black", $dash = false, $d_a = 1, $d_b = 1); + + // Left End of Ticket - NOTE: use only "left" in glmpdfPlaceText - use "position=..." in optlist instead. + if (($t['entrance']-0) > 0) { + $entranceDetail = $Entrances->getEntranceDetail($t['entrance']); + $this->glmpdfPlaceBox(1, 0, 0, 80, -275, '', $entranceDetail['color']['name'], 'miter'); + } + $this->glmpdfSetFont( "Helvetica-Bold", 10.0 ); +// $this->glmpdfPlaceText( 'Departing from:', 7, 40, 'left', 'black', 0, 'position=center rotate=90'); + $this->glmpdfSetFont( "Helvetica-Bold", 20.0 ); + $this->glmpdfPlaceText( strtoupper(html_entity_decode($t['entrance_name'],ENT_QUOTES,"utf-8")), 40, 138, 'left', 'black', -250, 'position=center rotate=90'); +// $this->glmpdfPlaceText( strtoupper(html_entity_decode($t['member_name'],ENT_QUOTES,"utf-8")), 60, 138, 'left', 'black', -250, 'position=center rotate=90'); + + // Display values + $this->glmpdfSetFont( "Helvetica-Bold", 26.0 ); + $this->glmpdfPlaceText( html_entity_decode($t['performance_name'],ENT_QUOTES,"utf-8"), 280, 170, "center", 'black', -370, ''); + $this->glmpdfSetFont( "Helvetica-Bold", 24.0 ); + $this->glmpdfPlaceText( html_entity_decode($t['ticket_name'],ENT_QUOTES,"utf-8"), 280, 140, "center", 'black', -370, '' ); + $this->glmpdfSetFont( "Helvetica-Bold", 20.0 ); +// $this->glmpdfPlaceText( html_entity_decode($t['section_name'],ENT_QUOTES,"utf-8"), 280, 130, "center", 'black', -370, '' ); + $this->glmpdfSetFont( "Helvetica", 18.0 ); + if ($t['date_specific']['value']) { + $thisTime = ''; + if ($t['time_specific']['value']) { + $thisTime = ' - '.$t['ticket_time']['time']; + } + $this->glmpdfPlaceText( $t['ticket_date']['date'].$thisTime, 280, 110, "center", 'black', -370, '' ); + } else { + $dateRange = 'Valid From '.$t['start_date']['date'].' through '.$t['end_date']['date']; + $this->glmpdfPlaceText( $dateRange, 280, 110, "center", 'black', -370, '' ); + } + + $this->glmpdfSetFont( "Helvetica", 16.0 ); + + // Check for Ticket add-ons + if (isset($t['addons_sold']) && count($t['addons_sold']) > 0) { + $this->glmpdfSetFont( "Helvetica", 14.0 ); + foreach($t['addons_sold'] as $a) { + $addonText = $a['add_on_name']; + if (($a['add_on_type']['value']-0) == 2) { + $addonText = $addonText.', '.$a['quant'].' '.$a['unit_name']; + } + $this->glmpdfPlaceText( $addonText, 280, $this->glmpdfCurrentY, "center", 'black', -370, '' ); + } + } + + // Display NON-REFUNDABLE MESSAGE + $this->glmpdfSetFont( "Helvetica", 14.0 ); + $this->glmpdfPlaceText( "NON-REFUNDABLE", 280, $this->glmpdfCurrentY, "center", 'black', -300, ''); + + // Display address and contact information + if ($venueContact) { + $this->glmpdfSetFont( "Helvetica", 10.0 ); + $this->glmpdfPlaceText( html_entity_decode($this->config->term->prop->cap.' contact information',ENT_QUOTES,"utf-8"), 280, $this->glmpdfCurrentY-5, "center", 'black', -300, ''); + $this->glmpdfPlaceText( html_entity_decode($venueContact,ENT_QUOTES,"utf-8"), 280, $this->glmpdfCurrentY, "center", 'black', -300, ''); + } + + // Display address and contact information + if ($companyContact) { + $this->glmpdfSetFont( "Helvetica", 10.0 ); + $this->glmpdfPlaceText( html_entity_decode($companyContact,ENT_QUOTES,"utf-8"), 280, 25, "center", 'black', -380, ''); + } + + // Display additional voucher text at the bottom of the voucher if provided + $voucherText = ''; + if (trim($t['ticket_voucher_text']) != '') { + $voucherText = trim(html_entity_decode($t['ticket_voucher_text'],ENT_QUOTES,"utf-8")); + } elseif (trim($performanceDetail['voucher_text']) != '') { + $voucherText = trim(html_entity_decode($performanceDetail['voucher_text'],ENT_QUOTES,"utf-8")); + } + if ($voucherText != '') { + $this->glmpdfPlaceLine(1, 80, 20, 480, 20, 'black', false); + $this->glmpdfSetFont( "Helvetica-Bold", 14.0 ); +// $this->glmpdfPlaceBox(1, 80, 20, 400, 20, "black", "black"); + $this->glmpdfPlaceText( html_entity_decode($voucherText,ENT_QUOTES,"utf-8"), 280, 6, "center", 'black', -370, '' ); + } + + // $this->glmpdfPlaceText( $t['ticket_date']['date'].' - '.$t['ticket_time']['time'], 120, $this->glmpdfCurrentY, "left", 'black', 0, '' ); + + // Print barcode = {ticket_sold ID}-{person type}-{person_sequence} + $barcode = $this->addCheckCode($t['id']); + // If we're supposed to print barcode and voucher number on ticket + switch ($t['ticket_voucher_type']) { + + case 11: // Voucher/Ticket for Pickup - no Barcode + $this->glmpdfSetFont( "Helvetica-Bold", 20.0 ); + $this->glmpdfPlaceText( "Pickup at ".$this->config->term->prop->norm, 510, 140, 'left', 'black', -260, 'position=center rotate=90'); + $this->glmpdfSetFont( "Courier", 12.0 ); + $this->glmpdfPlaceText( $this->config->term->voucher->cap." $barcode", 540, 140, 'left', 'black', -260, 'position=center rotate=90'); + break; + + case 12; // Voucher/Ticket to be mailed Mailed - no Barcode + case 82; // Object Sold (i.e. books) to be mailed - no Barcode + $this->glmpdfSetFont( "Helvetica-Bold", 20.0 ); + $this->glmpdfPlaceText( "You will receive this by mail", 510, 140, 'left', 'black', -260, 'position=center rotate=90'); + $this->glmpdfSetFont( "Courier", 12.0 ); + $this->glmpdfPlaceText( $this->config->term->voucher->cap." $barcode", 540, 140, 'left', 'black', -260, 'position=center rotate=90'); + break; + + case 1: // Standard Voucher/Ticket with Barcode + case 81; // Object Sold (i.e. books) to be claimed - with Barcode + default: + $this->glmpdfSetFont( 'barcode', 54 ); + $this->glmpdfPlaceText( "*$barcode*", 510, 140, 'left', 'black', 0, 'position=center rotate=90'); + $this->glmpdfSetFont( "Courier", 12.0 ); + $this->glmpdfPlaceText( $this->config->term->voucher->cap." $barcode", 540, 140, 'left', 'black', -260, 'position=center rotate=90'); + break; + + } + + $this->glmpdfPlaceText( "Order #".$order['id'], 552, 140, 'left', 'black', 0, 'position=center rotate=90'); + + // Check if we need to display a coupon + if( ++$numb_tickets % $this->pdfCouponInterval == 0 ) + $this->printCoupon(); + + } // Each voucher + + // Make sure we print the minimum number of coupons + $numb_coupons = 0; + while( $numb_coupons < $this->pdfMinCoupons ) { + $this->printCoupon(); + $numb_coupons++; + } + + // Close PDF setup and send to user's browser + $this->glmpdfSendToBrowser( '', 'voucher.pdf' ); + + if ($venueImageFile) { + unlink($venueImageFile); + } + if ($parkingImageFile) { + unlink($parkingImageFile); + } + if ($sectionImageFile) { + unlink($sectionImageFile); + } + if ($sectionImageFile) { + unlink($sectionImageFile); + } + + } + + + // function to print a coupon + function printCoupon() + { + // Print a Coupon + $this->glmpdfNextForm(); + $this->glmpdfPlaceBox( $this->borderWidth, 0, 142, 281, 142, $this->borderColor ); + + // Place Coupon Image + $this->glmpdfSetFont( "Helvetica-Bold", 10.0 ); + $this->glmpdfPlaceText( 'Coupon Title', 85, 130, "center", 'black' ); + $this->glmpdfPlaceText( 'Expires on: 1/1/2020', 85, 75 ); + $this->glmpdfSetFont( "Times-Bold", 30.0 ); + $this->glmpdfPlaceText( "COUPON", 85, 95, "center", 'lightgrey' ); + $this->glmpdfSetFont( "Helvetica", 8.0 ); + $this->glmpdfPlaceTextBox( 'This is a coupon description. It describes this coupon.', 5, 55, 274, 40, "left", 'black' ); + $this->glmpdfSetFont( "Helvetica-Bold", 8.5 ); + $this->glmpdfPlaceText( "Michigan Maritime Museum - South Haven, MI - 269-637-8078", 144.5, 2, "center", 'darkblue' ); + + } + + /* + * Function to add check character to end of voucher number + * + * Uses config->voucher_check_secret and voucher # to create MD5 string + * then takes last hex character off of that string and shifts it up to + * always be a character (adds 16 to numbers and 10 to the upper-case + * version of the character). + * i.e. 0 = A, 9 = J, A = K, F = + * + */ + public function addCheckCode($voucherNumb) + { + + // Create MD5 string using voucher number and secret + $md5 = md5($voucherNumb.$this->config->voucher_check_secret); + + // Get last character code of the last character in the MD5 + $cc = strtoupper(substr($md5, -2)); + $cc[0] = $this->shiftCheckCodeCharacter($cc[0]); + $cc[1] = $this->shiftCheckCodeCharacter($cc[1]); + + // Return voucher number with the new character on the end + $voucherNumb .= $cc; + return $voucherNumb; + + } + + private function shiftCheckCodeCharacter($c) { + + $x = ord($c); + + // If it's a digit, add 16 + if ($x < 65) { + $x += 17; + // otherwise, add 10 + } else { + $x += 10; + } + + // Also skip the letter O + if (x >= ord('O')) { + $x += 1; + } + + return chr($x); + } + +} // class + +// Absolutely nothing after next line +?> diff --git a/models/vouchers/MackinacFerry/voucher.php b/models/vouchers/MackinacFerry/voucher.php new file mode 100644 index 0000000..b999c87 --- /dev/null +++ b/models/vouchers/MackinacFerry/voucher.php @@ -0,0 +1,1133 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: printVoucher.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +require_once PDF_ABSTRACT; +$Pdf = new GlmPdf(); + +/** + * PdfVoucher class + * + * @category PdfVoucher + * @package PDFLib + * @author Chuck Scott + * @license http://www.gaslightmedia.com Gaslightmedia + * @link <> +*/ +class PdfVoucher extends GlmPdf +{ + + public $borderWidth = 1; + public $borderColor = 'black'; + public $pdfCouponInterval = 5; + public $pdfMinCoupons = 3; + public $config; + private $is; + private $dbh; + + function __construct($order, $vouchers, $member, $dbh, $config, $couponTest = false) + { + + $this->dbh = $dbh; + $this->config = $config; + + // Load image server support + require_once IMAGE_SERVER_ABSTRACT; + $this->is = new ImageServerAbstract(); + + // if debug.glmpdf is set in the configs/common.ini file in the CommonApp directory, do grids on PDFs + define ('GLMPDF_DEBUG', $this->config->debug->glmpdf); + + // The following produces a color test sheet. There is no return from that call. + // $this->glmpdfShowValidColors(); exit; + + // Start with cover page. + $this->glmpdfSetForms( + 1, + array( + 1 => array( 'x' => 0, 'y' => 0, 'xs' => 613, 'ys' => 792 ) + ), + 'US Letter' + ); + + // Start page + $this->glmpdfStart( $this->config->owner->name, "Gaslight Media", "Ticket System Receipt/Vouchers" ); + + if( !$this->glmpdfAddFont( 'barcode', 'barcode/FREE3OF9.TTF' ) ) + { + echo 'ERROR: Unable to add barcode font.

    + Did you place the barcode font provided in docs/BarcodeFonts into + a system fonts directory ("/usr/share/fonts/truetype/Barcode")? + Also check the GLMPDF_PDF_FONT_DIR setting in GlmPdf.php.'; + exit; + } + + // Get images to tmp files + if (trim($member['image']) != '') { + $venueImageFile = $this->is->saveImageToTemp(IMAGE_SERVER_PREFIX.'original/'.$member['image']); + if ($venueImageFile) { + $venueImage = $this->glmpdfOpenImage($venueImageFile); + + // If failure getting the image + if ($venueImage == false) { + $venueImageFile = false; + } + } + } else { + $venueImageFile = false; + } + + if (trim($member['parking_map']) != '') { + $parkingImageFile = $this->is->saveImageToTemp(IMAGE_SERVER_PREFIX.'original/'.$member['parking_map']); + if ($parkingImageFile) { + $parkingImage = $this->glmpdfOpenImage($parkingImageFile); + + // If failure getting the image + if ($parkingImage == false) { + $parkingImageFile = false; + } + } + } else { + $parkingImageFile = false; + } + + if (trim($member['ticket_sec_map']) != '') { + $sectionImageFile = $this->is->saveImageToTemp(IMAGE_SERVER_PREFIX.'original/'.$member['ticket_sec_map']); + if ($sectionImageFile) { + $sectionImage = $this->glmpdfOpenImage($sectionImageFile); + + // If failure getting the image + if ($sectionImage == false) { + $sectionImageFile = false; + } + } + } else { + $sectionImageFile = false; + } + + // Load entrance class + require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/entrances.php'; + $Entrances = new EventManagementAdminEntrances($dbh, $config); + + // Load performance class + require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/performances.php'; + $Performances = new EventManagementAdminPerformances($dbh, $config); + + // Load Voucher Coupons class and get coupons list for display + require_once EVENT_MANAGEMENT_APP_BASE.'classes/data/dataVoucherCoupons.php'; + $VoucherCoupons = new EventManagementDataVoucherCoupons($dbh, $config); + + // Load ticket packages data class + require_once EVENT_MANAGEMENT_APP_BASE.'classes/data/dataTicketPackages.php'; + $TicketPackages = new EventManagementDataTicketPackages($dbh, $config); + + + // If no date has been supplied - make it today + if (isset($_REQUEST['date']) && $_REQUEST['date'] != '') { + $date = $_REQUEST['date']; + } else { + $date = date('m/d/Y', time()); + } + + $vc = $VoucherCoupons->getCouponsForDisplay($date); + + // Setup footers +/* + $footer = 'For assistance call '.$this->config->owner->phone; + if ($this->config->owner->toll_free != '') { + $footer .= ' or '.$this->config->owner->toll_free; + } +*/ + + if (!$couponTest) { + + $this->glmpdfNextForm(); + + + /* Cover Page */ + + // Header + if ($venueImageFile) { + $coverImage = $this->glmpdfOpenImage($venueImageFile); + $this->glmpdfPlaceImage($coverImage, 30, 690, .5, false, 'center', 280, 140); + } + $this->glmpdfSetFont( "Helvetica-Bold", 18.0 ); // Header Text + $this->glmpdfPlaceText( $config->owner->name, 340, 750, "center", 'black', -400 ); + $this->glmpdfSetFont( "Helvetica", 14.0 ); + $this->glmpdfPlaceText( $config->owner->short_name." - ".$member['name'], 340, $this->glmpdfCurrentY-10, "center", 'black', -400 ); + $this->glmpdfPlaceText( $member['addr1'], 340, $this->glmpdfCurrentY, "center", 'black', -400 ); + $this->glmpdfPlaceText( $member['city'].", ".$member['state']['name']." ".$member['zip'], 340, $this->glmpdfCurrentY, "center", 'black', -400 ); + + // Sold To Information + $valCol = 60; + $this->glmpdfSetFont( "Helvetica", 10.0 ); + $this->glmpdfPlaceText( $this->config->term->order->cap." ID: ".trim($order['id']), $valCol, 650, "left", 'black' ); + $this->glmpdfPlaceText( trim($order['fname'].' '.$order['lname']), $valCol, $this->glmpdfCurrentY-5, "left", 'black', -200 ); + $this->glmpdfPlaceText( trim($order['addr1']), $valCol, $this->glmpdfCurrentY-5, "left", 'black', -200 ); + if( trim($order['addr2']) != '' ) + $this->glmpdfPlaceText( trim($order['addr2']), $valCol, $this->glmpdfCurrentY-5, "left", 'black', -200 ); + $this->glmpdfPlaceText( trim($order['city']).', '.$order['state']['value'].' '.trim($order['zip']).' '.$order['country']['value'], $valCol, $this->glmpdfCurrentY-5, "left", 'black', -200 ); + + // Purchace/Charge information + $this->glmpdfSetFont( "Helvetica", 10.0 ); + $promptCol = 330; + $valCol = 420; + $this->glmpdfPlaceText( "Date of Purchase:", $promptCol, 650, "left", 'black' ); + $this->glmpdfPlaceText( $order['purchase_date']['date'], $valCol, $this->glmpdfLastY, "left", 'black', -160 ); + $this->glmpdfPlaceText( "Card Type:", $promptCol, $this->glmpdfCurrentY-5, "left", 'black' ); + $this->glmpdfPlaceText( $order['cctype'], $valCol, $this->glmpdfLastY, "left", 'black', -160 ); + $this->glmpdfPlaceText( "Name on Card:", $promptCol, $this->glmpdfCurrentY-5, "left", 'black' ); + $this->glmpdfPlaceText( $order['ccname'], $valCol, $this->glmpdfLastY, "left", 'black', -160 ); + $this->glmpdfPlaceText( "Card Number:", $promptCol, $this->glmpdfCurrentY-5, "left", 'black' ); + $this->glmpdfPlaceText( $order['ccnumber'], $valCol, $this->glmpdfLastY, "left", 'black', -160 ); + $this->glmpdfPlaceText( "Confirmation:", $promptCol, $this->glmpdfCurrentY-5, "left", 'black' ); + $this->glmpdfPlaceText( $order['ccconf'], $valCol, $this->glmpdfLastY, "left", 'black', -160 ); + $this->glmpdfPlaceText( "Total Charged:", $promptCol, $this->glmpdfCurrentY-5, "left", 'black' ); + $this->glmpdfPlaceText( $order['charge_total'], $valCol, $this->glmpdfLastY, "left", 'black', -160 ); + + // Purchase Summary + $ticNumbCol = 20; + $perfNameCol = 80; + $ticNameCol = 200; + $secNameCol = 370; + $dateCol = 440; + $this->glmpdfPlaceText( '', $ticNumbCol, 550, "center", 'black', 0, ''); + + $this->glmpdfSetFont( "Helvetica", 8.0 ); + $this->glmpdfPlaceText( $this->config->term->voucher->cap, $ticNumbCol, $this->glmpdfCurrentY, "left", 'black', -52, ''); + $this->glmpdfPlaceText( $this->config->term->performance->cap, $perfNameCol, $this->glmpdfLastY, "left", 'black', -110, ''); + $this->glmpdfPlaceText( $this->config->term->ticket->cap, $ticNameCol, $this->glmpdfLastY, "left", 'black', -160, ''); + $this->glmpdfPlaceText( $this->config->term->section->cap, $secNameCol, $this->glmpdfLastY, "left", 'black', -60, ''); + $this->glmpdfPlaceText( 'Date / Time', $dateCol, $this->glmpdfLastY, "left", 'black', -160, ''); + + $this->glmpdfPlaceText( '', $ticNumbCol, $this->glmpdfCurrentY-3, "center", 'black', 0, ''); + + foreach( $vouchers as $t ) { + + $voucherCode = $this->addCheckCode($t['id']); + + $this->glmpdfSetFont( "Helvetica", 8.0 ); + if (!$t['ticket_package']) { + $this->glmpdfPlaceText( $voucherCode, $ticNumbCol, $this->glmpdfCurrentY, "left", 'black', -52, ''); + } else { + $this->glmpdfPlaceText( '', $ticNumbCol, $this->glmpdfCurrentY, "left", 'black', -52, ''); + } + $this->glmpdfPlaceText( html_entity_decode($t['performance_name'],ENT_QUOTES,"utf-8"), $perfNameCol, $this->glmpdfLastY, "left", 'black', -110, ''); + $this->glmpdfPlaceText( html_entity_decode($t['ticket_name'],ENT_QUOTES,"utf-8"), $ticNameCol, $this->glmpdfLastY, "left", 'black', -160, ''); + if (!$t['is_package']['value']) { + $this->glmpdfPlaceText( html_entity_decode($t['section_name'],ENT_QUOTES,"utf-8"), $secNameCol, $this->glmpdfLastY, "left", 'black', -60, ''); + if ($t['date_specific']['value']) { + $this->glmpdfPlaceText( $t['ticket_date']['date'], $dateCol, $this->glmpdfLastY, "left", 'black', -160, ''); + } else { + $dateRange = 'Valid From '.$t['start_date']['date'].' through '.$t['end_date']['date']; + $this->glmpdfPlaceText( $dateRange, $dateCol, $this->glmpdfLastY, "left", 'black', -160, ''); + } + } + + // Check for Ticket add-ons + if (isset($t['addons_sold']) && count($t['addons_sold']) > 0) { + foreach($t['addons_sold'] as $a) { + + $addonText = $a['add_on_name']; + if (($a['add_on_type']['value']-0) == 2) { + $addonText = $addonText.', '.$a['quant'].' '.$a['unit_name']; + } + $this->glmpdfPlaceText( html_entity_decode($addonText,ENT_QUOTES,"utf-8"), $ticNameCol+10, $this->glmpdfCurrentY, "left", 'black', -240, ''); + } + } + + } + + // Special Needs + $this->glmpdfSetFont( "Helvetica", 9.0 ); + if (trim($order['special_needs']) != '') { + $this->glmpdfPlaceText( "Special Needs:", 20, $this->glmpdfCurrentY-30, "left", 'black' ); + $this->glmpdfPlaceTextBox( $order['special_needs'], 100, $this->glmpdfCurrentY+16, 450, 50, "left", 'black' ); + } + + // General Member Policies + if (trim($member['def_ticket_pol']) != '') { + $this->glmpdfPlaceText( "Policies:", 20, $this->glmpdfCurrentY-30, "left", 'black' ); + $this->glmpdfPlaceTextBox( $member['def_ticket_pol'], 100, $this->glmpdfCurrentY+16, 450, 50, "left", 'black' ); + } + + } + + // Standard voucher & coupon form - 1 Voucher, 8 coupons + $voucher1_coupon8 = array( + 'forms' => 10, + 'layout' => array( + 1 => array( 'x' => 25, 'y' => 515, 'xs' => 560, 'ys' => 232 ), + 2 => array( 'x' => 25, 'y' => 325, 'xs' => 375, 'ys' => 150 ), + 3 => array( 'x' => 415, 'y' => 325, 'xs' => 170, 'ys' => 150 ), + 4 => array( 'x' => 25, 'y' => 160, 'xs' => 170, 'ys' => 150 ), + 5 => array( 'x' => 210, 'y' => 160, 'xs' => 375, 'ys' => 150 ), + 6 => array( 'x' => 25, 'y' => 25, 'xs' => 137, 'ys' => 120 ), + 7 => array( 'x' => 166, 'y' => 25, 'xs' => 137, 'ys' => 120 ), + 8 => array( 'x' => 307, 'y' => 25, 'xs' => 137, 'ys' => 120 ), + 9 => array( 'x' => 448, 'y' => 25, 'xs' => 137, 'ys' => 120 ), + 10 => array( 'x' => 25, 'y' => 25, 'xs' => 419, 'ys' => 120 ), + ) + ); + + // Package vouchers - 3 vouchers, no coupons + $voucher3_coupon0 = array( + 'forms' => 3, + 'layout' => array( + 1 => array( 'x' => 25, 'y' => 561, 'xs' => 560, 'ys' => 176 ), + 2 => array( 'x' => 25, 'y' => 308, 'xs' => 560, 'ys' => 176 ), + 3 => array( 'x' => 25, 'y' => 55, 'xs' => 560, 'ys' => 176 ) + ) + ); + + // Now setup ticket forms + $this->glmpdfSetForms( + $voucher1_coupon8['forms'], + $voucher1_coupon8['layout'], + 'US Letter' + ); + +/*********CPS + // Display Parking Map + if ($parkingImage) { + $this->glmpdfNextForm(); + $this->glmpdfPlaceImage( $parkingImage, 0, 2, 0, 'meet', 'center', 280, 125); + $this->glmpdfSetFont( "Helvetica-Bold", 10.0 ); + $this->glmpdfPlaceText( 'Parking Map', 140, 130, "center", 'black' ); + } + + // Display Section Map + if ($sectionImage) { + $this->glmpdfNextForm(); + $this->glmpdfPlaceImage( $sectionImage, 0, 2, 0, 'meet', 'center', 280, 125); + $this->glmpdfSetFont( "Helvetica-Bold", 10.0 ); + $this->glmpdfPlaceText( 'Section Map', 140, 130, "center", 'black' ); + } +*/ + + // Clear performance image loaded flag + $performanceLoaded = false; + +// $this->glmpdfNextPage(); + $firstVoucherPageSet = false; + + // Process Vouchers - For each type of ticket purchased + $numb_tickets = 0; + $counterSQL = ''; + $packageVouchersPrintedSeparately = ''; + $allPackageVouchersSeparate = true; + $packageVoucher = false; + $packageTicketName = ''; + $doDashes = false; + $skipNextFormAdvance = false; + + foreach( $vouchers as $t ) + { + + // Flag to determine if this voucher will be displayed (vouchers not displayed if it's a package ticket) + $displaying_this_voucher = false; + + if (!$couponTest) { + + // Check if the current voucher is a new package that has vouchers that print + if ($t['is_package']['value']) { + + $packageVoucher = true; + + // Check if any vouchers for this package print separately + $ticketPackage = $TicketPackages->getList('package = '.$t['ticket']); + if (is_array($ticketPackage) && count($ticketPackage) > 0) { + + // For each ticket in the package + foreach ($ticketPackage as $tp) { + + // Check if it requires a separate voucher + if ($tp['separate_voucher']['value']) { + + // Set this flag to the package sold ID (same for all vouchers for a package) so we can tell if we hit the end of the package + $packageVouchersPrintedSeparately = $t['package_sold_id']; + $packagePerformanceName = $t['performance_name']; + $packageTicketName = $t['ticket_name']; + } else { + $allPackageVouchersSeparate = false; + } + } + } + + // If we found one, then switch layouts. + if ($packageVouchersPrintedSeparately != '') { + $this->glmpdfSetForms( + $voucher3_coupon0['forms'], + $voucher3_coupon0['layout'], + 'US Letter' + ); + $voucherPageStarted = false; + $skipNextFormAdvance = false; + $doDashes = true; + if ($numb_tickets) { + $skipNextFormAdvance = true; + } + } + + // If we have a package with separate vouchers + } else { + $packageVoucher = false; + } + + if ($packageVouchersPrintedSeparately != '') { + + // Check if we're now past the package that had vouchers printed separately + if ($t['package_sold_id'] != $packageVouchersPrintedSeparately) { + + $this->glmpdfSetForms( + $voucher1_coupon8['forms'], + $voucher1_coupon8['layout'], + 'US Letter' + ); + $voucherPageStarted = false; + $packageVouchersPrintedSeparately = ''; + $skipNextFormAdvance = true; + } + + } + + // Check if this voucher is a print separate voucher for a package + $printVoucher = false; + if ($t['ticket_package']) { + + // Get ticket_package data + $ticketPackage = $TicketPackages->getList('package = '.$t['ticket_package'].' AND ticket = '.$t['ticket']); + + // If Separate Voucher, override and display voucher. + if ($ticketPackage[0]['separate_voucher']['value']) { + $printVoucher = true; + } + + } else { + $printVoucher = true; + } + + // Check if this is a package voucher and we are printing all package tickets separately + if ($packageVoucher && $allPackageVouchersSeparate) { + $printVoucher = false; + } + + // If this isn't a package ticket (we're not printing separate vouchers at this time) + if ($printVoucher) { + + + if ($packageVouchersPrintedSeparately) { + + // If the first voucher page hasn't been set + if (!$voucherPageStarted) { + $this->glmpdfNextPage(); + $voucherPageStarted = true; + + if ($doDashes) { + // Print perforations + $this->glmpdfPlaceLine(1, 0, -38, 560, -38, $color = "dimgray", $dash = true, $d_a = 1, $d_b = 5); + $this->glmpdfPlaceLine(1, 0, -291, 560, -291, $color = "dimgray", $dash = true, $d_a = 1, $d_b = 5); + $doDashes = false; + } + + } + + $displaying_this_voucher = true; + + if ($numb_tickets++ > 0) { + + if ($skipNextFormAdvance) { + $skipNextFormAdvance = false; + } else { + $this->glmpdfNextForm(); + } + } + $this->glmpdfPlaceBox( $this->borderWidth, 0, 176, 560, 176, $this->borderColor ); + + // Display Logo - Only get performance image if it's not currently loaded + if ($performanceLoaded != $t['performance']) { + + $performanceDetail = $Performances->getPerformanceDetail($t['performance']); + + // If we have an image but it's the wrong one, dump the temp file + if ($performanceImageFile) { + unlink($performanceImageFile); + } + + // This performance image is not currently loaded - so do that now + + $performanceImageFile = $this->is->saveImageToTemp(IMAGE_SERVER_PREFIX.'original/'.$performanceDetail['image']); + if ($performanceImageFile) { + // If we have the image, then load it + $performanceImage = $this->glmpdfOpenImage($performanceImageFile); + $performanceLoaded = $t['performance']; + } else { + + // otherwise, try the venue image + $performanceLoaded = $venueImage; + } + + } + + // If we have the performance image, display it + $haveTopImage = false; + if ($performanceImage) { + $this->glmpdfPlaceImage( $performanceImage, 85, 100, 1, 'meet', 'center', 70, 75); + $haveTopImage = true; + } elseif ($venueImageFile) { + $this->glmpdfPlaceImage($coverImage, 85, 100, 1, 'meet', 'center', 70, 75); + $haveTopImage = true; + } + + // Place owner name at top possitioned by whether or not there's an image supplied + $this->glmpdfSetFont( "Helvetica-Bold", 20.0 ); + if ($haveTopImage) { + $this->glmpdfPlaceText( $config->owner->name, 315, 131, "center", 'black', -300, ''); + } else { + $this->glmpdfPlaceText( $config->owner->name, 280, 131, "center", 'black', -350, ''); + } + + // If ticket has already been claimed, then mark ticket + if ($t['time_claimed']['date'] != '') { + $this->glmpdfSetFont( "Times-Bold", 72.0 ); + $this->glmpdfPlaceText( "CLAIMED", 110, 80, "left", 'orangered', 0, '' ); // last parameter can be things like "rotate=90" + } + + // Ticket Information Area + $this->glmpdfPlaceLine(1, 80, 0, 80, 176, $color = "black", $dash = false, $d_a = 1, $d_b = 1); + $this->glmpdfPlaceLine(1, 480, 0, 480, 176, $color = "black", $dash = false, $d_a = 1, $d_b = 1); + + // If part of a package, print the package name it's part of. + if ($packageTicketName && !$t['is_package']['value']) { + + $this->glmpdfSetFont( "Helvetica-Bold", 10.0 ); + $this->glmpdfPlaceText( 'Part of:', 7, 40, 'left', 'black', 0, 'position=center rotate=90'); + $this->glmpdfSetFont( "Helvetica-Bold", 12.0 ); + $this->glmpdfPlaceText( $packagePerformanceName, 30, 88, 'left', 'black', -165, 'position=center rotate=90'); + $this->glmpdfPlaceText( $packageTicketName, 60, 88, 'left', 'black', -165, 'position=center rotate=90'); + + } else { + + // Left End of Ticket - NOTE: use only "left" in glmpdfPlaceText - use "position=..." in optlist instead. + if (($t['entrance']-0) > 0) { + $entranceDetail = $Entrances->getEntranceDetail($t['entrance']); + $this->glmpdfPlaceBox(1, 0, 0, 80, -232, '', $entranceDetail['color']['name'], 'miter'); + } + + $this->glmpdfSetFont( "Helvetica-Bold", 10.0 ); + $this->glmpdfPlaceText( 'Departing from:', 7, 40, 'left', 'black', 0, 'position=center rotate=90'); + $this->glmpdfSetFont( "Helvetica-Bold", 16.0 ); + $this->glmpdfPlaceText( strtoupper(html_entity_decode($t['entrance_name'],ENT_QUOTES,"utf-8")), 30, 116, 'left', 'black', -224, 'position=center rotate=90'); + $this->glmpdfPlaceText( strtoupper(html_entity_decode($t['member_name'],ENT_QUOTES,"utf-8")), 60, 116, 'left', 'black', -224, 'position=center rotate=90'); + + } + + // Display values + $this->glmpdfSetFont( "Helvetica-Bold", 16.0 ); + $this->glmpdfPlaceText( html_entity_decode($t['performance_name'],ENT_QUOTES,"utf-8"), 280, 91, "center", 'black', -370, ''); + $this->glmpdfSetFont( "Helvetica-Bold", 12.0 ); + $this->glmpdfPlaceText( html_entity_decode($t['ticket_name'],ENT_QUOTES,"utf-8"), 280, 77, "center", 'black', -370, '' ); + + $this->glmpdfSetFont( "Helvetica", 10.0 ); + if ($t['date_specific']['value']) { + $this->glmpdfPlaceText( $t['ticket_date']['date'], 280, 65, "center", 'black', -370, '' ); + } else { + $dateRange = 'Valid From '.$t['start_date']['date'].' through '.$t['end_date']['date']; + $this->glmpdfPlaceText( $dateRange, 280, 65, "center", 'black', -370, '' ); + } + + $this->glmpdfSetFont( "Helvetica", 16.0 ); + + // Put package line for voucher here + + // Check for Ticket add-ons +/* No addons for packages + if (isset($t['addons_sold']) && count($t['addons_sold']) > 0) { + $this->glmpdfSetFont( "Helvetica", 14.0 ); + foreach($t['addons_sold'] as $a) { + $addonText = $a['add_on_name']; + if (($a['add_on_type']['value']-0) == 2) { + $addonText = $addonText.', '.$a['quant'].' '.$a['unit_name']; + } + $this->glmpdfPlaceText( $addonText, 280, $this->glmpdfCurrentY, "center", 'black', -370, '' ); + } + } +*/ + // Non-Refundable and other Fixed text for body of Voucher + $this->glmpdfSetFont( "Helvetica", 10.0 ); + $this->glmpdfPlaceText( "NON-REFUNDABLE", 280, $this->glmpdfCurrentY, "center", 'black', -300, ''); + + // Display address and contact information + $this->glmpdfSetFont( "Helvetica", 10.0 ); + $contactInfo = $this->config->owner->name.' - ' + .$this->config->owner->address1.' - ' + .($this->config->owner->address2 != '' ? ', '.$this->config->owner->address2 : '') + .$this->config->owner->city.', ' + .$this->config->owner->state.' ' + .$this->config->owner->zip.' - ' + .$this->config->owner->phone + .($this->config->owner->toll_free != '' ? ' - '.$this->config->owner->toll_free : ''); + $this->glmpdfPlaceText( html_entity_decode($contactInfo,ENT_QUOTES,"utf-8"), 280, 25, "center", 'black', -380, ''); + + // Display additional voucher text at the bottom of the voucher if provided + $voucherText = ''; + if (trim($t['ticket_voucher_text']) != '') { + $voucherText = trim(html_entity_decode($t['ticket_voucher_text'],ENT_QUOTES,"utf-8")); + } elseif (trim($performanceDetail['voucher_text']) != '') { + $voucherText = trim(html_entity_decode($performanceDetail['voucher_text'],ENT_QUOTES,"utf-8")); + } + if ($voucherText != '') { + $this->glmpdfPlaceLine(1, 80, 20, 480, 20, 'black', false); + $this->glmpdfSetFont( "Helvetica-Bold", 10.0 ); + // $this->glmpdfPlaceBox(1, 80, 20, 400, 20, "black", "black"); + $this->glmpdfPlaceText( html_entity_decode($voucherText,ENT_QUOTES,"utf-8"), 280, 6, "center", 'black', -370, '' ); + } + + // $this->glmpdfPlaceText( $t['ticket_date']['date'].' - '.$t['ticket_time']['time'], 120, $this->glmpdfCurrentY, "left", 'black', 0, '' ); + + // Print barcode = {ticket_sold ID}-{person type}-{person_sequence} + $barcode = $this->addCheckCode($t['id']); + + // If we're supposed to print barcode and voucher number on ticket + switch ($t['ticket_voucher_type']) { + case 11: + $this->glmpdfSetFont( "Courier-Bold", 10.0 ); + $this->glmpdfPlaceText( "Pickup ".$this->config->term->voucher->norm." at ".$this->config->term->prop->norm, 510, 88, 'left', 'red', -170, 'position=center rotate=90'); + $this->glmpdfSetFont( "Courier", 12.0 ); + $this->glmpdfPlaceText( $this->config->term->voucher->cap." $barcode", 540, 88, 'left', 'black', -170, 'position=center rotate=90'); + break; + case 12; + $this->glmpdfSetFont( "Courier-Bold", 10.0 ); + $this->glmpdfPlaceText( "You will receive ".$this->config->term->voucher->cap." by mail", 510, 88, 'left', 'red', -170, 'position=center rotate=90'); + $this->glmpdfSetFont( "Courier", 12.0 ); + $this->glmpdfPlaceText( $this->config->term->voucher->cap." $barcode", 540, 88, 'left', 'black', -170, 'position=center rotate=90'); + break; + case 1: + default: + $this->glmpdfSetFont( 'barcode', 40 ); + $this->glmpdfPlaceText( "*$barcode*", 510, 88, 'left', 'black', 0, 'position=center rotate=90'); + $this->glmpdfSetFont( "Courier", 10.0 ); + $this->glmpdfPlaceText( $this->config->term->voucher->cap." $barcode", 540, 88, 'left', 'black', -224, 'position=center rotate=90'); + break; + } + + $this->glmpdfPlaceText( "Order #".$order['id'], 552, 88, 'left', 'black', 0, 'position=center rotate=90'); + + // Display Footer + $this->glmpdfSetFont( "Helvetica-Bold", 8.5 ); + $this->glmpdfPlaceText( $footer, 140.5, 2, "center", 'darkblue' ); + + + // Print a normal voucher + } else { + + // If the first voucher page hasn't been set + if (!$voucherPageStarted) { + $this->glmpdfNextPage(); + $voucherPageStarted = true; + + if ($doDashes) { + // Print perforations + $this->glmpdfPlaceLine(1, 0, -11, 560, -11, $color = "dimgray", $dash = true, $d_a = 1, $d_b = 5); + $this->glmpdfPlaceLine(1, 0, -265, 560, -265, $color = "dimgray", $dash = true, $d_a = 1, $d_b = 5); + $doDashes = false; + } + + } + + $displaying_this_voucher = true; + + if ($numb_tickets++ > 0) { + + if ($skipNextFormAdvance) { + $skipNextFormAdvance = false; + } else { + $this->glmpdfNextForm(); + } + } + $this->glmpdfPlaceBox( $this->borderWidth, 0, 232, 560, 232, $this->borderColor ); + + // Display Logo - Only get performance image if it's not currently loaded + if ($performanceLoaded != $t['performance']) { + + $performanceDetail = $Performances->getPerformanceDetail($t['performance']); + + // If we have an image but it's the wrong one, dump the temp file + if ($performanceImageFile) { + unlink($performanceImageFile); + } + + // This performance image is not currently loaded - so do that now + + $performanceImageFile = $this->is->saveImageToTemp(IMAGE_SERVER_PREFIX.'original/'.$performanceDetail['image']); + if ($performanceImageFile) { + // If we have the image, then load it + $performanceImage = $this->glmpdfOpenImage($performanceImageFile); + $performanceLoaded = $t['performance']; + } else { + + // otherwise, try the venue image + $performanceLoaded = $venueImage; + } + + } + + // If we have the performance image, display it + $haveTopImage = false; + if ($performanceImage) { + $this->glmpdfPlaceImage( $performanceImage, 85, 154, 1, 'meet', 'center', 70, 75); + $haveTopImage = true; + } elseif ($venueImageFile) { + $this->glmpdfPlaceImage($coverImage, 85, 154, 1, 'meet', 'center', 70, 75); + $haveTopImage = true; + } + + // Place owner name at top possitioned by whether or not there's an image supplied + $this->glmpdfSetFont( "Helvetica-Bold", 20.0 ); + if ($haveTopImage) { + $this->glmpdfPlaceText( $config->owner->name, 315, 185, "center", 'black', -300, ''); + } else { + $this->glmpdfPlaceText( $config->owner->name, 280, 185, "center", 'black', -350, ''); + } + + // If ticket has already been claimed, then mark ticket + if ($t['time_claimed']['date'] != '') { + $this->glmpdfSetFont( "Times-Bold", 72.0 ); + $this->glmpdfPlaceText( "CLAIMED", 110, 80, "left", 'orangered', 0, '' ); // last parameter can be things like "rotate=90" + } + + // Ticket Information Area + $this->glmpdfPlaceLine(1, 80, 0, 80, 232, $color = "black", $dash = false, $d_a = 1, $d_b = 1); + $this->glmpdfPlaceLine(1, 480, 0, 480, 232, $color = "black", $dash = false, $d_a = 1, $d_b = 1); + + // If part of a package, print the package name it's part of. + if ($packageTicketName && !$t['is_package']['value']) { + + $this->glmpdfSetFont( "Helvetica-Bold", 10.0 ); + $this->glmpdfPlaceText( 'Part of:', 7, 40, 'left', 'black', 0, 'position=center rotate=90'); + $this->glmpdfSetFont( "Helvetica-Bold", 16.0 ); + $this->glmpdfPlaceText( $packagePerformanceName, 30, 116, 'left', 'black', -224, 'position=center rotate=90'); + $this->glmpdfPlaceText( $packageTicketName, 60, 116, 'left', 'black', -224, 'position=center rotate=90'); + + } else { + + // Voucher left end text overrides departing from text + if ($t['ticket_voucher_leftend_text'] != '') { + $this->glmpdfPlaceBox(1, 0, 0, 80, -232, '', 'lightlilac', 'miter'); + $this->glmpdfSetFont( "Helvetica-Bold", 16.0 ); + $this->glmpdfPlaceText( strtoupper(html_entity_decode($t['ticket_voucher_leftend_text'],ENT_QUOTES,"utf-8")), 40, 116, 'left', 'black', -224, 'position=center rotate=90'); + } else { + // Left End of Ticket - NOTE: use only "left" in glmpdfPlaceText - use "position=..." in optlist instead. + if (($t['entrance']-0) > 0) { + $entranceDetail = $Entrances->getEntranceDetail($t['entrance']); + $this->glmpdfPlaceBox(1, 0, 0, 80, -232, '', $entranceDetail['color']['name'], 'miter'); + } + + $this->glmpdfSetFont( "Helvetica-Bold", 10.0 ); + $this->glmpdfPlaceText( 'Departing from:', 7, 40, 'left', 'black', 0, 'position=center rotate=90'); + $this->glmpdfSetFont( "Helvetica-Bold", 16.0 ); + $this->glmpdfPlaceText( strtoupper(html_entity_decode($t['entrance_name'],ENT_QUOTES,"utf-8")), 30, 116, 'left', 'black', -224, 'position=center rotate=90'); + $this->glmpdfPlaceText( strtoupper(html_entity_decode($t['member_name'],ENT_QUOTES,"utf-8")), 60, 116, 'left', 'black', -224, 'position=center rotate=90'); + } + } + + // Display values + $this->glmpdfSetFont( "Helvetica-Bold", 20.0 ); + $this->glmpdfPlaceText( html_entity_decode($t['performance_name'],ENT_QUOTES,"utf-8"), 280, 135, "center", 'black', -370, ''); + $this->glmpdfSetFont( "Helvetica-Bold", 18.0 ); + $this->glmpdfPlaceText( html_entity_decode($t['ticket_name'],ENT_QUOTES,"utf-8"), 280, 114, "center", 'black', -370, '' ); + + $this->glmpdfSetFont( "Helvetica", 14.0 ); + if ($t['date_specific']['value']) { + $this->glmpdfPlaceText( $t['ticket_date']['date'], 280, 96, "center", 'black', -370, '' ); + } else { + $dateRange = 'Valid From '.$t['start_date']['date'].' through '.$t['end_date']['date']; + $this->glmpdfPlaceText( $dateRange, 280, 96, "center", 'black', -370, '' ); + } + + $this->glmpdfSetFont( "Helvetica", 16.0 ); + + // Put package line for voucher here + + // Check for Ticket add-ons + if (isset($t['addons_sold']) && count($t['addons_sold']) > 0) { + $this->glmpdfSetFont( "Helvetica", 14.0 ); + foreach($t['addons_sold'] as $a) { + $addonText = $a['add_on_name']; + if (($a['add_on_type']['value']-0) == 2) { + $addonText = $addonText.', '.$a['quant'].' '.$a['unit_name']; + } + $this->glmpdfPlaceText( $addonText, 280, $this->glmpdfCurrentY, "center", 'black', -370, '' ); + } + } + + // Non-Refundable and other Fixed text for body of Voucher + $this->glmpdfSetFont( "Helvetica", 12.0 ); + $this->glmpdfPlaceText( "NON-REFUNDABLE", 280, $this->glmpdfCurrentY, "center", 'black', -300, ''); + + // Display address and contact information + $this->glmpdfSetFont( "Helvetica", 12.0 ); + $contactInfo = $this->config->owner->name.' - ' + .$this->config->owner->address1.' - ' + .($this->config->owner->address2 != '' ? ', '.$this->config->owner->address2 : '') + .$this->config->owner->city.', ' + .$this->config->owner->state.' ' + .$this->config->owner->zip.' - ' + .$this->config->owner->phone + .($this->config->owner->toll_free != '' ? ' - '.$this->config->owner->toll_free : ''); + $this->glmpdfPlaceText( html_entity_decode($contactInfo,ENT_QUOTES,"utf-8"), 280, 25, "center", 'black', -380, ''); + + // Display additional voucher text at the bottom of the voucher if provided + $voucherText = ''; + if (trim($t['ticket_voucher_text']) != '') { + $voucherText = trim(html_entity_decode($t['ticket_voucher_text'],ENT_QUOTES,"utf-8")); + } elseif (trim($performanceDetail['voucher_text']) != '') { + $voucherText = trim(html_entity_decode($performanceDetail['voucher_text'],ENT_QUOTES,"utf-8")); + } + if ($voucherText != '') { + $this->glmpdfPlaceLine(1, 80, 20, 480, 20, 'black', false); + $this->glmpdfSetFont( "Helvetica-Bold", 14.0 ); + // $this->glmpdfPlaceBox(1, 80, 20, 400, 20, "black", "black"); + $this->glmpdfPlaceText( html_entity_decode($voucherText,ENT_QUOTES,"utf-8"), 280, 6, "center", 'black', -370, '' ); + } + + // $this->glmpdfPlaceText( $t['ticket_date']['date'].' - '.$t['ticket_time']['time'], 120, $this->glmpdfCurrentY, "left", 'black', 0, '' ); + + // Print barcode = {ticket_sold ID}-{person type}-{person_sequence} + $barcode = $this->addCheckCode($t['id']); + + // If we're supposed to print barcode and voucher number on ticket + switch ($t['ticket_voucher_type']) { + case 11: + $this->glmpdfSetFont( "Courier-Bold", 12.0 ); + $this->glmpdfPlaceText( "Pickup ".$this->config->term->voucher->norm." at ".$this->config->term->prop->norm, 510, 116, 'left', 'red', -224, 'position=center rotate=90'); + $this->glmpdfSetFont( "Courier", 12.0 ); + $this->glmpdfPlaceText( $this->config->term->voucher->cap." $barcode", 540, 116, 'left', 'black', -224, 'position=center rotate=90'); + break; + case 12; + $this->glmpdfSetFont( "Courier-Bold", 12.0 ); + $this->glmpdfPlaceText( "You will receive ".$this->config->term->voucher->cap." by mail", 510, 116, 'left', 'red', -224, 'position=center rotate=90'); + $this->glmpdfSetFont( "Courier", 12.0 ); + $this->glmpdfPlaceText( $this->config->term->voucher->cap." $barcode", 540, 116, 'left', 'black', -224, 'position=center rotate=90'); + break; + case 1: + default: + $this->glmpdfSetFont( 'barcode', 48 ); + $this->glmpdfPlaceText( "*$barcode*", 510, 116, 'left', 'black', 0, 'position=center rotate=90'); + $this->glmpdfSetFont( "Courier", 12.0 ); + $this->glmpdfPlaceText( $this->config->term->voucher->cap." $barcode", 540, 116, 'left', 'black', -224, 'position=center rotate=90'); + break; + } + + $this->glmpdfPlaceText( "Order #".$order['id'], 552, 116, 'left', 'black', 0, 'position=center rotate=90'); + + // Display Footer + $this->glmpdfSetFont( "Helvetica-Bold", 8.5 ); + $this->glmpdfPlaceText( $footer, 140.5, 2, "center", 'darkblue' ); + + } // End of normal voucher + + } // Printing Voucher + + } + + if ($displaying_this_voucher) { + + if (!$packageVouchersPrintedSeparately) { + + $this->glmpdfNextForm(); + + // Get table of Ads/Coupons + if (isset($vc[1])) { + + // Get the key for the current ad/coupon for position 1 + $k = key($vc[1]); + + // If the max count is -1 (unlimited) or more than the current display count + if ($vc[1][$k]['max_display_count'] < 0 || $vc[1][$k]['max_display_count'] > $vc[1][$k]['display_count']) { + + // Display the ad/coupon and save SQL to update the display count + $counterSQL .= $this->displayCoupon(current($vc[1]), 375, 150); + + // Incriment the local display count + $vc[1][$k]['display_count']++; + } + + // Advance to the next ad/coupon for this position. If all used, start over. + if (next($vc[1]) === false) { + reset($vc[1]); + } + } + + // Advance to the next form + $this->glmpdfNextForm(); + + // Do the same for the remaining ad/coupon forms + + if (isset($vc[2])) { + $k = key($vc[2]); + if ($vc[2][$k]['max_display_count'] < 0 || $vc[2][$k]['max_display_count'] > $vc[2][$k]['display_count']) { + $counterSQL .= $this->displayCoupon(current($vc[2]), 170, 150); + $vc[2][$k]['display_count']++; + } + if (next($vc[2]) === false) { + reset($vc[2]); + } + } + $this->glmpdfNextForm(); + + if (isset($vc[3])) { + $k = key($vc[3]); + if ($vc[3][$k]['max_display_count'] < 0 || $vc[3][$k]['max_display_count'] > $vc[3][$k]['display_count']) { + $counterSQL .= $this->displayCoupon(current($vc[3]), 170, 150); + $vc[3][$k]['display_count']++; + } + if (next($vc[3]) === false) { + reset($vc[3]); + } + } + $this->glmpdfNextForm(); + + if (isset($vc[4])) { + $k = key($vc[4]); + if ($vc[4][$k]['max_display_count'] < 0 || $vc[4][$k]['max_display_count'] > $vc[4][$k]['display_count']) { + $counterSQL .= $this->displayCoupon(current($vc[4]), 375, 150); + $vc[4][$k]['display_count']++; + } + if (next($vc[4]) === false) { + reset($vc[4]); + } + } + $this->glmpdfNextForm(); + + if (isset($vc[5])) { + $k = key($vc[5]); + if ($vc[5][$k]['max_display_count'] < 0 || $vc[5][$k]['max_display_count'] > $vc[5][$k]['display_count']) { + $counterSQL .= $this->displayCoupon(current($vc[5]), 137, 120); + $vc[5][$k]['display_count']++; + } + if (next($vc[5]) === false) { + reset($vc[5]); + } + } + $this->glmpdfNextForm(); + + if (isset($vc[6])) { + $k = key($vc[6]); + if ($vc[6][$k]['max_display_count'] < 0 || $vc[6][$k]['max_display_count'] > $vc[6][$k]['display_count']) { + $counterSQL .= $this->displayCoupon(current($vc[6]), 137, 120); + $vc[6][$k]['display_count']++; + } + if (next($vc[6]) === false) { + reset($vc[6]); + } + } + $this->glmpdfNextForm(); + + if (isset($vc[7])) { + $k = key($vc[7]); + if ($vc[7][$k]['max_display_count'] < 0 || $vc[7][$k]['max_display_count'] > $vc[7][$k]['display_count']) { + $counterSQL .= $this->displayCoupon(current($vc[7]), 137, 120); + $vc[7][$k]['display_count']++; + } + if (next($vc[7]) === false) { + reset($vc[7]); + } + } + $this->glmpdfNextForm(); + + if (isset($vc[8])) { + $k = key($vc[8]); + if ($vc[8][$k]['max_display_count'] < 0 || $vc[8][$k]['max_display_count'] > $vc[8][$k]['display_count']) { + $counterSQL .= $this->displayCoupon(current($vc[8]), 137, 120); + $vc[8][$k]['display_count']++; + } + if (next($vc[8]) === false) { + reset($vc[8]); + } + } + $this->glmpdfNextForm(); + + if (isset($vc[9])) { + $k = key($vc[9]); + if ($vc[9][$k]['max_display_count'] < 0 || $vc[9][$k]['max_display_count'] > $vc[9][$k]['display_count']) { + $counterSQL .= $this->displayCoupon(current($vc[9]), 419, 120); + $vc[9][$k]['display_count']++; + } + if (next($vc[9]) === false) { + reset($vc[9]); + } + } + } + } + + } // Each voucher + + if ($vc != false) { + $this->dbh->exec("BEGIN;\n".$counterSQL."COMMIT;\n"); + } + + // Close PDF setup and send to user's browser + $this->glmpdfSendToBrowser( '', 'Star_Line_Ticket_Vouchers.pdf' ); + + if ($venueImageFile) { + unlink($venueImageFile); + } + if ($parkingImageFile) { + unlink($parkingImageFile); + } + if ($sectionImageFile) { + unlink($sectionImageFile); + } + if ($sectionImageFile) { + unlink($sectionImageFile); + } + + } + + private function displayCoupon($coupon, $xs, $ys) + { + + // Attempt to get the coupon image + $im = $this->getCouponImage( $this->is, $coupon['coupon_image']); + + // Check for stretch + $fit = 'auto'; + if ($coupon['stretch_to_fit']['value']) { + $fit = 'entire'; + } + + // Check for padding - enforce a minimum size + $pad = $coupon['padding']; + + $x = $xs - ($pad * 2); + if ($x < 10) { + $x == 10; + } + $y = $ys - ($pad * 2); + if ($y < 10) { + $y = 10; + } + + // If the image exists + if ($im) { + + // Place the image + $this->glmpdfPlaceImage($im, $pad, $pad, 1, $fit, 'center', $x, $y); + + + // If a border is requested display that + if ($coupon['show_border']['value']) { + $this->glmpdfPlaceBox( $this->borderWidth, 0, $ys, $xs, $ys, $this->borderColor ); + } + + } + + // SQL to Update Counters + $sql = "UPDATE eventmgt.voucher_coupons SET display_count = display_count + 1 WHERE id = ".$coupon['id'].";\n"; + + return $sql; + + } + + /* + * Function to load an image for use in Voucher Ads or Coupons + * + * This function maintains a static array of loaded images. It + * first checks to see if the image has already been loaded and + * returns the existing object if it is. Otherwise it will + * attempt to load the image, store the open image object in the + * static array for future use, and return it. + * + * @param $is object Image Server Object + * @param $imageName string Name of the image to load + * + * @return object Loaded and opened image object or false if not loaded + * + */ + private function getCouponImage( $is, $imageName ) + { + static $images = array(); + + // Check if image has already been loaded + if (isset($images[$imageName])) { + return $images[$imageName]; + } + + // Try to load the image + $imageFile = $is->saveImageToTemp(IMAGE_SERVER_PREFIX.'original/'.$imageName); + if ($imageFile) { + + // Open the image and save it in case it's needeed again + $images[$imageName] = $this->glmpdfOpenImage($imageFile); + + return $images[$imageName]; + + } + + return false; + + } + + /* + * Function to add check character to end of voucher number + * + * Uses config->voucher_check_secret and voucher # to create MD5 string + * then takes last hex character off of that string and shifts it up to + * always be a character (adds 16 to numbers and 10 to the upper-case + * version of the character). + * i.e. 0 = A, 9 = J, A = K, F = + * + */ + public function addCheckCode($voucherNumb) + { + + // Create MD5 string using voucher number and secret + $md5 = md5($voucherNumb.$this->config->voucher_check_secret); + + // Get last character code of the last character in the MD5 + $cc = strtoupper(substr($md5, -2)); + $cc[0] = $this->shiftCheckCodeCharacter($cc[0]); + $cc[1] = $this->shiftCheckCodeCharacter($cc[1]); + + // Return voucher number with the new character on the end + $voucherNumb .= $cc; + return $voucherNumb; + + } + + private function shiftCheckCodeCharacter($c) { + + $x = ord($c); + + // If it's a digit, add 16 + if ($x < 65) { + $x += 17; + // otherwise, add 10 + } else { + $x += 10; + } + + // Also skip the letter O + if (x >= ord('O')) { + $x += 1; + } + + return chr($x); + } + +} // class + +// Absolutely nothing after next line +?> \ No newline at end of file diff --git a/models/vouchers/MackinacFerry/voucherMobile.php b/models/vouchers/MackinacFerry/voucherMobile.php new file mode 100644 index 0000000..02918ef --- /dev/null +++ b/models/vouchers/MackinacFerry/voucherMobile.php @@ -0,0 +1,711 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: printVoucher.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +require_once PDF_ABSTRACT; +$Pdf = new GlmPdf(); + +/** + * PdfVoucher class + * + * @category PdfVoucher + * @package PDFLib + * @author Chuck Scott + * @license http://www.gaslightmedia.com Gaslightmedia + * @link <> +*/ +class PdfVoucher extends GlmPdf +{ + + public $borderWidth = 1; + public $borderColor = 'black'; + public $pdfCouponInterval = 5; + public $pdfMinCoupons = 3; + public $config; + private $is; + private $dbh; + + function __construct($order, $vouchers, $member, $dbh, $config, $couponTest = false) + { + + $this->dbh = $dbh; + $this->config = $config; + + // Load image server support + require_once IMAGE_SERVER_ABSTRACT; + $this->is = new ImageServerAbstract(); + + // if debug.glmpdf is set in the configs/common.ini file in the CommonApp directory, do grids on PDFs + define ('GLMPDF_DEBUG', $this->config->debug->glmpdf); + + // Start with cover page. + $this->glmpdfSetForms( + 1, + array( + 1 => array( 'x' => 0, 'y' => 0, 'xs' => 613, 'ys' => 792 ) + ), + 'US Letter' + ); + + // Set PDF options - In this case, we don't allow printing for mobile vouchers + $optlist = "masterpassword=GLMPdfPerm permissions=noprint"; + + // Start page + $this->glmpdfStart( $this->config->owner->name, "Gaslight Media", "Ticket System Receipt/Vouchers", $optlist ); + $this->glmpdfNextPage(); + + if( !$this->glmpdfAddFont( 'barcode', 'barcode/FREE3OF9.TTF' ) ) + { + echo 'ERROR: Unable to add barcode font.

    + Did you place the barcode font provided in docs/BarcodeFonts into + a system fonts directory ("/usr/share/fonts/truetype/Barcode")? + Also check the GLMPDF_PDF_FONT_DIR setting in GlmPdf.php.'; + exit; + } + + // Get images to tmp files + if (trim($member['image']) != '') { + $venueImageFile = $this->is->saveImageToTemp(IMAGE_SERVER_PREFIX.'original/'.$member['image']); + if ($venueImageFile) { + $venueImage = $this->glmpdfOpenImage($venueImageFile); + + // If failure getting the image + if ($venueImage == false) { + $venueImageFile = false; + } + } + } else { + $venueImageFile = false; + } + + + // Load entrance class + require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/entrances.php'; + $Entrances = new EventManagementAdminEntrances($dbh, $config); + + // Load performance class + require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/performances.php'; + $Performances = new EventManagementAdminPerformances($dbh, $config); + + // Load ticket packages data class + require_once EVENT_MANAGEMENT_APP_BASE.'classes/data/dataTicketPackages.php'; + $TicketPackages = new EventManagementDataTicketPackages($dbh, $config); + + // If no date has been supplied - make it today + if (isset($_REQUEST['date']) && $_REQUEST['date'] != '') { + $date = $_REQUEST['date']; + } else { + $date = date('m/d/Y', time()); + } + + $firstVoucherPageSet = false; + + // Process Vouchers - For each type of ticket purchased + $numb_tickets = 0; + $counterSQL = ''; + $packageVouchersPrintedSeparately = ''; + $allPackageVouchersSeparate = true; + $packageVoucher = false; + $packageTicketName = ''; + $doDashes = false; + $skipNextFormAdvance = false; + + /* Cover Page */ + + // Header + if ($venueImageFile) { + $coverImage = $this->glmpdfOpenImage($venueImageFile); + $this->glmpdfPlaceImage($coverImage, 30, 690, .5, false, 'center', 280, 140); + } + $this->glmpdfSetFont( "Helvetica-Bold", 18.0 ); // Header Text + $this->glmpdfPlaceText( $config->owner->name, 340, 750, "center", 'black', -400 ); + $this->glmpdfSetFont( "Helvetica", 14.0 ); + $this->glmpdfPlaceText( $config->owner->short_name." - ".$member['name'], 340, $this->glmpdfCurrentY-10, "center", 'black', -400 ); + $this->glmpdfPlaceText( $member['addr1'], 340, $this->glmpdfCurrentY, "center", 'black', -400 ); + $this->glmpdfPlaceText( $member['city'].", ".$member['state']['name']." ".$member['zip'], 340, $this->glmpdfCurrentY, "center", 'black', -400 ); + + // Sold To Information + $valCol = 60; + $this->glmpdfSetFont( "Helvetica", 10.0 ); + $this->glmpdfPlaceText( $this->config->term->order->cap." ID: ".trim($order['id']), $valCol, 650, "left", 'black' ); + $this->glmpdfPlaceText( trim($order['fname'].' '.$order['lname']), $valCol, $this->glmpdfCurrentY-5, "left", 'black', -200 ); + $this->glmpdfPlaceText( trim($order['addr1']), $valCol, $this->glmpdfCurrentY-5, "left", 'black', -200 ); + if( trim($order['addr2']) != '' ) + $this->glmpdfPlaceText( trim($order['addr2']), $valCol, $this->glmpdfCurrentY-5, "left", 'black', -200 ); + $this->glmpdfPlaceText( trim($order['city']).', '.$order['state']['value'].' '.trim($order['zip']).' '.$order['country']['value'], $valCol, $this->glmpdfCurrentY-5, "left", 'black', -200 ); + + // Purchace/Charge information + $this->glmpdfSetFont( "Helvetica", 10.0 ); + $promptCol = 330; + $valCol = 420; + $this->glmpdfPlaceText( "Date of Purchase:", $promptCol, 650, "left", 'black' ); + $this->glmpdfPlaceText( $order['purchase_date']['date'], $valCol, $this->glmpdfLastY, "left", 'black', -160 ); + $this->glmpdfPlaceText( "Card Type:", $promptCol, $this->glmpdfCurrentY-5, "left", 'black' ); + $this->glmpdfPlaceText( $order['cctype'], $valCol, $this->glmpdfLastY, "left", 'black', -160 ); + $this->glmpdfPlaceText( "Name on Card:", $promptCol, $this->glmpdfCurrentY-5, "left", 'black' ); + $this->glmpdfPlaceText( $order['ccname'], $valCol, $this->glmpdfLastY, "left", 'black', -160 ); + $this->glmpdfPlaceText( "Card Number:", $promptCol, $this->glmpdfCurrentY-5, "left", 'black' ); + $this->glmpdfPlaceText( $order['ccnumber'], $valCol, $this->glmpdfLastY, "left", 'black', -160 ); + $this->glmpdfPlaceText( "Confirmation:", $promptCol, $this->glmpdfCurrentY-5, "left", 'black' ); + $this->glmpdfPlaceText( $order['ccconf'], $valCol, $this->glmpdfLastY, "left", 'black', -160 ); + $this->glmpdfPlaceText( "Total Charged:", $promptCol, $this->glmpdfCurrentY-5, "left", 'black' ); + $this->glmpdfPlaceText( $order['charge_total'], $valCol, $this->glmpdfLastY, "left", 'black', -160 ); + + // Purchase Summary + $ticNumbCol = 20; + $perfNameCol = 80; + $ticNameCol = 200; + $secNameCol = 370; + $dateCol = 440; + $this->glmpdfPlaceText( '', $ticNumbCol, 550, "center", 'black', 0, ''); + + $this->glmpdfSetFont( "Helvetica", 8.0 ); + $this->glmpdfPlaceText( $this->config->term->voucher->cap, $ticNumbCol, $this->glmpdfCurrentY, "left", 'black', -52, ''); + $this->glmpdfPlaceText( $this->config->term->performance->cap, $perfNameCol, $this->glmpdfLastY, "left", 'black', -110, ''); + $this->glmpdfPlaceText( $this->config->term->ticket->cap, $ticNameCol, $this->glmpdfLastY, "left", 'black', -160, ''); + $this->glmpdfPlaceText( $this->config->term->section->cap, $secNameCol, $this->glmpdfLastY, "left", 'black', -60, ''); + $this->glmpdfPlaceText( 'Date / Time', $dateCol, $this->glmpdfLastY, "left", 'black', -160, ''); + + $this->glmpdfPlaceText( '', $ticNumbCol, $this->glmpdfCurrentY-3, "center", 'black', 0, ''); + + foreach( $vouchers as $t ) { + + $voucherCode = $this->addCheckCode($t['id']); + + $this->glmpdfSetFont( "Helvetica", 8.0 ); + if (!$t['ticket_package']) { + $this->glmpdfPlaceText( $voucherCode, $ticNumbCol, $this->glmpdfCurrentY, "left", 'black', -52, ''); + } else { + $this->glmpdfPlaceText( '', $ticNumbCol, $this->glmpdfCurrentY, "left", 'black', -52, ''); + } + $this->glmpdfPlaceText( html_entity_decode($t['performance_name'],ENT_QUOTES,"utf-8"), $perfNameCol, $this->glmpdfLastY, "left", 'black', -110, ''); + $this->glmpdfPlaceText( html_entity_decode($t['ticket_name'],ENT_QUOTES,"utf-8"), $ticNameCol, $this->glmpdfLastY, "left", 'black', -160, ''); + if (!$t['is_package']['value']) { + $this->glmpdfPlaceText( html_entity_decode($t['section_name'],ENT_QUOTES,"utf-8"), $secNameCol, $this->glmpdfLastY, "left", 'black', -60, ''); + if ($t['date_specific']['value']) { + $this->glmpdfPlaceText( $t['ticket_date']['date'], $dateCol, $this->glmpdfLastY, "left", 'black', -160, ''); + } else { + $dateRange = 'Valid From '.$t['start_date']['date'].' through '.$t['end_date']['date']; + $this->glmpdfPlaceText( $dateRange, $dateCol, $this->glmpdfLastY, "left", 'black', -160, ''); + } + } + + // Check for Ticket add-ons + if (isset($t['addons_sold']) && count($t['addons_sold']) > 0) { + foreach($t['addons_sold'] as $a) { + + $addonText = $a['add_on_name']; + if (($a['add_on_type']['value']-0) == 2) { + $addonText = $addonText.', '.$a['quant'].' '.$a['unit_name']; + } + $this->glmpdfPlaceText( html_entity_decode($addonText,ENT_QUOTES,"utf-8"), $ticNameCol+10, $this->glmpdfCurrentY, "left", 'black', -240, ''); + } + } + + } + + // Special Needs + $this->glmpdfSetFont( "Helvetica", 9.0 ); + if (trim($order['special_needs']) != '') { + $this->glmpdfPlaceText( "Special Needs:", 20, $this->glmpdfCurrentY-30, "left", 'black' ); + $this->glmpdfPlaceTextBox( $order['special_needs'], 100, $this->glmpdfCurrentY+16, 450, 50, "left", 'black' ); + } + + // General Member Policies + if (trim($member['def_ticket_pol']) != '') { + $this->glmpdfPlaceText( "Policies:", 20, $this->glmpdfCurrentY-30, "left", 'black' ); + $this->glmpdfPlaceTextBox( $member['def_ticket_pol'], 100, $this->glmpdfCurrentY+16, 450, 50, "left", 'black' ); + } + + // General Member Policies + $noPrintNotice = + "NOTE: These MOBILE FRIENDLY vouchers are NOT FOR PRINTING, they are designed specifically for scanning directly from your mobile device. " + ."Scanners at the dock may not be able to read the barcode below from a printed page. " + ."If you need to print your vouchers, please select and print our standard PRINTABLE vouchers."; + $this->glmpdfPlaceTextBox( $noPrintNotice, 50, $this->glmpdfCurrentY-30, 500, 50, "left", 'black' ); + + + // Start with cover page. + $this->glmpdfSetForms( + 1, + array( + 1 => array( 'x' => 10, 'y' => 10, 'xs' => 593, 'ys' => 150), + ), + 612, + 170 + ); + + $this->glmpdfNextPage(); + + + + + $voucherCount = count($vouchers); + foreach( $vouchers as $t ) + { + + $voucherCount--; + + // Flag to determine if this voucher will be displayed (vouchers not displayed if it's a package ticket) + $displaying_this_voucher = false; + + if (!$couponTest) { + + // Check if the current voucher is a new package that has vouchers that print + if ($t['is_package']['value']) { + + $packageVoucher = true; + + // Check if any vouchers for this package print separately + $ticketPackage = $TicketPackages->getList('package = '.$t['ticket']); + if (is_array($ticketPackage) && count($ticketPackage) > 0) { + + // For each ticket in the package + foreach ($ticketPackage as $tp) { + + // Check if it requires a separate voucher + if ($tp['separate_voucher']['value']) { + + // Set this flag to the package sold ID (same for all vouchers for a package) so we can tell if we hit the end of the package + $packageVouchersPrintedSeparately = $t['package_sold_id']; + $packagePerformanceName = $t['performance_name']; + $packageTicketName = $t['ticket_name']; + } else { + $allPackageVouchersSeparate = false; + } + } + } + + // If we found one, then switch layouts. + if ($packageVouchersPrintedSeparately != '') { + $this->glmpdfSetForms( + $voucher3_coupon0['forms'], + $voucher3_coupon0['layout'], + 'US Letter' + ); + $voucherPageStarted = false; + $skipNextFormAdvance = false; + $doDashes = true; + if ($numb_tickets) { + $skipNextFormAdvance = true; + } + } + + // If we have a package with separate vouchers + } else { + $packageVoucher = false; + } + + if ($packageVouchersPrintedSeparately != '') { + + // Check if we're now past the package that had vouchers printed separately + if ($t['package_sold_id'] != $packageVouchersPrintedSeparately) { + + $this->glmpdfSetForms( + $voucher1_coupon8['forms'], + $voucher1_coupon8['layout'], + 'US Letter' + ); + $voucherPageStarted = false; + $packageVouchersPrintedSeparately = ''; + + } + + } + + // Check if this voucher is a print separate voucher for a package + $printVoucher = false; + if ($t['ticket_package']) { + + // Get ticket_package data + $ticketPackage = $TicketPackages->getList('package = '.$t['ticket_package'].' AND ticket = '.$t['ticket']); + + // If Separate Voucher, override and display voucher. + if ($ticketPackage[0]['separate_voucher']['value']) { + $printVoucher = true; + } + + } else { + $printVoucher = true; + } + + // Check if this is a package voucher and we are printing all package tickets separately + if ($packageVoucher && $allPackageVouchersSeparate) { + $printVoucher = false; + } + + // If this isn't a package ticket (we're not printing separate vouchers at this time) + $voucherPrinted = false; + if ($printVoucher) { + + if ($packageVouchersPrintedSeparately) { + + // If the first voucher page hasn't been set + if (!$voucherPageStarted) { +// $this->glmpdfNextPage(); + $voucherPageStarted = true; + } + + $displaying_this_voucher = true; + + if ($numb_tickets++ > 0) { + + if ($skipNextFormAdvance) { + $skipNextFormAdvance = false; + } else { +// $this->glmpdfNextForm(); + } + } + + + $this->glmpdfSetFont( "Helvetica-Bold", 10 ); +// $this->glmpdfPlaceText( $config->owner->name, 300, 140, "center", 'black', -350, ''); + + // If ticket has already been claimed, then mark ticket + if ($t['time_claimed']['date'] != '') { + $this->glmpdfSetFont( "Times-Bold", 48.0 ); + $this->glmpdfPlaceText( "CLAIMED", 110, 80, "left", 'orangered', 0, '' ); // last parameter can be things like "rotate=90" + } + + // If part of a package, print the package name it's part of. + $packageText = ''; + if ($packageTicketName && !$t['is_package']['value']) { + $packageText = $packageTicketName.' - '; + } + + // Display values + $this->glmpdfSetFont( "Helvetica", 11.0 ); + $this->glmpdfPlaceText( + html_entity_decode($packageText,ENT_QUOTES,"utf-8") + .html_entity_decode($t['performance_name'],ENT_QUOTES,"utf-8") + .' - '.html_entity_decode($t['ticket_name'], ENT_QUOTES,"utf-8"), + 300, 135, "center", 'black', -570, '' ); + + $this->glmpdfSetFont( "Helvetica", 8.5 ); + if ($t['date_specific']['value']) { + $this->glmpdfPlaceText( $t['ticket_date']['date'], 300, $this->glmpdfCurrentY, "center", 'black', -370, '' ); + } else { + $dateRange = 'Valid From '.$t['start_date']['date'].' through '.$t['end_date']['date']; + $this->glmpdfPlaceText( $dateRange, 300, $this->glmpdfCurrentY, "center", 'black', -370, '' ); + } + + // Display address and contact information + $this->glmpdfSetFont( "Helvetica", 8.5 ); + $contactInfo = $this->config->owner->name.' - ' + .$this->config->owner->address1.' - ' + .($this->config->owner->address2 != '' ? ', '.$this->config->owner->address2 : '') + .$this->config->owner->city.', ' + .$this->config->owner->state.' ' + .$this->config->owner->zip.' - ' + .$this->config->owner->phone + .($this->config->owner->toll_free != '' ? ' - '.$this->config->owner->toll_free : ''); + $this->glmpdfPlaceText( html_entity_decode($contactInfo,ENT_QUOTES,"utf-8"), 300, 2, "center", 'black', -380, ''); + + // Print barcode = {ticket_sold ID}-{person type}-{person_sequence} + $barcode = $this->addCheckCode($t['id']); + + // If we're supposed to print barcode and voucher number on ticket + switch ($t['ticket_voucher_type']) { + case 11: + $this->glmpdfSetFont( "Helvetica-Bold", 12.0 ); + $this->glmpdfPlaceText( "Pickup ".$this->config->term->voucher->norm." at ".$this->config->term->prop->norm, 300, 116, 'center', 'red', -224); + $this->glmpdfSetFont( "Helvetica", 12.0 ); + $this->glmpdfPlaceText( $this->config->term->voucher->cap." $barcode", 300, 116, 'center', 'black', -224); + break; + case 12; + $this->glmpdfSetFont( "Helvetica-Bold", 12.0 ); + $this->glmpdfPlaceText( "You will receive ".$this->config->term->voucher->cap." by mail", 510, 116, 'left', 'red', -224); + $this->glmpdfSetFont( "Helvetica", 12.0 ); + $this->glmpdfPlaceText( $this->config->term->voucher->cap." $barcode", 540, 116, 'left', 'black', -224); + break; + case 1: + default: + $this->glmpdfSetFont( 'barcode', 110 ); + $this->glmpdfPlaceText( "*$barcode*", 300, 30, 'center', 'black', 0); + break; + } + + $this->glmpdfSetFont( "Helvetica", 10.0 ); + $this->glmpdfPlaceText( "Order #".$order['id'].' '.$this->config->term->voucher->cap.' '.$barcode, 300, 20, 'center', 'black', 0); + + $voucherPrinted = true; + + // Print a normal voucher + } else { + + // If the first voucher page hasn't been set + if (!$voucherPageStarted) { +// $this->glmpdfNextPage(); + $voucherPageStarted = true; + } + + $displaying_this_voucher = true; + + if ($numb_tickets++ > 0) { + + if ($skipNextFormAdvance) { + $skipNextFormAdvance = false; + } else { +// $this->glmpdfNextForm(); + } + } + + $this->glmpdfSetFont( "Helvetica-Bold", 10 ); + + // If ticket has already been claimed, then mark ticket + if ($t['time_claimed']['date'] != '') { + $this->glmpdfSetFont( "Times-Bold", 48.0 ); + $this->glmpdfPlaceText( "CLAIMED", 110, 80, "left", 'orangered', 0, '' ); // last parameter can be things like "rotate=90" + } + + // If part of a package, print the package name it's part of. + if ($packageTicketName && !$t['is_package']['value']) { + + $this->glmpdfSetFont( "Helvetica-Bold", 10.0 ); + $this->glmpdfPlaceText( 'Part of:', 7, 40, 'left', 'black', 0, 'position=center rotate=90'); + $this->glmpdfSetFont( "Helvetica-Bold", 16.0 ); + $this->glmpdfPlaceText( $packagePerformanceName, 30, 116, 'left', 'black', -224, 'position=center rotate=90'); + $this->glmpdfPlaceText( $packageTicketName, 60, 116, 'left', 'black', -224, 'position=center rotate=90'); + + } + + // Display values + $this->glmpdfSetFont( "Helvetica", 11.0 ); + $this->glmpdfPlaceText( html_entity_decode($t['performance_name'],ENT_QUOTES,"utf-8").' - '.html_entity_decode($t['ticket_name'],ENT_QUOTES,"utf-8"), + 300, 135, "center", 'black', -570, '' ); + + $this->glmpdfSetFont( "Helvetica", 8.5 ); + if ($t['date_specific']['value']) { + $this->glmpdfPlaceText( $t['ticket_date']['date'], 300, $this->glmpdfCurrentY, "center", 'black', -370, '' ); + } else { + $dateRange = 'Valid From '.$t['start_date']['date'].' through '.$t['end_date']['date']; + $this->glmpdfPlaceText( $dateRange, 300, $this->glmpdfCurrentY, "center", 'black', -370, '' ); + } + + // Display address and contact information + $this->glmpdfSetFont( "Helvetica", 8.5 ); + $contactInfo = $this->config->owner->name.' - ' + .$this->config->owner->address1.' - ' + .($this->config->owner->address2 != '' ? ', '.$this->config->owner->address2 : '') + .$this->config->owner->city.', ' + .$this->config->owner->state.' ' + .$this->config->owner->zip.' - ' + .$this->config->owner->phone + .($this->config->owner->toll_free != '' ? ' - '.$this->config->owner->toll_free : ''); + $this->glmpdfPlaceText( html_entity_decode($contactInfo,ENT_QUOTES,"utf-8"), 300, 2, "center", 'black', -380, ''); + + // Print barcode = {ticket_sold ID}-{person type}-{person_sequence} + $barcode = $this->addCheckCode($t['id']); + + // If we're supposed to print barcode and voucher number on ticket + switch ($t['ticket_voucher_type']) { + case 11: + $this->glmpdfSetFont( "Helvetica-Bold", 12.0 ); + $this->glmpdfPlaceText( "Pickup ".$this->config->term->voucher->norm." at ".$this->config->term->prop->norm, 300, 116, 'center', 'red', -224); + $this->glmpdfSetFont( "Helvetica", 12.0 ); + $this->glmpdfPlaceText( $this->config->term->voucher->cap." $barcode", 300, 116, 'center', 'black', -224); + break; + case 12; + $this->glmpdfSetFont( "Helvetica-Bold", 12.0 ); + $this->glmpdfPlaceText( "You will receive ".$this->config->term->voucher->cap." by mail", 510, 116, 'left', 'red', -224); + $this->glmpdfSetFont( "Helvetica", 12.0 ); + $this->glmpdfPlaceText( $this->config->term->voucher->cap." $barcode", 540, 116, 'left', 'black', -224); + break; + case 1: + default: + $this->glmpdfSetFont( 'barcode', 110 ); + $this->glmpdfPlaceText( "*$barcode*", 300, 30, 'center', 'black', 0); + break; + } + + $this->glmpdfSetFont( "Helvetica", 10.0 ); + $this->glmpdfPlaceText( "Order #".$order['id'].' '.$this->config->term->voucher->cap.' '.$barcode, 300, 20, 'center', 'black', 0); + + $voucherPrinted = true; + + + } // End of normal voucher + + if ($voucherPrinted && $voucherCount) { + $this->glmpdfNextForm(); + } + + } // Printing Voucher + + } +/* + if ($displaying_this_voucher) { + if (!$packageVouchersPrintedSeparately) { + } + } +*/ + } // Each voucher + + if ($vc != false) { + $this->dbh->exec("BEGIN;\n".$counterSQL."COMMIT;\n"); + } + + // Close PDF setup and send to user's browser + $this->glmpdfSendToBrowser( '', 'Star_Line_Ticket_Vouchers_Mobile.pdf' ); + + if ($venueImageFile) { + unlink($venueImageFile); + } + if ($parkingImageFile) { + unlink($parkingImageFile); + } + if ($sectionImageFile) { + unlink($sectionImageFile); + } + if ($sectionImageFile) { + unlink($sectionImageFile); + } + + } + + private function displayCoupon($coupon, $xs, $ys) + { + + // Attempt to get the coupon image + $im = $this->getCouponImage( $this->is, $coupon['coupon_image']); + + // Check for stretch + $fit = 'auto'; + if ($coupon['stretch_to_fit']['value']) { + $fit = 'entire'; + } + + // Check for padding - enforce a minimum size + $pad = $coupon['padding']; + + $x = $xs - ($pad * 2); + if ($x < 10) { + $x == 10; + } + $y = $ys - ($pad * 2); + if ($y < 10) { + $y = 10; + } + + // If the image exists + if ($im) { + + // Place the image + $this->glmpdfPlaceImage($im, $pad, $pad, 1, $fit, 'center', $x, $y); + + + // If a border is requested display that + if ($coupon['show_border']['value']) { + $this->glmpdfPlaceBox( $this->borderWidth, 0, $ys, $xs, $ys, $this->borderColor ); + } + + } + + // SQL to Update Counters + $sql = "UPDATE eventmgt.voucher_coupons SET display_count = display_count + 1 WHERE id = ".$coupon['id'].";\n"; + + return $sql; + + } + + /* + * Function to load an image for use in Voucher Ads or Coupons + * + * This function maintains a static array of loaded images. It + * first checks to see if the image has already been loaded and + * returns the existing object if it is. Otherwise it will + * attempt to load the image, store the open image object in the + * static array for future use, and return it. + * + * @param $is object Image Server Object + * @param $imageName string Name of the image to load + * + * @return object Loaded and opened image object or false if not loaded + * + */ + private function getCouponImage( $is, $imageName ) + { + static $images = array(); + + // Check if image has already been loaded + if (isset($images[$imageName])) { + return $images[$imageName]; + } + + // Try to load the image + $imageFile = $is->saveImageToTemp(IMAGE_SERVER_PREFIX.'original/'.$imageName); + if ($imageFile) { + + // Open the image and save it in case it's needeed again + $images[$imageName] = $this->glmpdfOpenImage($imageFile); + + return $images[$imageName]; + + } + + return false; + + } + + /* + * Function to add check character to end of voucher number + * + * Uses config->voucher_check_secret and voucher # to create MD5 string + * then takes last hex character off of that string and shifts it up to + * always be a character (adds 16 to numbers and 10 to the upper-case + * version of the character). + * i.e. 0 = A, 9 = J, A = K, F = + * + */ + public function addCheckCode($voucherNumb) + { + + // Create MD5 string using voucher number and secret + $md5 = md5($voucherNumb.$this->config->voucher_check_secret); + + // Get last character code of the last character in the MD5 + $cc = strtoupper(substr($md5, -2)); + $cc[0] = $this->shiftCheckCodeCharacter($cc[0]); + $cc[1] = $this->shiftCheckCodeCharacter($cc[1]); + + // Return voucher number with the new character on the end + $voucherNumb .= $cc; + return $voucherNumb; + + } + + private function shiftCheckCodeCharacter($c) { + + $x = ord($c); + + // If it's a digit, add 16 + if ($x < 65) { + $x += 17; + // otherwise, add 10 + } else { + $x += 10; + } + + // Also skip the letter O + if (x >= ord('O')) { + $x += 1; + } + + return chr($x); + } + +} // class + +// Absolutely nothing after next line +?> \ No newline at end of file diff --git a/models/vouchers/PointerBoat/voucher.php b/models/vouchers/PointerBoat/voucher.php new file mode 100644 index 0000000..d81a2c1 --- /dev/null +++ b/models/vouchers/PointerBoat/voucher.php @@ -0,0 +1,1183 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: printVoucher.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +require_once PDF_ABSTRACT; +$Pdf = new GlmPdf(); + +/** + * PdfVoucher class + * + * @category PdfVoucher + * @package PDFLib + * @author Chuck Scott + * @license http://www.gaslightmedia.com Gaslightmedia + * @link <> +*/ +class PdfVoucher extends GlmPdf +{ + + public $borderWidth = 1; + public $borderColor = 'black'; + public $pdfCouponInterval = 5; + public $pdfMinCoupons = 3; + public $config; + private $is; + private $dbh; + + function __construct($order, $vouchers, $member, $dbh, $config, $couponTest = false) + { + + $this->dbh = $dbh; + $this->config = $config; + + // Load image server support + require_once IMAGE_SERVER_ABSTRACT; + $this->is = new ImageServerAbstract(); + + // if debug.glmpdf is set in the configs/common.ini file in the CommonApp directory, do grids on PDFs + define ('GLMPDF_DEBUG', $this->config->debug->glmpdf); + + // The following produces a color test sheet. There is no return from that call. + // $this->glmpdfShowValidColors(); exit; + + // Start with cover page. + $this->glmpdfSetForms( + 1, + array( + 1 => array( 'x' => 0, 'y' => 0, 'xs' => 613, 'ys' => 792 ) + ), + 'US Letter' + ); + + // Start page + $this->glmpdfStart( $this->config->owner->name, "Gaslight Media", "Ticket System Receipt/Vouchers" ); + + if( !$this->glmpdfAddFont( 'barcode', 'barcode/FREE3OF9.TTF' ) ) + { + echo 'ERROR: Unable to add barcode font.

    + Did you place the barcode font provided in docs/BarcodeFonts into + a system fonts directory ("/usr/share/fonts/truetype/Barcode")? + Also check the GLMPDF_PDF_FONT_DIR setting in GlmPdf.php.'; + exit; + } + + // Get images to tmp files + if (trim($member['image']) != '') { + $venueImageFile = $this->is->saveImageToTemp(IMAGE_SERVER_PREFIX.'original/'.$member['image']); + if ($venueImageFile) { + $venueImage = $this->glmpdfOpenImage($venueImageFile); + + // If failure getting the image + if ($venueImage == false) { + $venueImageFile = false; + } + } + } else { + $venueImageFile = false; + } + + if (trim($member['parking_map']) != '') { + $parkingImageFile = $this->is->saveImageToTemp(IMAGE_SERVER_PREFIX.'original/'.$member['parking_map']); + if ($parkingImageFile) { + $parkingImage = $this->glmpdfOpenImage($parkingImageFile); + + // If failure getting the image + if ($parkingImage == false) { + $parkingImageFile = false; + } + } + } else { + $parkingImageFile = false; + } + + if (trim($member['ticket_sec_map']) != '') { + $sectionImageFile = $this->is->saveImageToTemp(IMAGE_SERVER_PREFIX.'original/'.$member['ticket_sec_map']); + if ($sectionImageFile) { + $sectionImage = $this->glmpdfOpenImage($sectionImageFile); + + // If failure getting the image + if ($sectionImage == false) { + $sectionImageFile = false; + } + } + } else { + $sectionImageFile = false; + } + + // Load entrance class + require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/entrances.php'; + $Entrances = new EventManagementAdminEntrances($dbh, $config); + + // Load performance class + require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/performances.php'; + $Performances = new EventManagementAdminPerformances($dbh, $config); + + // Load Voucher Coupons class and get coupons list for display + require_once EVENT_MANAGEMENT_APP_BASE.'classes/data/dataVoucherCoupons.php'; + $VoucherCoupons = new EventManagementDataVoucherCoupons($dbh, $config); + + // Load ticket packages data class + require_once EVENT_MANAGEMENT_APP_BASE.'classes/data/dataTicketPackages.php'; + $TicketPackages = new EventManagementDataTicketPackages($dbh, $config); + + + // If no date has been supplied - make it today + if (isset($_REQUEST['date']) && $_REQUEST['date'] != '') { + $date = $_REQUEST['date']; + } else { + $date = date('m/d/Y', time()); + } + + $vc = $VoucherCoupons->getCouponsForDisplay($date); + + // Setup footers +/* + $footer = 'For assistance call '.$this->config->owner->phone; + if ($this->config->owner->toll_free != '') { + $footer .= ' or '.$this->config->owner->toll_free; + } +*/ + + if (!$couponTest) { + + $this->glmpdfNextForm(); + + /* Cover Page */ + + // Header + if ($venueImageFile) { + $coverImage = $this->glmpdfOpenImage($venueImageFile); + $this->glmpdfPlaceImage($coverImage, 30, 690, .5, false, 'center', 280, 140); + } + $this->glmpdfSetFont( "Helvetica-Bold", 18.0 ); // Header Text + $this->glmpdfPlaceText( $config->owner->name, 340, 750, "center", 'black', -400 ); + $this->glmpdfSetFont( "Helvetica", 14.0 ); +// $this->glmpdfPlaceText( $config->owner->short_name." - ".$member['name'], 340, $this->glmpdfCurrentY-10, "center", 'black', -400 ); + $this->glmpdfPlaceText( htmlspecialchars_decode($member['name'], ENT_QUOTES), 340, $this->glmpdfCurrentY-10, "center", 'black', -400 ); + $this->glmpdfPlaceText( $member['addr1'], 340, $this->glmpdfCurrentY, "center", 'black', -400 ); + $this->glmpdfPlaceText( $member['city'].", ".$member['state']['name']." ".$member['zip'], 340, $this->glmpdfCurrentY, "center", 'black', -400 ); + + // Sold To Information + $valCol = 60; + $this->glmpdfSetFont( "Helvetica", 10.0 ); + $this->glmpdfPlaceText( $this->config->term->order->cap." ID: ".trim($order['id']), $valCol, 650, "left", 'black' ); + $this->glmpdfPlaceText( trim($order['fname'].' '.$order['lname']), $valCol, $this->glmpdfCurrentY-5, "left", 'black', -200 ); + $this->glmpdfPlaceText( trim($order['addr1']), $valCol, $this->glmpdfCurrentY-5, "left", 'black', -200 ); + if( trim($order['addr2']) != '' ) + $this->glmpdfPlaceText( trim($order['addr2']), $valCol, $this->glmpdfCurrentY-5, "left", 'black', -200 ); + $this->glmpdfPlaceText( trim($order['city']).', '.$order['state']['value'].' '.trim($order['zip']).' '.$order['country']['value'], $valCol, $this->glmpdfCurrentY-5, "left", 'black', -200 ); + + // Purchace/Charge information + $this->glmpdfSetFont( "Helvetica", 10.0 ); + $promptCol = 330; + $valCol = 420; + $this->glmpdfPlaceText( "Date of Purchase:", $promptCol, 650, "left", 'black' ); + $this->glmpdfPlaceText( $order['purchase_date']['date'], $valCol, $this->glmpdfLastY, "left", 'black', -160 ); + $this->glmpdfPlaceText( "Card Type:", $promptCol, $this->glmpdfCurrentY-5, "left", 'black' ); + $this->glmpdfPlaceText( $order['cctype'], $valCol, $this->glmpdfLastY, "left", 'black', -160 ); + $this->glmpdfPlaceText( "Name on Card:", $promptCol, $this->glmpdfCurrentY-5, "left", 'black' ); + $this->glmpdfPlaceText( $order['ccname'], $valCol, $this->glmpdfLastY, "left", 'black', -160 ); + $this->glmpdfPlaceText( "Card Number:", $promptCol, $this->glmpdfCurrentY-5, "left", 'black' ); + $this->glmpdfPlaceText( $order['ccnumber'], $valCol, $this->glmpdfLastY, "left", 'black', -160 ); + $this->glmpdfPlaceText( "Confirmation:", $promptCol, $this->glmpdfCurrentY-5, "left", 'black' ); + $this->glmpdfPlaceText( $order['ccconf'], $valCol, $this->glmpdfLastY, "left", 'black', -160 ); + $this->glmpdfPlaceText( "Total Charged:", $promptCol, $this->glmpdfCurrentY-5, "left", 'black' ); + $this->glmpdfPlaceText( $order['charge_total'], $valCol, $this->glmpdfLastY, "left", 'black', -160 ); + + // Purchase Summary + $ticNumbCol = 20; + $perfNameCol = 80; + $ticNameCol = 300; + $secNameCol = 450; + $dateCol = 500; + $this->glmpdfPlaceText( '', $ticNumbCol, 550, "center", 'black', 0, ''); + + $this->glmpdfSetFont( "Helvetica", 8.0 ); + $this->glmpdfPlaceText( $this->config->term->voucher->cap, $ticNumbCol, $this->glmpdfCurrentY, "left", 'black', -52, ''); + $this->glmpdfPlaceText( $this->config->term->performance->cap, $perfNameCol, $this->glmpdfLastY, "left", 'black', -110, ''); + $this->glmpdfPlaceText( $this->config->term->ticket->cap, $ticNameCol, $this->glmpdfLastY, "left", 'black', -160, ''); +// $this->glmpdfPlaceText( $this->config->term->section->cap, $secNameCol, $this->glmpdfLastY, "left", 'black', -60, ''); + $this->glmpdfPlaceText( 'Date / Time', $dateCol, $this->glmpdfLastY, "left", 'black', -160, ''); + + $this->glmpdfPlaceText( '', $ticNumbCol, $this->glmpdfCurrentY-3, "center", 'black', 0, ''); + + foreach( $vouchers as $t ) { + + $voucherCode = $this->addCheckCode($t['id']); + + $this->glmpdfSetFont( "Helvetica", 8.0 ); + if (!$t['ticket_package']) { + $this->glmpdfPlaceText( $voucherCode, $ticNumbCol, $this->glmpdfCurrentY, "left", 'black', -52, ''); + } else { + $this->glmpdfPlaceText( '', $ticNumbCol, $this->glmpdfCurrentY, "left", 'black', -52, ''); + } + $memberPerformance = $t['real_member_name'].': '.$t['performance_name']; + $this->glmpdfPlaceText( html_entity_decode($memberPerformance,ENT_QUOTES,"utf-8"), $perfNameCol, $this->glmpdfLastY, "left", 'black', -110, ''); + $this->glmpdfPlaceText( html_entity_decode($t['ticket_name'],ENT_QUOTES,"utf-8"), $ticNameCol, $this->glmpdfLastY, "left", 'black', -160, ''); + if (!$t['is_package']['value']) { +// $this->glmpdfPlaceText( html_entity_decode($t['section_name'],ENT_QUOTES,"utf-8"), $secNameCol, $this->glmpdfLastY, "left", 'black', -60, ''); + if ($t['date_specific']['value']) { + $datetime = $t['ticket_date']['date']; + if ($t['time_specific']['value']) { + $datetime .= ' '.$t['ticket_time']['time']; + } +// $this->glmpdfPlaceText( $t['ticket_date']['date'].'.', $dateCol, $this->glmpdfLastY, "left", 'black', -160, ''); + $this->glmpdfPlaceText( $datetime, $dateCol, $this->glmpdfLastY, "left", 'black', -160, ''); + } else { + $dateRange = 'Valid From '.$t['start_date']['date'].' through '.$t['end_date']['date']; + $this->glmpdfPlaceText( $dateRange, $dateCol, $this->glmpdfLastY, "left", 'black', -160, ''); + } + } + + // Check for Ticket add-ons + if (isset($t['addons_sold']) && count($t['addons_sold']) > 0) { + foreach($t['addons_sold'] as $a) { + + $addonText = $a['add_on_name']; + if (($a['add_on_type']['value']-0) == 2) { + $addonText = $addonText.', '.$a['quant'].' '.$a['unit_name']; + } + $this->glmpdfPlaceText( html_entity_decode($addonText,ENT_QUOTES,"utf-8"), $ticNameCol+10, $this->glmpdfCurrentY, "left", 'black', -240, ''); + } + } + + } + + // Special Needs + $this->glmpdfSetFont( "Helvetica", 9.0 ); + if (trim($order['special_needs']) != '') { + $this->glmpdfPlaceText( "Special Needs:", 20, $this->glmpdfCurrentY-30, "left", 'black' ); + $this->glmpdfPlaceTextBox( $order['special_needs'], 100, $this->glmpdfCurrentY+16, 450, 50, "left", 'black' ); + } + + // General Member Policies + if (trim($member['def_ticket_pol']) != '') { + $this->glmpdfPlaceText( "Policies:", 20, $this->glmpdfCurrentY-30, "left", 'black' ); + $this->glmpdfPlaceTextBox( $member['def_ticket_pol'], 100, $this->glmpdfCurrentY+16, 450, 50, "left", 'black' ); + } + + } + + // Standard voucher & coupon form - 1 Voucher, 8 coupons + $voucher1_coupon8 = array( + 'forms' => 10, + 'layout' => array( + 1 => array( 'x' => 25, 'y' => 515, 'xs' => 560, 'ys' => 232 ), + 2 => array( 'x' => 25, 'y' => 325, 'xs' => 375, 'ys' => 150 ), + 3 => array( 'x' => 415, 'y' => 325, 'xs' => 170, 'ys' => 150 ), + 4 => array( 'x' => 25, 'y' => 160, 'xs' => 170, 'ys' => 150 ), + 5 => array( 'x' => 210, 'y' => 160, 'xs' => 375, 'ys' => 150 ), + 6 => array( 'x' => 25, 'y' => 25, 'xs' => 137, 'ys' => 120 ), + 7 => array( 'x' => 166, 'y' => 25, 'xs' => 137, 'ys' => 120 ), + 8 => array( 'x' => 307, 'y' => 25, 'xs' => 137, 'ys' => 120 ), + 9 => array( 'x' => 448, 'y' => 25, 'xs' => 137, 'ys' => 120 ), + 10 => array( 'x' => 25, 'y' => 25, 'xs' => 419, 'ys' => 120 ), + ) + ); + + // No voucher & coupon form - 9 Coupons + $voucher0_coupon9 = array( + 'forms' => 9, + 'layout' => array( + // 1 => array( 'x' => 25, 'y' => 515, 'xs' => 560, 'ys' => 232 ), + 1 => array( 'x' => 25, 'y' => 325, 'xs' => 375, 'ys' => 150 ), + 2 => array( 'x' => 415, 'y' => 325, 'xs' => 170, 'ys' => 150 ), + 3 => array( 'x' => 25, 'y' => 160, 'xs' => 170, 'ys' => 150 ), + 4 => array( 'x' => 210, 'y' => 160, 'xs' => 375, 'ys' => 150 ), + 5 => array( 'x' => 25, 'y' => 25, 'xs' => 137, 'ys' => 120 ), + 6 => array( 'x' => 166, 'y' => 25, 'xs' => 137, 'ys' => 120 ), + 7 => array( 'x' => 307, 'y' => 25, 'xs' => 137, 'ys' => 120 ), + 8 => array( 'x' => 448, 'y' => 25, 'xs' => 137, 'ys' => 120 ), + 9 => array( 'x' => 25, 'y' => 25, 'xs' => 419, 'ys' => 120 ), + ) + ); + + // Package vouchers - 3 vouchers, no coupons + $voucher3_coupon0 = array( + 'forms' => 3, + 'layout' => array( + 1 => array( 'x' => 25, 'y' => 531, 'xs' => 560, 'ys' => 176 ), + 2 => array( 'x' => 25, 'y' => 284, 'xs' => 560, 'ys' => 176 ), + 3 => array( 'x' => 25, 'y' => 35, 'xs' => 560, 'ys' => 176 ) + ) + ); + + // Now setup ticket forms + $this->glmpdfSetForms( + $voucher3_coupon0['forms'], + $voucher3_coupon0['layout'], + 'US Letter' + ); + +/*********CPS + // Display Parking Map + if ($parkingImage) { + $this->glmpdfNextForm(); + $this->glmpdfPlaceImage( $parkingImage, 0, 2, 0, 'meet', 'center', 280, 125); + $this->glmpdfSetFont( "Helvetica-Bold", 10.0 ); + $this->glmpdfPlaceText( 'Parking Map', 140, 130, "center", 'black' ); + } + + // Display Section Map + if ($sectionImage) { + $this->glmpdfNextForm(); + $this->glmpdfPlaceImage( $sectionImage, 0, 2, 0, 'meet', 'center', 280, 125); + $this->glmpdfSetFont( "Helvetica-Bold", 10.0 ); + $this->glmpdfPlaceText( 'Section Map', 140, 130, "center", 'black' ); + } +*/ + + // Clear performance image loaded flag + $performanceLoaded = false; + +// $this->glmpdfNextPage(); + $firstVoucherPageSet = false; + + // Process Vouchers - For each type of ticket purchased + $numb_tickets = 0; + $counterSQL = ''; + $packageVouchersPrintedSeparately = ''; + $allPackageVouchersSeparate = true; + $packageVoucher = false; + $packageTicketName = ''; + $doDashes = false; + $skipNextFormAdvance = false; + + foreach( $vouchers as $t ) + { + + // Fix member output + $t['member_name'] = htmlspecialchars_decode($t['member_name'], ENT_QUOTES); + + + // Flag to determine if this voucher will be displayed (vouchers not displayed if it's a package ticket) + $displaying_this_voucher = false; + + if (!$couponTest) { + + // Check if the current voucher is a new package that has vouchers that print + if ($t['is_package']['value']) { + + $packageVoucher = true; + + // Check if any vouchers for this package print separately + $ticketPackage = $TicketPackages->getList('package = '.$t['ticket']); + if (is_array($ticketPackage) && count($ticketPackage) > 0) { + + // For each ticket in the package + foreach ($ticketPackage as $tp) { + + // Check if it requires a separate voucher + if ($tp['separate_voucher']['value']) { + + // Set this flag to the package sold ID (same for all vouchers for a package) so we can tell if we hit the end of the package + $packageVouchersPrintedSeparately = $t['package_sold_id']; + $packagePerformanceName = $t['performance_name']; + $packageTicketName = $t['ticket_name']; + } else { + $allPackageVouchersSeparate = false; + } + } + } + + // If we found one, then switch layouts. + if ($packageVouchersPrintedSeparately != '') { + $this->glmpdfSetForms( + $voucher3_coupon0['forms'], + $voucher3_coupon0['layout'], + 'US Letter' + ); + $voucherPageStarted = false; + $skipNextFormAdvance = false; + $doDashes = true; + if ($numb_tickets) { + $skipNextFormAdvance = true; + } + } + + // If we have a package with separate vouchers + } else { + $packageVoucher = false; + } +/* + if ($packageVouchersPrintedSeparately != '') { + + // Check if we're now past the package that had vouchers printed separately + if ($t['package_sold_id'] != $packageVouchersPrintedSeparately) { + + $this->glmpdfSetForms( + $voucher1_coupon8['forms'], + $voucher1_coupon8['layout'], + 'US Letter' + ); + $voucherPageStarted = false; + $packageVouchersPrintedSeparately = ''; + $skipNextFormAdvance = true; + } + + } +*/ + + // Check if this voucher is a print separate voucher for a package + $printVoucher = false; + if ($t['ticket_package']) { + + // Get ticket_package data + $ticketPackage = $TicketPackages->getList('package = '.$t['ticket_package'].' AND ticket = '.$t['ticket']); + + // If Separate Voucher, override and display voucher. + if ($ticketPackage[0]['separate_voucher']['value']) { + $printVoucher = true; + } + + } else { + $printVoucher = true; + } + + // Check if this is a package voucher and we are printing all package tickets separately + if ($packageVoucher && $allPackageVouchersSeparate) { + $printVoucher = false; + } + + // If this isn't a package ticket (we're not printing separate vouchers at this time) + if ($printVoucher) { + + if ($packageVouchersPrintedSeparately) { + + // If the first voucher page hasn't been set + if (!$voucherPageStarted) { + $this->glmpdfNextPage(); + $voucherPageStarted = true; + + if ($doDashes) { + // Print perforations + $this->glmpdfPlaceLine(1, 0, -38, 560, -38, $color = "dimgray", $dash = true, $d_a = 1, $d_b = 5); + $this->glmpdfPlaceLine(1, 0, -291, 560, -291, $color = "dimgray", $dash = true, $d_a = 1, $d_b = 5); + $doDashes = false; + } + + } + + $displaying_this_voucher = true; + + if ($numb_tickets++ > 0) { + + if ($skipNextFormAdvance) { + $skipNextFormAdvance = false; + } else { + $this->glmpdfNextForm(); + } + } + $this->glmpdfPlaceBox( $this->borderWidth, 0, 176, 560, 176, $this->borderColor ); + + // Display Logo - Only get performance image if it's not currently loaded + if ($performanceLoaded != $t['performance']) { + + $performanceDetail = $Performances->getPerformanceDetail($t['performance']); + + // If we have an image but it's the wrong one, dump the temp file + if ($performanceImageFile) { + unlink($performanceImageFile); + } + + // This performance image is not currently loaded - so do that now + + $performanceImageFile = $this->is->saveImageToTemp(IMAGE_SERVER_PREFIX.'original/'.$performanceDetail['image']); + if ($performanceImageFile) { + // If we have the image, then load it + $performanceImage = $this->glmpdfOpenImage($performanceImageFile); + $performanceLoaded = $t['performance']; + } else { + + // otherwise, try the venue image + $performanceLoaded = $venueImage; + } + + } + + // If we have the performance image, display it + $haveTopImage = false; + if ($performanceImage) { + $this->glmpdfPlaceImage( $performanceImage, 85, 100, 1, 'meet', 'center', 70, 75); + $haveTopImage = true; + } elseif ($venueImageFile) { + $this->glmpdfPlaceImage($coverImage, 85, 100, 1, 'meet', 'center', 70, 75); + $haveTopImage = true; + } + + // Place owner name at top possitioned by whether or not there's an image supplied + $this->glmpdfSetFont( "Helvetica-Bold", 20.0 ); + if ($haveTopImage) { + $this->glmpdfPlaceText( $config->owner->name, 315, 131, "center", 'black', -300, ''); + } else { + $this->glmpdfPlaceText( $config->owner->name, 280, 131, "center", 'black', -350, ''); + } + + // If ticket has already been claimed, then mark ticket + if ($t['time_claimed']['date'] != '') { + $this->glmpdfSetFont( "Times-Bold", 72.0 ); + $this->glmpdfPlaceText( "CLAIMED", 110, 80, "left", 'orangered', 0, '' ); // last parameter can be things like "rotate=90" + } + + // Ticket Information Area + $this->glmpdfPlaceLine(1, 80, 0, 80, 176, $color = "black", $dash = false, $d_a = 1, $d_b = 1); + $this->glmpdfPlaceLine(1, 480, 0, 480, 176, $color = "black", $dash = false, $d_a = 1, $d_b = 1); + + // If part of a package, print the package name it's part of. + if ($packageTicketName && !$t['is_package']['value']) { + + $this->glmpdfSetFont( "Helvetica-Bold", 10.0 ); + $this->glmpdfPlaceText( 'Part of:', 7, 40, 'left', 'black', 0, 'position=center rotate=90'); + $this->glmpdfSetFont( "Helvetica-Bold", 12.0 ); + $this->glmpdfPlaceText( $packagePerformanceName, 30, 88, 'left', 'black', -165, 'position=center rotate=90'); + $this->glmpdfPlaceText( $packageTicketName, 60, 88, 'left', 'black', -165, 'position=center rotate=90'); + + } else { + + // Left End of Ticket - NOTE: use only "left" in glmpdfPlaceText - use "position=..." in optlist instead. + if (($t['entrance']-0) > 0) { + $entranceDetail = $Entrances->getEntranceDetail($t['entrance']); + $this->glmpdfPlaceBox(1, 0, 0, 80, -232, '', $entranceDetail['color']['name'], 'miter'); + } + + $this->glmpdfSetFont( "Helvetica-Bold", 10.0 ); + $this->glmpdfPlaceText( 'Departing from:', 7, 40, 'left', 'black', 0, 'position=center rotate=90'); + $this->glmpdfSetFont( "Helvetica-Bold", 16.0 ); + $this->glmpdfPlaceText( strtoupper(html_entity_decode($t['entrance_name'],ENT_QUOTES,"utf-8")), 30, 116, 'left', 'black', -224, 'position=center rotate=90'); + $this->glmpdfPlaceText( strtoupper(html_entity_decode($t['member_name'],ENT_QUOTES,"utf-8")), 60, 116, 'left', 'black', -224, 'position=center rotate=90'); + + } + + // Display values + $this->glmpdfSetFont( "Helvetica-Bold", 16.0 ); + $this->glmpdfPlaceText( html_entity_decode($t['performance_name'],ENT_QUOTES,"utf-8"), 280, 91, "center", 'black', -370, ''); + $this->glmpdfSetFont( "Helvetica-Bold", 12.0 ); + $this->glmpdfPlaceText( html_entity_decode($t['ticket_name'],ENT_QUOTES,"utf-8"), 280, 77, "center", 'black', -370, '' ); + + $this->glmpdfSetFont( "Helvetica", 10.0 ); + if ($t['date_specific']['value']) { + $this->glmpdfPlaceText( $t['ticket_date']['date'], 280, 65, "center", 'black', -370, '' ); + } else { + $dateRange = 'Valid From '.$t['start_date']['date'].' through '.$t['end_date']['date']; + $this->glmpdfPlaceText( $dateRange, 280, 65, "center", 'black', -370, '' ); + } + + $this->glmpdfSetFont( "Helvetica", 16.0 ); + + // Put package line for voucher here + + // Check for Ticket add-ons +/* No addons for packages + if (isset($t['addons_sold']) && count($t['addons_sold']) > 0) { + $this->glmpdfSetFont( "Helvetica", 14.0 ); + foreach($t['addons_sold'] as $a) { + $addonText = $a['add_on_name']; + if (($a['add_on_type']['value']-0) == 2) { + $addonText = $addonText.', '.$a['quant'].' '.$a['unit_name']; + } + $this->glmpdfPlaceText( $addonText, 280, $this->glmpdfCurrentY, "center", 'black', -370, '' ); + } + } +*/ + // Non-Refundable and other Fixed text for body of Voucher + $this->glmpdfSetFont( "Helvetica", 10.0 ); + $this->glmpdfPlaceText( "NON-REFUNDABLE", 280, $this->glmpdfCurrentY, "center", 'black', -300, ''); + + // Display address and contact information + $this->glmpdfSetFont( "Helvetica", 10.0 ); + $contactInfo = $this->config->owner->name.' - ' + .$this->config->owner->address1.' - ' + .($this->config->owner->address2 != '' ? ', '.$this->config->owner->address2 : '') + .$this->config->owner->city.', ' + .$this->config->owner->state.' ' + .$this->config->owner->zip.' - ' + .$this->config->owner->phone + .($this->config->owner->toll_free != '' ? ' - '.$this->config->owner->toll_free : ''); + $this->glmpdfPlaceText( html_entity_decode($contactInfo,ENT_QUOTES,"utf-8"), 280, 25, "center", 'black', -380, ''); + + // Display additional voucher text at the bottom of the voucher if provided + $voucherText = ''; + if (trim($t['ticket_voucher_text']) != '') { + $voucherText = trim(html_entity_decode($t['ticket_voucher_text'],ENT_QUOTES,"utf-8")); + } elseif (trim($performanceDetail['voucher_text']) != '') { + $voucherText = trim(html_entity_decode($performanceDetail['voucher_text'],ENT_QUOTES,"utf-8")); + } + if ($voucherText != '') { + $this->glmpdfPlaceLine(1, 80, 20, 480, 20, 'black', false); + $this->glmpdfSetFont( "Helvetica-Bold", 10.0 ); + // $this->glmpdfPlaceBox(1, 80, 20, 400, 20, "black", "black"); + $this->glmpdfPlaceText( html_entity_decode($voucherText,ENT_QUOTES,"utf-8"), 280, 6, "center", 'black', -370, '' ); + } + + // $this->glmpdfPlaceText( $t['ticket_date']['date'].' - '.$t['ticket_time']['time'], 120, $this->glmpdfCurrentY, "left", 'black', 0, '' ); + + // Print barcode = {ticket_sold ID}-{person type}-{person_sequence} + $barcode = $this->addCheckCode($t['id']); + + // If we're supposed to print barcode and voucher number on ticket + switch ($t['ticket_voucher_type']) { + case 11: + $this->glmpdfSetFont( "Courier-Bold", 10.0 ); + $this->glmpdfPlaceText( "Pickup ".$this->config->term->voucher->norm." at ".$this->config->term->prop->norm, 510, 88, 'left', 'red', -170, 'position=center rotate=90'); + $this->glmpdfSetFont( "Courier", 12.0 ); + $this->glmpdfPlaceText( $this->config->term->voucher->cap." $barcode", 540, 88, 'left', 'black', -170, 'position=center rotate=90'); + break; + case 12; + $this->glmpdfSetFont( "Courier-Bold", 10.0 ); + $this->glmpdfPlaceText( "You will receive ".$this->config->term->voucher->cap." by mail", 510, 88, 'left', 'red', -170, 'position=center rotate=90'); + $this->glmpdfSetFont( "Courier", 12.0 ); + $this->glmpdfPlaceText( $this->config->term->voucher->cap." $barcode", 540, 88, 'left', 'black', -170, 'position=center rotate=90'); + break; + case 1: + default: + $this->glmpdfSetFont( 'barcode', 40 ); + $this->glmpdfPlaceText( "*$barcode*", 510, 88, 'left', 'black', 0, 'position=center rotate=90'); + $this->glmpdfSetFont( "Courier", 10.0 ); + $this->glmpdfPlaceText( $this->config->term->voucher->cap." $barcode", 540, 88, 'left', 'black', -224, 'position=center rotate=90'); + break; + } + + $this->glmpdfPlaceText( "Order #".$order['id'], 552, 88, 'left', 'black', 0, 'position=center rotate=90'); + + // Display Footer + $this->glmpdfSetFont( "Helvetica-Bold", 8.5 ); + $this->glmpdfPlaceText( $footer, 140.5, 2, "center", 'darkblue' ); + + + // Print a normal voucher + } else { + + // If the first voucher page hasn't been set + if (!$voucherPageStarted) { + $this->glmpdfNextPage(); + $voucherPageStarted = true; + + if ($doDashes) { + // Print perforations + $this->glmpdfPlaceLine(1, 0, -11, 560, -11, $color = "dimgray", $dash = true, $d_a = 1, $d_b = 5); + $this->glmpdfPlaceLine(1, 0, -265, 560, -265, $color = "dimgray", $dash = true, $d_a = 1, $d_b = 5); + $doDashes = false; + } + + } + + $displaying_this_voucher = true; + + if ($numb_tickets++ > 0) { + + if ($skipNextFormAdvance) { + $skipNextFormAdvance = false; + } else { + $this->glmpdfNextForm(); + } + } + $this->glmpdfPlaceBox( $this->borderWidth, 0, 232, 560, 232, $this->borderColor ); + + // Display Logo - Only get performance image if it's not currently loaded + if ($performanceLoaded != $t['performance']) { + + $performanceDetail = $Performances->getPerformanceDetail($t['performance']); + + // If we have an image but it's the wrong one, dump the temp file + if ($performanceImageFile) { + unlink($performanceImageFile); + } + + // This performance image is not currently loaded - so do that now + + $performanceImageFile = $this->is->saveImageToTemp(IMAGE_SERVER_PREFIX.'original/'.$performanceDetail['image']); + if ($performanceImageFile) { + // If we have the image, then load it + $performanceImage = $this->glmpdfOpenImage($performanceImageFile); + $performanceLoaded = $t['performance']; + } else { + + // otherwise, try the venue image + $performanceLoaded = $venueImage; + } + + } + + // If we have the performance image, display it + $haveTopImage = false; + if ($performanceImage) { + $this->glmpdfPlaceImage( $performanceImage, 85, 154, 1, 'meet', 'center', 70, 75); + $haveTopImage = true; + } elseif ($venueImageFile) { + $this->glmpdfPlaceImage($coverImage, 85, 154, 1, 'meet', 'center', 70, 75); + $haveTopImage = true; + } + + // Place members at top possitioned by whether or not there's an image supplied + $this->glmpdfSetFont( "Helvetica-Bold", 20.0 ); + if ($haveTopImage) { + $this->glmpdfPlaceText( $t['member_name'], 315, 185, "center", 'black', -300, ''); + } else { + $this->glmpdfPlaceText( $t['member_name'], 280, 185, "center", 'black', -350, ''); + } + + // If ticket has already been claimed, then mark ticket + if ($t['time_claimed']['date'] != '') { + $this->glmpdfSetFont( "Times-Bold", 72.0 ); + $this->glmpdfPlaceText( "CLAIMED", 110, 80, "left", 'orangered', 0, '' ); // last parameter can be things like "rotate=90" + } + + // Ticket Information Area + $this->glmpdfPlaceLine(1, 80, 0, 80, 232, $color = "black", $dash = false, $d_a = 1, $d_b = 1); + $this->glmpdfPlaceLine(1, 480, 0, 480, 232, $color = "black", $dash = false, $d_a = 1, $d_b = 1); + + // If part of a package, print the package name it's part of. + if ($packageTicketName && !$t['is_package']['value']) { + + $this->glmpdfSetFont( "Helvetica-Bold", 10.0 ); + $this->glmpdfPlaceText( 'Part of:', 7, 40, 'left', 'black', 0, 'position=center rotate=90'); + $this->glmpdfSetFont( "Helvetica-Bold", 16.0 ); + $this->glmpdfPlaceText( $packagePerformanceName, 30, 116, 'left', 'black', -224, 'position=center rotate=90'); + $this->glmpdfPlaceText( $packageTicketName, 60, 116, 'left', 'black', -224, 'position=center rotate=90'); + + } else { + + // Voucher left end text overrides departing from text + if ($t['ticket_voucher_leftend_text'] != '') { + $this->glmpdfPlaceBox(1, 0, 0, 80, -232, '', 'lightlilac', 'miter'); + $this->glmpdfSetFont( "Helvetica-Bold", 16.0 ); + $this->glmpdfPlaceText( strtoupper(html_entity_decode($t['ticket_voucher_leftend_text'],ENT_QUOTES,"utf-8")), 40, 116, 'left', 'black', -224, 'position=center rotate=90'); + } else { + // Left End of Ticket - NOTE: use only "left" in glmpdfPlaceText - use "position=..." in optlist instead. + if (($t['entrance']-0) > 0) { + $entranceDetail = $Entrances->getEntranceDetail($t['entrance']); + $this->glmpdfPlaceBox(1, 0, 0, 80, -232, '', $entranceDetail['color']['name'], 'miter'); + } + + $this->glmpdfSetFont( "Helvetica-Bold", 10.0 ); + $this->glmpdfPlaceText( 'Departing from:', 7, 40, 'left', 'black', 0, 'position=center rotate=90'); + $this->glmpdfSetFont( "Helvetica-Bold", 16.0 ); + + $this->glmpdfPlaceText( strtoupper(htmlspecialchars_decode($t['entrance_name'],ENT_QUOTES)), 30, 116, 'left', 'black', -224, 'position=center rotate=90'); +// $this->glmpdfPlaceText( strtoupper(html_entity_decode($t['member_name'],ENT_QUOTES,"utf-8")), 45, 116, 'left', 'black', -224, 'position=center rotate=90'); + } + } + + // Display values + $this->glmpdfSetFont( "Helvetica-Bold", 20.0 ); +// $this->glmpdfPlaceText( html_entity_decode($t['real_member_name'],ENT_QUOTES,"utf-8"), 280, 135, "center", 'black', -370, ''); + $this->glmpdfSetFont( "Helvetica-Bold", 18.0 ); + $this->glmpdfPlaceText( html_entity_decode($t['ticket_name'],ENT_QUOTES,"utf-8"), 280, 135, "center", 'black', -370, '' ); + + $this->glmpdfSetFont( "Helvetica", 14.0 ); + if ($t['date_specific']['value']) { + + $datetime = $t['ticket_date']['date']; + if ($t['time_specific']['value']) { + $datetime .= ' '.$t['ticket_time']['time']; + } +// $this->glmpdfPlaceText( $t['ticket_date']['date'], 280, 96, "center", 'black', -370, '' ); + $this->glmpdfPlaceText( $datetime, 280, 114, "center", 'black', -370, '' ); + } else { + $dateRange = 'Valid From '.$t['start_date']['date'].' through '.$t['end_date']['date']; + $this->glmpdfPlaceText( $dateRange, 280, 96, "center", 'black', -370, '' ); + } + + $this->glmpdfSetFont( "Helvetica", 16.0 ); + + // Put package line for voucher here + + // Check for Ticket add-ons + if (isset($t['addons_sold']) && count($t['addons_sold']) > 0) { + $this->glmpdfSetFont( "Helvetica", 14.0 ); + foreach($t['addons_sold'] as $a) { + $addonText = $a['add_on_name']; + if (($a['add_on_type']['value']-0) == 2) { + $addonText = $addonText.', '.$a['quant'].' '.$a['unit_name']; + } + $this->glmpdfPlaceText( $addonText, 280, $this->glmpdfCurrentY, "center", 'black', -370, '' ); + } + } + + // Non-Refundable and other Fixed text for body of Voucher + $this->glmpdfSetFont( "Helvetica", 12.0 ); + $this->glmpdfPlaceText( "NON-REFUNDABLE", 280, $this->glmpdfCurrentY, "center", 'black', -300, ''); + + // Display address and contact information + $this->glmpdfSetFont( "Helvetica", 12.0 ); + $contactInfo = $this->config->owner->name.' - ' + .$this->config->owner->address1.' - ' + .($this->config->owner->address2 != '' ? ', '.$this->config->owner->address2 : '') + .$this->config->owner->city.', ' + .$this->config->owner->state.' ' + .$this->config->owner->zip.' - ' + .$this->config->owner->phone + .($this->config->owner->toll_free != '' ? ' - '.$this->config->owner->toll_free : ''); + $this->glmpdfPlaceText( html_entity_decode($contactInfo,ENT_QUOTES,"utf-8"), 280, 25, "center", 'black', -380, ''); + + // Display additional voucher text at the bottom of the voucher if provided + $voucherText = ''; + if (trim($t['ticket_voucher_text']) != '') { + $voucherText = trim(html_entity_decode($t['ticket_voucher_text'],ENT_QUOTES,"utf-8")); + } elseif (trim($performanceDetail['voucher_text']) != '') { + $voucherText = trim(html_entity_decode($performanceDetail['voucher_text'],ENT_QUOTES,"utf-8")); + } + if ($voucherText != '') { + $this->glmpdfPlaceLine(1, 80, 20, 480, 20, 'black', false); + $this->glmpdfSetFont( "Helvetica-Bold", 14.0 ); + // $this->glmpdfPlaceBox(1, 80, 20, 400, 20, "black", "black"); + $this->glmpdfPlaceText( html_entity_decode($voucherText,ENT_QUOTES,"utf-8"), 280, 6, "center", 'black', -370, '' ); + } + + // $this->glmpdfPlaceText( $t['ticket_date']['date'].' - '.$t['ticket_time']['time'], 120, $this->glmpdfCurrentY, "left", 'black', 0, '' ); + + // Print barcode = {ticket_sold ID}-{person type}-{person_sequence} + $barcode = $this->addCheckCode($t['id']); + + // If we're supposed to print barcode and voucher number on ticket + switch ($t['ticket_voucher_type']) { + case 11: + $this->glmpdfSetFont( "Courier-Bold", 12.0 ); + $this->glmpdfPlaceText( "Pickup ".$this->config->term->voucher->norm." at ".$this->config->term->prop->norm, 510, 116, 'left', 'red', -224, 'position=center rotate=90'); + $this->glmpdfSetFont( "Courier", 12.0 ); + $this->glmpdfPlaceText( $this->config->term->voucher->cap." $barcode", 540, 116, 'left', 'black', -224, 'position=center rotate=90'); + break; + case 12; + $this->glmpdfSetFont( "Courier-Bold", 12.0 ); + $this->glmpdfPlaceText( "You will receive ".$this->config->term->voucher->cap." by mail", 510, 116, 'left', 'red', -224, 'position=center rotate=90'); + $this->glmpdfSetFont( "Courier", 12.0 ); + $this->glmpdfPlaceText( $this->config->term->voucher->cap." $barcode", 540, 116, 'left', 'black', -224, 'position=center rotate=90'); + break; + case 1: + default: + $this->glmpdfSetFont( 'barcode', 48 ); + $this->glmpdfPlaceText( "*$barcode*", 510, 116, 'left', 'black', 0, 'position=center rotate=90'); + $this->glmpdfSetFont( "Courier", 12.0 ); + $this->glmpdfPlaceText( $this->config->term->voucher->cap." $barcode", 540, 116, 'left', 'black', -224, 'position=center rotate=90'); + break; + } + + $this->glmpdfPlaceText( "Order #".$order['id'], 552, 116, 'left', 'black', 0, 'position=center rotate=90'); + + // Display Footer + $this->glmpdfSetFont( "Helvetica-Bold", 8.5 ); + $this->glmpdfPlaceText( $footer, 140.5, 2, "center", 'darkblue' ); + + } // End of normal voucher + + } // Printing Voucher + + } + } // Each voucher + + +// if ($displaying_this_voucher) { + + $haveActiveCoupons = false; + if (isset($vc) && is_array($vc) && count($vc) > 0) { + foreach($vc as $c) { + $k = key($c); + if ($c[$k]['max_display_count'] < 0 || ($c[$k]['max_display_count'] > $c[$k]['display_count'])) { + $haveActiveCoupons = true; + } + } + } + if ($haveActiveCoupons) { + $this->glmpdfNextForm(); + $this->glmpdfSetForms( + $voucher0_coupon9['forms'], + $voucher0_coupon9['layout'], + 'US Letter' + ); + + // Get table of Ads/Coupons + if (isset($vc[1])) { + + // Get the key for the current ad/coupon for position 1 + $k = key($vc[1]); + + // If the max count is -1 (unlimited) or more than the current display count + if ($vc[1][$k]['max_display_count'] < 0 || $vc[1][$k]['max_display_count'] > $vc[1][$k]['display_count']) { + + // Display the ad/coupon and save SQL to update the display count + $counterSQL .= $this->displayCoupon(current($vc[1]), 375, 150); + + // Incriment the local display count + $vc[1][$k]['display_count']++; + } + + // Advance to the next ad/coupon for this position. If all used, start over. + if (next($vc[1]) === false) { + reset($vc[1]); + } + } + + // Advance to the next form + $this->glmpdfNextForm(); + + // Do the same for the remaining ad/coupon forms + + if (isset($vc[2])) { + $k = key($vc[2]); + if ($vc[2][$k]['max_display_count'] < 0 || $vc[2][$k]['max_display_count'] > $vc[2][$k]['display_count']) { + $counterSQL .= $this->displayCoupon(current($vc[2]), 170, 150); + $vc[2][$k]['display_count']++; + } + if (next($vc[2]) === false) { + reset($vc[2]); + } + } + $this->glmpdfNextForm(); + + if (isset($vc[3])) { + $k = key($vc[3]); + if ($vc[3][$k]['max_display_count'] < 0 || $vc[3][$k]['max_display_count'] > $vc[3][$k]['display_count']) { + $counterSQL .= $this->displayCoupon(current($vc[3]), 170, 150); + $vc[3][$k]['display_count']++; + } + if (next($vc[3]) === false) { + reset($vc[3]); + } + } + $this->glmpdfNextForm(); + + if (isset($vc[4])) { + $k = key($vc[4]); + if ($vc[4][$k]['max_display_count'] < 0 || $vc[4][$k]['max_display_count'] > $vc[4][$k]['display_count']) { + $counterSQL .= $this->displayCoupon(current($vc[4]), 375, 150); + $vc[4][$k]['display_count']++; + } + if (next($vc[4]) === false) { + reset($vc[4]); + } + } + $this->glmpdfNextForm(); + + if (isset($vc[5])) { + $k = key($vc[5]); + if ($vc[5][$k]['max_display_count'] < 0 || $vc[5][$k]['max_display_count'] > $vc[5][$k]['display_count']) { + $counterSQL .= $this->displayCoupon(current($vc[5]), 137, 120); + $vc[5][$k]['display_count']++; + } + if (next($vc[5]) === false) { + reset($vc[5]); + } + } + $this->glmpdfNextForm(); + + if (isset($vc[6])) { + $k = key($vc[6]); + if ($vc[6][$k]['max_display_count'] < 0 || $vc[6][$k]['max_display_count'] > $vc[6][$k]['display_count']) { + $counterSQL .= $this->displayCoupon(current($vc[6]), 137, 120); + $vc[6][$k]['display_count']++; + } + if (next($vc[6]) === false) { + reset($vc[6]); + } + } + $this->glmpdfNextForm(); + + if (isset($vc[7])) { + $k = key($vc[7]); + if ($vc[7][$k]['max_display_count'] < 0 || $vc[7][$k]['max_display_count'] > $vc[7][$k]['display_count']) { + $counterSQL .= $this->displayCoupon(current($vc[7]), 137, 120); + $vc[7][$k]['display_count']++; + } + if (next($vc[7]) === false) { + reset($vc[7]); + } + } + $this->glmpdfNextForm(); + + if (isset($vc[8])) { + $k = key($vc[8]); + if ($vc[8][$k]['max_display_count'] < 0 || $vc[8][$k]['max_display_count'] > $vc[8][$k]['display_count']) { + $counterSQL .= $this->displayCoupon(current($vc[8]), 137, 120); + $vc[8][$k]['display_count']++; + } + if (next($vc[8]) === false) { + reset($vc[8]); + } + } + $this->glmpdfNextForm(); + + if (isset($vc[9])) { + $k = key($vc[9]); + if ($vc[9][$k]['max_display_count'] < 0 || $vc[9][$k]['max_display_count'] > $vc[9][$k]['display_count']) { + $counterSQL .= $this->displayCoupon(current($vc[9]), 419, 120); + $vc[9][$k]['display_count']++; + } + if (next($vc[9]) === false) { + reset($vc[9]); + } + } + + } +// } + +// } // Each voucher + + if ($vc != false) { + $this->dbh->exec("BEGIN;\n".$counterSQL."COMMIT;\n"); + } + + // Close PDF setup and send to user's browser + $this->glmpdfSendToBrowser( '', 'Star_Line_Ticket_Vouchers.pdf' ); + + if ($venueImageFile) { + unlink($venueImageFile); + } + if ($parkingImageFile) { + unlink($parkingImageFile); + } + if ($sectionImageFile) { + unlink($sectionImageFile); + } + if ($sectionImageFile) { + unlink($sectionImageFile); + } + + } + + private function displayCoupon($coupon, $xs, $ys) + { + + // Attempt to get the coupon image + $im = $this->getCouponImage( $this->is, $coupon['coupon_image']); + + // Check for stretch + $fit = 'auto'; + if ($coupon['stretch_to_fit']['value']) { + $fit = 'entire'; + } + + // Check for padding - enforce a minimum size + $pad = $coupon['padding']; + + $x = $xs - ($pad * 2); + if ($x < 10) { + $x == 10; + } + $y = $ys - ($pad * 2); + if ($y < 10) { + $y = 10; + } + + // If the image exists + if ($im) { + + // Place the image + $this->glmpdfPlaceImage($im, $pad, $pad, 1, $fit, 'center', $x, $y); + + + // If a border is requested display that + if ($coupon['show_border']['value']) { + $this->glmpdfPlaceBox( $this->borderWidth, 0, $ys, $xs, $ys, $this->borderColor ); + } + + } + + // SQL to Update Counters + $sql = "UPDATE eventmgt.voucher_coupons SET display_count = display_count + 1 WHERE id = ".$coupon['id'].";\n"; + + return $sql; + + } + + /* + * Function to load an image for use in Voucher Ads or Coupons + * + * This function maintains a static array of loaded images. It + * first checks to see if the image has already been loaded and + * returns the existing object if it is. Otherwise it will + * attempt to load the image, store the open image object in the + * static array for future use, and return it. + * + * @param $is object Image Server Object + * @param $imageName string Name of the image to load + * + * @return object Loaded and opened image object or false if not loaded + * + */ + private function getCouponImage( $is, $imageName ) + { + static $images = array(); + + // Check if image has already been loaded + if (isset($images[$imageName])) { + return $images[$imageName]; + } + + // Try to load the image + $imageFile = $is->saveImageToTemp(IMAGE_SERVER_PREFIX.'original/'.$imageName); + if ($imageFile) { + + // Open the image and save it in case it's needeed again + $images[$imageName] = $this->glmpdfOpenImage($imageFile); + + return $images[$imageName]; + + } + + return false; + + } + + /* + * Function to add check character to end of voucher number + * + * Uses config->voucher_check_secret and voucher # to create MD5 string + * then takes last hex character off of that string and shifts it up to + * always be a character (adds 16 to numbers and 10 to the upper-case + * version of the character). + * i.e. 0 = A, 9 = J, A = K, F = + * + */ + public function addCheckCode($voucherNumb) + { + + // Create MD5 string using voucher number and secret + $md5 = md5($voucherNumb.$this->config->voucher_check_secret); + + // Get last character code of the last character in the MD5 + $cc = strtoupper(substr($md5, -2)); + $cc[0] = $this->shiftCheckCodeCharacter($cc[0]); + $cc[1] = $this->shiftCheckCodeCharacter($cc[1]); + + // Return voucher number with the new character on the end + $voucherNumb .= $cc; + return $voucherNumb; + + } + + private function shiftCheckCodeCharacter($c) { + + $x = ord($c); + + // If it's a digit, add 16 + if ($x < 65) { + $x += 17; + // otherwise, add 10 + } else { + $x += 10; + } + + // Also skip the letter O + if (x >= ord('O')) { + $x += 1; + } + + return chr($x); + } + +} // class + +// Absolutely nothing after next line +?> diff --git a/models/vouchers/PointerBoat/voucher.php.SAVE b/models/vouchers/PointerBoat/voucher.php.SAVE new file mode 100644 index 0000000..a80de57 --- /dev/null +++ b/models/vouchers/PointerBoat/voucher.php.SAVE @@ -0,0 +1,614 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: printVoucher.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +require_once PDF_ABSTRACT; +$Pdf = new GlmPdf(); + +/** + * PdfVoucher class + * + * @category PdfVoucher + * @package PDFLib + * @author Chuck Scott + * @license http://www.gaslightmedia.com Gaslightmedia + * @link <> +*/ +class PdfVoucher extends GlmPdf +{ + + public $borderWidth = 1; + public $borderColor = 'black'; + public $pdfCouponInterval = 5; + public $pdfMinCoupons = 3; + public $config; + public $companyContact = false; + public $venueContact = false; + + function __construct($order, $vouchers, $member, $dbh, $config) + { + + $this->config = $config; + + // if debug.glmpdf is set in the configs/common.ini file in the CommonApp directory, do grids on PDFs + define ('GLMPDF_DEBUG', $this->config->debug->glmpdf); + + // The following produces a color test sheet. There is no return from that call. + // $this->glmpdfShowValidColors(); + + // Start with cover page. + $this->glmpdfSetForms( + 1, + array( + 1 => array( 'x' => 0, 'y' => 0, 'xs' => 613, 'ys' => 792 ) + ), + 'US Letter' + ); + + // Start page + $this->glmpdfStart( $this->config->owner->name, "Michigan Maritime Museum", "Ticket System Receipt/Vouchers" ); + + if( !$this->glmpdfAddFont( 'barcode', 'barcode/FREE3OF9.TTF' ) ) + { + echo 'ERROR: Unable to add barcode font.

    + Did you place the barcode font provided in docs/BarcodeFonts into + a system fonts directory ("/usr/share/fonts/truetype/Barcode")? + Also check the GLMPDF_PDF_FONT_DIR setting in GlmPdf.php.'; + exit; + } + + // If coupon test is selected, print them all now. + if( isset($_REQUEST['test_coupons']) ) + { + for( $i=1 ; $i<=count($coupons) ; $i++ ) + $this->printCoupon( $i ); + + glmpdf_send_to_browser( '', 'voucher.pdf' ); + exit; + } + + // Get images to tmp files + require_once IMAGE_SERVER_ABSTRACT; + $imServer = new ImageServerAbstract(); + + if (trim($member['image']) != '') { + $venueImageFile = $imServer->saveImageToTemp(IMAGE_SERVER_PREFIX.'original/'.$member['image']); + if ($venueImageFile) { + $venueImage = $this->glmpdfOpenImage($venueImageFile); + + // If failure getting the image + if ($venueImage == false) { + $venueImageFile = false; + } + } + } else { + $venueImageFile = false; + } + + if (trim($member['parking_map']) != '') { + $parkingImageFile = $imServer->saveImageToTemp(IMAGE_SERVER_PREFIX.'original/'.$member['parking_map']); + if ($parkingImageFile) { + $parkingImage = $this->glmpdfOpenImage($parkingImageFile); + + // If failure getting the image + if ($parkingImage == false) { + $parkingImageFile = false; + } + } + } else { + $parkingImageFile = false; + } + + if (trim($member['ticket_sec_map']) != '') { + $sectionImageFile = $imServer->saveImageToTemp(IMAGE_SERVER_PREFIX.'original/'.$member['ticket_sec_map']); + if ($sectionImageFile) { + $sectionImage = $this->glmpdfOpenImage($sectionImageFile); + + // If failure getting the image + if ($sectionImage == false) { + $sectionImageFile = false; + } + } + } else { + $sectionImageFile = false; + } + + // Load entrance class + require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/entrances.php'; + $Entrances = new EventManagementAdminEntrances($dbh, $config); + + // Load performance class + require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/performances.php'; + $Performances = new EventManagementAdminPerformances($dbh, $config); + + // Setup additional information + // Company contact info + if ($config->option->voucher->show_company_contact) { + $companyContact = ''; + $sep = ''; + if ($config->option->voucher->show_company_name) { + $companyContact .= $config->owner->name; + $sep = ' - '; + } + if ($config->option->voucher->show_company_addr && $config->owner->addr1) { + $companyContact .= $sep.$config->owner->addr1; + $sep = ' - '; + if ($config->owner->addr2) { + $companyContact .= ', '.$config->owner->addr2; + } + } + if ($config->option->voucher->show_company_citystate) { + $companyContact .= $sep.$config->owner->city.', '.$config->owner->state; + $sep = ' - '; + } + if ($config->option->voucher->show_company_phone) { + if ($config->owner->toll_free) { + $companyContact .= $sep.$config->owner->toll_free; + } else { + $companyContact .= $sep.$config->owner->phone; + } + } + } + // Venue/Location contact info + $venueContact = false; + if ($config->option->voucher->show_venue_contact) { + $venueContact = ''; + $sep = ''; + if ($config->option->voucher->show_venue_name) { + $venueContact .= $member['name']; + $sep = ' - '; + } + if ($config->option->voucher->show_venue_addr && $member['addr1']) { + $venueContact .= $sep.$member['addr1']; + $sep = ' - '; + if ($member['addr2']) { + $venueContact .= ', '.$member['addr2']; + } + } + if ($config->option->voucher->show_venue_citystate) { + $venueContact .= $sep.$member['city'].', '.$member['state']['name']; + $sep = ' - '; + } + if ($config->option->voucher->show_venue_phone) { + $venueContact .= $sep.$member['phone']; + } + } + + // START VOUCHER PRINTOUT + + $this->glmpdfNextForm(); + + /* Cover Page */ + + // Header + if ($venueImageFile) { + $coverImage = $this->glmpdfOpenImage($venueImageFile); + $this->glmpdfPlaceImage($coverImage, 30, 690, .5, false, 'center', 280, 140); + } + $this->glmpdfSetFont( "Helvetica-Bold", 18.0 ); // Header Text + $this->glmpdfPlaceText( $config->owner->name, 340, 750, "center", 'black', -400 ); + $this->glmpdfSetFont( "Helvetica", 14.0 ); + $this->glmpdfPlaceText( $config->owner->short_name." - ".$member['name'], 340, $this->glmpdfCurrentY-10, "center", 'black', -400 ); + $this->glmpdfPlaceText( $member['addr1'], 340, $this->glmpdfCurrentY, "center", 'black', -400 ); + $this->glmpdfPlaceText( $member['city'].", ".$member['state']['name']." ".$member['zip'], 340, $this->glmpdfCurrentY, "center", 'black', -400 ); + + // Sold To Information + $valCol = 60; + $this->glmpdfSetFont( "Helvetica", 10.0 ); + $this->glmpdfPlaceText( $this->config->term->order->cap." ID: ".trim($order['id']), $valCol, 650, "left", 'black' ); + $this->glmpdfPlaceText( trim($order['fname'].' '.$order['lname']), $valCol, $this->glmpdfCurrentY-5, "left", 'black', -200 ); + $this->glmpdfPlaceText( trim($order['addr1']), $valCol, $this->glmpdfCurrentY-5, "left", 'black', -200 ); + if( trim($order['addr2']) != '' ) + $this->glmpdfPlaceText( trim($order['addr2']), $valCol, $this->glmpdfCurrentY-5, "left", 'black', -200 ); + $this->glmpdfPlaceText( trim($order['city']).', '.$order['state']['value'].' '.trim($order['zip']).' '.$order['country']['value'], $valCol, $this->glmpdfCurrentY-5, "left", 'black', -200 ); + + // Purchace/Charge information + $this->glmpdfSetFont( "Helvetica", 10.0 ); + $promptCol = 330; + $valCol = 420; + $this->glmpdfPlaceText( "Date of Purchase:", $promptCol, 650, "left", 'black' ); + $this->glmpdfPlaceText( $order['purchase_date']['date'], $valCol, $this->glmpdfLastY, "left", 'black', -160 ); + $this->glmpdfPlaceText( "Card Type:", $promptCol, $this->glmpdfCurrentY-5, "left", 'black' ); + $this->glmpdfPlaceText( $order['cctype'], $valCol, $this->glmpdfLastY, "left", 'black', -160 ); + $this->glmpdfPlaceText( "Name on Card:", $promptCol, $this->glmpdfCurrentY-5, "left", 'black' ); + $this->glmpdfPlaceText( $order['ccname'], $valCol, $this->glmpdfLastY, "left", 'black', -160 ); + $this->glmpdfPlaceText( "Card Number:", $promptCol, $this->glmpdfCurrentY-5, "left", 'black' ); + $this->glmpdfPlaceText( $order['ccnumber'], $valCol, $this->glmpdfLastY, "left", 'black', -160 ); + $this->glmpdfPlaceText( "Confirmation:", $promptCol, $this->glmpdfCurrentY-5, "left", 'black' ); + $this->glmpdfPlaceText( $order['ccconf'], $valCol, $this->glmpdfLastY, "left", 'black', -160 ); + $this->glmpdfPlaceText( "Total Charged:", $promptCol, $this->glmpdfCurrentY-5, "left", 'black' ); + $this->glmpdfPlaceText( $order['charge_total'], $valCol, $this->glmpdfLastY, "left", 'black', -160 ); + + // Purchase Summary + $ticNumbCol = 20; + $perfNameCol = 80; + $ticNameCol = 200; + $secNameCol = 370; + $dateCol = 440; + $this->glmpdfPlaceText( '', $ticNumbCol, 550, "center", 'black', 0, ''); + + $this->glmpdfSetFont( "Helvetica", 8.0 ); + $this->glmpdfPlaceText( $this->config->term->voucher->cap, $ticNumbCol, $this->glmpdfCurrentY, "left", 'black', -52, ''); + $this->glmpdfPlaceText( $this->config->term->performance->cap, $perfNameCol, $this->glmpdfLastY, "left", 'black', -110, ''); + $this->glmpdfPlaceText( $this->config->term->ticket->cap, $ticNameCol, $this->glmpdfLastY, "left", 'black', -160, ''); + $this->glmpdfPlaceText( $this->config->term->section->cap, $secNameCol, $this->glmpdfLastY, "left", 'black', -60, ''); + $this->glmpdfPlaceText( 'Date / Time', $dateCol, $this->glmpdfLastY, "left", 'black', -160, ''); + + $this->glmpdfPlaceText( '', $ticNumbCol, $this->glmpdfCurrentY-3, "center", 'black', 0, ''); + + foreach( $vouchers as $t ) { + + $voucherCode = $this->addCheckCode($t['id']); + + $this->glmpdfSetFont( "Helvetica", 8.0 ); + $this->glmpdfPlaceText( $voucherCode, $ticNumbCol, $this->glmpdfCurrentY, "left", 'black', -52, ''); + $this->glmpdfPlaceText( html_entity_decode($t['performance_name'],ENT_QUOTES,"utf-8"), $perfNameCol, $this->glmpdfLastY, "left", 'black', -110, ''); + $this->glmpdfPlaceText( html_entity_decode($t['ticket_name'],ENT_QUOTES,"utf-8"), $ticNameCol, $this->glmpdfLastY, "left", 'black', -160, ''); + $this->glmpdfPlaceText( html_entity_decode($t['section_name'],ENT_QUOTES,"utf-8"), $secNameCol, $this->glmpdfLastY, "left", 'black', -60, ''); + if ($t['date_specific']['value']) { + $this->glmpdfPlaceText( $t['ticket_date']['date'].' '.$t['ticket_time']['time'], $dateCol, $this->glmpdfLastY, "left", 'black', -160, ''); + } else { + $dateRange = 'Valid From '.$t['start_date']['date'].' through '.$t['end_date']['date']; + $this->glmpdfPlaceText( $dateRange, $dateCol, $this->glmpdfLastY, "left", 'black', -160, ''); + } + + // Check for Ticket add-ons + if (isset($t['addons_sold']) && count($t['addons_sold']) > 0) { + foreach($t['addons_sold'] as $a) { + + $addonText = $a['add_on_name']; + if (($a['add_on_type']['value']-0) == 2) { + $addonText = $addonText.', '.$a['quant'].' '.$a['unit_name']; + } + $this->glmpdfPlaceText( html_entity_decode($addonText,ENT_QUOTES,"utf-8"), $ticNameCol+10, $this->glmpdfCurrentY, "left", 'black', -240, ''); + } + } + + } + + // Special Needs + $this->glmpdfSetFont( "Helvetica", 9.0 ); + if (trim($order['special_needs']) != '') { + $this->glmpdfPlaceText( "Special Needs:", 20, $this->glmpdfCurrentY-30, "left", 'black' ); + $this->glmpdfPlaceTextBox( $order['special_needs'], 100, $this->glmpdfCurrentY+16, 450, 50, "left", 'black' ); + } + + // General Member Policies + if (trim($member['def_ticket_pol']) != '') { + $this->glmpdfPlaceText( "Policies:", 20, $this->glmpdfCurrentY-30, "left", 'black' ); + $this->glmpdfPlaceTextBox( $member['def_ticket_pol'], 100, $this->glmpdfCurrentY+16, 450, 50, "left", 'black' ); + } + + // Now setup ticket forms + $this->glmpdfSetForms( + 1, + array( + 1 => array( 'x' => 25, 'y' => 495, 'xs' => 560, 'ys' => 275 ) +// 2 => array( 'x' => 25, 'y' => 210, 'xs' => 560, 'ys' => 275 ) + ), + 'US Letter' + ); + // Also reset form count + $this->glmpdfNextPage(); + + // Display Footer + $this->glmpdfSetFont( "Helvetica-Bold", 8.5 ); + $this->glmpdfPlaceText( $footer, 140.5, 2, "center", 'darkblue' ); +/*********CPS + // Display Parking Map + if ($parkingImage) { + $this->glmpdfNextForm(); + $this->glmpdfPlaceImage( $parkingImage, 0, 2, 0, 'meet', 'center', 280, 125); + $this->glmpdfSetFont( "Helvetica-Bold", 10.0 ); + $this->glmpdfPlaceText( 'Parking Map', 140, 130, "center", 'black' ); + } + + // Display Section Map + if ($sectionImage) { + $this->glmpdfNextForm(); + $this->glmpdfPlaceImage( $sectionImage, 0, 2, 0, 'meet', 'center', 280, 125); + $this->glmpdfSetFont( "Helvetica-Bold", 10.0 ); + $this->glmpdfPlaceText( 'Section Map', 140, 130, "center", 'black' ); + } +*/ + + // Load mask for darkening the bottom portion of the tickets +// $ticketMask = $this->glmpdfOpenImage(EVENT_MANAGEMENT_APP_BASE.'web/custom/greatlakesbaymag/assets/ticket-gradient.png'); + + // Clear performance image loaded flag + $performanceLoaded = false; + + // Process Vouchers - For each type of ticket purchased + $numb_tickets = 0; + foreach( $vouchers as $t ) + { + + if ($numb_tickets++ > 0) { + $this->glmpdfNextForm(); + } + $this->glmpdfPlaceBox( $this->borderWidth, 0, 275, 560, 275, $this->borderColor ); + + // Display Logo - Only get performance image if it's not currently loaded + if ($performanceLoaded != $t['performance']) { + + $performanceDetail = $Performances->getPerformanceDetail($t['performance']); + + // If we have an image but it's the wrong one, dump the temp file + if ($performanceImageFile) { + unlink($performanceImageFile); + } + + // This performance image is not currently loaded - so do that now + + $performanceImageFile = $imServer->saveImageToTemp(IMAGE_SERVER_PREFIX.'original/'.$performanceDetail['image']); + if ($performanceImageFile) { + // If we have the image, then load it + $performanceImage = $this->glmpdfOpenImage($performanceImageFile); + $performanceLoaded = $t['performance']; + } else { + + // otherwise, try the venue image + $performanceLoaded = $venueImage; + } + + } + + // If we have the performance image, display it + $haveTopImage = false; + if ($performanceImage) { + $this->glmpdfPlaceImage( $performanceImage, 85, 195, 1, 'meet', 'center', 70, 75); + $haveTopImage = true; + } elseif ($venueImageFile) { + $this->glmpdfPlaceImage($coverImage, 85, 195, 1, 'meet', 'center', 70, 75); + $haveTopImage = true; + } + + // Place owner name at top possitioned by whether or not there's an image supplied + $this->glmpdfSetFont( "Helvetica-Bold", 24.0 ); + if ($haveTopImage) { + +// $this->glmpdfPlaceText( $config->owner->name, 315, 227, "center", 'black', -300, ''); + $this->glmpdfPlaceText( html_entity_decode($t['member_name'],ENT_QUOTES,"utf-8"), 315, 227, "center", 'black', -300, ''); + } else { +// $this->glmpdfPlaceText( $config->owner->name, 280, 227, "center", 'black', -350, ''); + $this->glmpdfPlaceText( html_entity_decode($t['member_name'],ENT_QUOTES,"utf-8"), 280, 227, "center", 'black', -350, ''); + } + + // Place mask + //$this->glmpdfPlaceImage($ticketMask, 0, 52, .25, false, 'center', 280, 140); + + // If ticket has already been claimed, then mark ticket + if ($t['time_claimed']['date'] != '') { + $this->glmpdfSetFont( "Times-Bold", 72.0 ); + $this->glmpdfPlaceText( "CLAIMED", 110, 80, "left", 'orangered', 0, '' ); // last parameter can be things like "rotate=90" + } + + // Ticket Information Area + $this->glmpdfSetFont( "Helvetica-Bold", 24.0 ); + $this->glmpdfPlaceLine(1, 80, 0, 80, 275, $color = "black", $dash = false, $d_a = 1, $d_b = 1); + $this->glmpdfPlaceLine(1, 480, 0, 480, 275, $color = "black", $dash = false, $d_a = 1, $d_b = 1); + + // Left End of Ticket - NOTE: use only "left" in glmpdfPlaceText - use "position=..." in optlist instead. + if (($t['entrance']-0) > 0) { + $entranceDetail = $Entrances->getEntranceDetail($t['entrance']); + $this->glmpdfPlaceBox(1, 0, 0, 80, -275, '', $entranceDetail['color']['name'], 'miter'); + } + $this->glmpdfSetFont( "Helvetica-Bold", 10.0 ); +// $this->glmpdfPlaceText( 'Departing from:', 7, 40, 'left', 'black', 0, 'position=center rotate=90'); + $this->glmpdfSetFont( "Helvetica-Bold", 20.0 ); + $this->glmpdfPlaceText( strtoupper(html_entity_decode($t['entrance_name'],ENT_QUOTES,"utf-8")), 40, 138, 'left', 'black', -250, 'position=center rotate=90'); +// $this->glmpdfPlaceText( strtoupper(html_entity_decode($t['member_name'],ENT_QUOTES,"utf-8")), 60, 138, 'left', 'black', -250, 'position=center rotate=90'); + + // Display values + $this->glmpdfSetFont( "Helvetica-Bold", 26.0 ); + $this->glmpdfPlaceText( html_entity_decode($t['performance_name'],ENT_QUOTES,"utf-8"), 280, 170, "center", 'black', -370, ''); + $this->glmpdfSetFont( "Helvetica-Bold", 24.0 ); + $this->glmpdfPlaceText( html_entity_decode($t['ticket_name'],ENT_QUOTES,"utf-8"), 280, 140, "center", 'black', -370, '' ); + $this->glmpdfSetFont( "Helvetica-Bold", 20.0 ); +// $this->glmpdfPlaceText( html_entity_decode($t['section_name'],ENT_QUOTES,"utf-8"), 280, 130, "center", 'black', -370, '' ); + $this->glmpdfSetFont( "Helvetica", 18.0 ); + if ($t['date_specific']['value']) { + $thisTime = ''; + if ($t['time_specific']['value']) { + $thisTime = ' - '.$t['ticket_time']['time']; + } + $this->glmpdfPlaceText( $t['ticket_date']['date'].$thisTime, 280, 110, "center", 'black', -370, '' ); + } else { + $dateRange = 'Valid From '.$t['start_date']['date'].' through '.$t['end_date']['date']; + $this->glmpdfPlaceText( $dateRange, 280, 110, "center", 'black', -370, '' ); + } + + $this->glmpdfSetFont( "Helvetica", 16.0 ); + + // Check for Ticket add-ons + if (isset($t['addons_sold']) && count($t['addons_sold']) > 0) { + $this->glmpdfSetFont( "Helvetica", 14.0 ); + foreach($t['addons_sold'] as $a) { + $addonText = $a['add_on_name']; + if (($a['add_on_type']['value']-0) == 2) { + $addonText = $addonText.', '.$a['quant'].' '.$a['unit_name']; + } + $this->glmpdfPlaceText( $addonText, 280, $this->glmpdfCurrentY, "center", 'black', -370, '' ); + } + } + + // Display NON-REFUNDABLE MESSAGE + $this->glmpdfSetFont( "Helvetica", 14.0 ); + $this->glmpdfPlaceText( "NON-REFUNDABLE", 280, $this->glmpdfCurrentY, "center", 'black', -300, ''); + + // Display address and contact information + if ($venueContact) { + $this->glmpdfSetFont( "Helvetica", 10.0 ); + $this->glmpdfPlaceText( html_entity_decode($this->config->term->prop->cap.' contact information',ENT_QUOTES,"utf-8"), 280, $this->glmpdfCurrentY-5, "center", 'black', -300, ''); + $this->glmpdfPlaceText( html_entity_decode($venueContact,ENT_QUOTES,"utf-8"), 280, $this->glmpdfCurrentY, "center", 'black', -300, ''); + } + + // Display address and contact information + if ($companyContact) { + $this->glmpdfSetFont( "Helvetica", 10.0 ); + $this->glmpdfPlaceText( html_entity_decode($companyContact,ENT_QUOTES,"utf-8"), 280, 25, "center", 'black', -380, ''); + } + + // Display additional voucher text at the bottom of the voucher if provided + $voucherText = ''; + if (trim($t['ticket_voucher_text']) != '') { + $voucherText = trim(html_entity_decode($t['ticket_voucher_text'],ENT_QUOTES,"utf-8")); + } elseif (trim($performanceDetail['voucher_text']) != '') { + $voucherText = trim(html_entity_decode($performanceDetail['voucher_text'],ENT_QUOTES,"utf-8")); + } + if ($voucherText != '') { + $this->glmpdfPlaceLine(1, 80, 20, 480, 20, 'black', false); + $this->glmpdfSetFont( "Helvetica-Bold", 14.0 ); +// $this->glmpdfPlaceBox(1, 80, 20, 400, 20, "black", "black"); + $this->glmpdfPlaceText( html_entity_decode($voucherText,ENT_QUOTES,"utf-8"), 280, 6, "center", 'black', -370, '' ); + } + + // $this->glmpdfPlaceText( $t['ticket_date']['date'].' - '.$t['ticket_time']['time'], 120, $this->glmpdfCurrentY, "left", 'black', 0, '' ); + + // Print barcode = {ticket_sold ID}-{person type}-{person_sequence} + $barcode = $this->addCheckCode($t['id']); + // If we're supposed to print barcode and voucher number on ticket + switch ($t['ticket_voucher_type']) { + + case 11: // Voucher/Ticket for Pickup - no Barcode + $this->glmpdfSetFont( "Helvetica-Bold", 20.0 ); + $this->glmpdfPlaceText( "Pickup at ".$this->config->term->prop->norm, 510, 140, 'left', 'black', -260, 'position=center rotate=90'); + $this->glmpdfSetFont( "Courier", 12.0 ); + $this->glmpdfPlaceText( $this->config->term->voucher->cap." $barcode", 540, 140, 'left', 'black', -260, 'position=center rotate=90'); + break; + + case 12; // Voucher/Ticket to be mailed Mailed - no Barcode + case 82; // Object Sold (i.e. books) to be mailed - no Barcode + $this->glmpdfSetFont( "Helvetica-Bold", 20.0 ); + $this->glmpdfPlaceText( "You will receive this by mail", 510, 140, 'left', 'black', -260, 'position=center rotate=90'); + $this->glmpdfSetFont( "Courier", 12.0 ); + $this->glmpdfPlaceText( $this->config->term->voucher->cap." $barcode", 540, 140, 'left', 'black', -260, 'position=center rotate=90'); + break; + + case 1: // Standard Voucher/Ticket with Barcode + case 81; // Object Sold (i.e. books) to be claimed - with Barcode + default: + $this->glmpdfSetFont( 'barcode', 54 ); + $this->glmpdfPlaceText( "*$barcode*", 510, 140, 'left', 'black', 0, 'position=center rotate=90'); + $this->glmpdfSetFont( "Courier", 12.0 ); + $this->glmpdfPlaceText( $this->config->term->voucher->cap." $barcode", 540, 140, 'left', 'black', -260, 'position=center rotate=90'); + break; + + } + + $this->glmpdfPlaceText( "Order #".$order['id'], 552, 140, 'left', 'black', 0, 'position=center rotate=90'); + + // Check if we need to display a coupon + if( ++$numb_tickets % $this->pdfCouponInterval == 0 ) + $this->printCoupon(); + + } // Each voucher + + // Make sure we print the minimum number of coupons + $numb_coupons = 0; + while( $numb_coupons < $this->pdfMinCoupons ) { + $this->printCoupon(); + $numb_coupons++; + } + + // Close PDF setup and send to user's browser + $this->glmpdfSendToBrowser( '', 'voucher.pdf' ); + + if ($venueImageFile) { + unlink($venueImageFile); + } + if ($parkingImageFile) { + unlink($parkingImageFile); + } + if ($sectionImageFile) { + unlink($sectionImageFile); + } + if ($sectionImageFile) { + unlink($sectionImageFile); + } + + } + + + // function to print a coupon + function printCoupon() + { + // Print a Coupon + $this->glmpdfNextForm(); + $this->glmpdfPlaceBox( $this->borderWidth, 0, 142, 281, 142, $this->borderColor ); + + // Place Coupon Image + $this->glmpdfSetFont( "Helvetica-Bold", 10.0 ); + $this->glmpdfPlaceText( 'Coupon Title', 85, 130, "center", 'black' ); + $this->glmpdfPlaceText( 'Expires on: 1/1/2020', 85, 75 ); + $this->glmpdfSetFont( "Times-Bold", 30.0 ); + $this->glmpdfPlaceText( "COUPON", 85, 95, "center", 'lightgrey' ); + $this->glmpdfSetFont( "Helvetica", 8.0 ); + $this->glmpdfPlaceTextBox( 'This is a coupon description. It describes this coupon.', 5, 55, 274, 40, "left", 'black' ); + $this->glmpdfSetFont( "Helvetica-Bold", 8.5 ); + $this->glmpdfPlaceText( "Michigan Maritime Museum - South Haven, MI - 269-637-8078", 144.5, 2, "center", 'darkblue' ); + + } + + /* + * Function to add check character to end of voucher number + * + * Uses config->voucher_check_secret and voucher # to create MD5 string + * then takes last hex character off of that string and shifts it up to + * always be a character (adds 16 to numbers and 10 to the upper-case + * version of the character). + * i.e. 0 = A, 9 = J, A = K, F = + * + */ + public function addCheckCode($voucherNumb) + { + + // Create MD5 string using voucher number and secret + $md5 = md5($voucherNumb.$this->config->voucher_check_secret); + + // Get last character code of the last character in the MD5 + $cc = strtoupper(substr($md5, -2)); + $cc[0] = $this->shiftCheckCodeCharacter($cc[0]); + $cc[1] = $this->shiftCheckCodeCharacter($cc[1]); + + // Return voucher number with the new character on the end + $voucherNumb .= $cc; + return $voucherNumb; + + } + + private function shiftCheckCodeCharacter($c) { + + $x = ord($c); + + // If it's a digit, add 16 + if ($x < 65) { + $x += 17; + // otherwise, add 10 + } else { + $x += 10; + } + + // Also skip the letter O + if (x >= ord('O')) { + $x += 1; + } + + return chr($x); + } + +} // class + +// Absolutely nothing after next line +?> diff --git a/models/vouchers/SaultSteMarie/voucher.php b/models/vouchers/SaultSteMarie/voucher.php new file mode 100644 index 0000000..abf37f6 --- /dev/null +++ b/models/vouchers/SaultSteMarie/voucher.php @@ -0,0 +1,610 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: printVoucher.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +require_once PDF_ABSTRACT; +$Pdf = new GlmPdf(); + +/** + * PdfVoucher class + * + * @category PdfVoucher + * @package PDFLib + * @author Chuck Scott + * @license http://www.gaslightmedia.com Gaslightmedia + * @link <> +*/ +class PdfVoucher extends GlmPdf +{ + + public $borderWidth = 1; + public $borderColor = 'black'; + public $pdfCouponInterval = 5; + public $pdfMinCoupons = 3; + public $config; + public $companyContact = false; + public $venueContact = false; + + function __construct($order, $vouchers, $member, $dbh, $config) + { + + $this->config = $config; + + // if debug.glmpdf is set in the configs/common.ini file in the CommonApp directory, do grids on PDFs + define ('GLMPDF_DEBUG', $this->config->debug->glmpdf); + + // The following produces a color test sheet. There is no return from that call. + // $this->glmpdfShowValidColors(); + + // Start with cover page. + $this->glmpdfSetForms( + 1, + array( + 1 => array( 'x' => 0, 'y' => 0, 'xs' => 613, 'ys' => 792 ) + ), + 'US Letter' + ); + + // Start page + $this->glmpdfStart( $this->config->owner->name, "Gaslight Media", "Ticket System Receipt/Vouchers" ); + + if( !$this->glmpdfAddFont( 'barcode', 'barcode/FREE3OF9.TTF' ) ) + { + echo 'ERROR: Unable to add barcode font.

    + Did you place the barcode font provided in docs/BarcodeFonts into + a system fonts directory ("/usr/share/fonts/truetype/Barcode")? + Also check the GLMPDF_PDF_FONT_DIR setting in GlmPdf.php.'; + exit; + } + + // If coupon test is selected, print them all now. +// if( isset($_REQUEST['test_coupons']) ) +// { +// for( $i=1 ; $i<=count($coupons) ; $i++ ) +// $this->printCoupon( $i ); +// +// glmpdf_send_to_browser( '', 'voucher.pdf' ); +// exit; +// } + + // Get images to tmp files + require_once IMAGE_SERVER_ABSTRACT; + $imServer = new ImageServerAbstract(); + + if (trim($member['image']) != '') { + $venueImageFile = $imServer->saveImageToTemp(IMAGE_SERVER_PREFIX.'original/'.$member['image']); + if ($venueImageFile) { + $venueImage = $this->glmpdfOpenImage($venueImageFile); + + // If failure getting the image + if ($venueImage == false) { + $venueImageFile = false; + } + } + } else { + $venueImageFile = false; + } + + if (trim($member['parking_map']) != '') { + $parkingImageFile = $imServer->saveImageToTemp(IMAGE_SERVER_PREFIX.'original/'.$member['parking_map']); + if ($parkingImageFile) { + $parkingImage = $this->glmpdfOpenImage($parkingImageFile); + + // If failure getting the image + if ($parkingImage == false) { + $parkingImageFile = false; + } + } + } else { + $parkingImageFile = false; + } + + if (trim($member['ticket_sec_map']) != '') { + $sectionImageFile = $imServer->saveImageToTemp(IMAGE_SERVER_PREFIX.'original/'.$member['ticket_sec_map']); + if ($sectionImageFile) { + $sectionImage = $this->glmpdfOpenImage($sectionImageFile); + + // If failure getting the image + if ($sectionImage == false) { + $sectionImageFile = false; + } + } + } else { + $sectionImageFile = false; + } + + // Load entrance class + require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/entrances.php'; + $Entrances = new EventManagementAdminEntrances($dbh, $config); + + // Load performance class + require_once EVENT_MANAGEMENT_APP_BASE.'models/admin/classes/performances.php'; + $Performances = new EventManagementAdminPerformances($dbh, $config); + + // Setup additional information + // Company contact info + if ($config->option->voucher->show_company_contact) { + $companyContact = ''; + $sep = ''; + if ($config->option->voucher->show_company_name) { + $companyContact .= $config->owner->name; + $sep = ' - '; + } + if ($config->option->voucher->show_company_addr && $config->owner->addr1) { + $companyContact .= $sep.$config->owner->addr1; + $sep = ' - '; + if ($config->owner->addr2) { + $companyContact .= ', '.$config->owner->addr2; + } + } + if ($config->option->voucher->show_company_citystate) { + $companyContact .= $sep.$config->owner->city.', '.$config->owner->state; + $sep = ' - '; + } + if ($config->option->voucher->show_company_phone) { + if ($config->owner->toll_free) { + $companyContact .= $sep.$config->owner->toll_free; + } else { + $companyContact .= $sep.$config->owner->phone; + } + } + } + // Venue/Location contact info + $venueContact = false; + if ($config->option->voucher->show_venue_contact) { + $venueContact = ''; + $sep = ''; + if ($config->option->voucher->show_venue_name) { + $venueContact .= $member['name']; + $sep = ' - '; + } + if ($config->option->voucher->show_venue_addr && $member['addr1']) { + $venueContact .= $sep.$member['addr1']; + $sep = ' - '; + if ($member['addr2']) { + $venueContact .= ', '.$member['addr2']; + } + } + if ($config->option->voucher->show_venue_citystate) { + $venueContact .= $sep.$member['city'].', '.$member['state']['name']; + $sep = ' - '; + } + if ($config->option->voucher->show_venue_phone) { + $venueContact .= $sep.$member['phone']; + } + } + + // START VOUCHER PRINTOUT + + $this->glmpdfNextForm(); + + /* Cover Page */ + + // Header + if ($venueImageFile) { + $coverImage = $this->glmpdfOpenImage($venueImageFile); + $this->glmpdfPlaceImage($coverImage, 30, 690, .5, false, 'center', 280, 140); + } + $this->glmpdfSetFont( "Helvetica-Bold", 18.0 ); // Header Text + $this->glmpdfPlaceText( $config->owner->name, 340, 750, "center", 'black', -400 ); + $this->glmpdfSetFont( "Helvetica", 14.0 ); + $this->glmpdfPlaceText( $config->owner->short_name." - ".$member['name'], 340, $this->glmpdfCurrentY-10, "center", 'black', -400 ); + $this->glmpdfPlaceText( $member['addr1'], 340, $this->glmpdfCurrentY, "center", 'black', -400 ); + $this->glmpdfPlaceText( $member['city'].", ".$member['state']['name']." ".$member['zip'], 340, $this->glmpdfCurrentY, "center", 'black', -400 ); + + // Sold To Information + $valCol = 60; + $this->glmpdfSetFont( "Helvetica", 10.0 ); + $this->glmpdfPlaceText( $this->config->term->order->cap." ID: ".trim($order['id']), $valCol, 650, "left", 'black' ); + $this->glmpdfPlaceText( trim($order['fname'].' '.$order['lname']), $valCol, $this->glmpdfCurrentY-5, "left", 'black', -200 ); + $this->glmpdfPlaceText( trim($order['addr1']), $valCol, $this->glmpdfCurrentY-5, "left", 'black', -200 ); + if( trim($order['addr2']) != '' ) + $this->glmpdfPlaceText( trim($order['addr2']), $valCol, $this->glmpdfCurrentY-5, "left", 'black', -200 ); + $this->glmpdfPlaceText( trim($order['city']).', '.$order['state']['value'].' '.trim($order['zip']).' '.$order['country']['value'], $valCol, $this->glmpdfCurrentY-5, "left", 'black', -200 ); + + // Purchace/Charge information + $this->glmpdfSetFont( "Helvetica", 10.0 ); + $promptCol = 330; + $valCol = 420; + $this->glmpdfPlaceText( "Date of Purchase:", $promptCol, 650, "left", 'black' ); + $this->glmpdfPlaceText( $order['purchase_date']['date'], $valCol, $this->glmpdfLastY, "left", 'black', -160 ); + $this->glmpdfPlaceText( "Card Type:", $promptCol, $this->glmpdfCurrentY-5, "left", 'black' ); + $this->glmpdfPlaceText( $order['cctype'], $valCol, $this->glmpdfLastY, "left", 'black', -160 ); + $this->glmpdfPlaceText( "Name on Card:", $promptCol, $this->glmpdfCurrentY-5, "left", 'black' ); + $this->glmpdfPlaceText( $order['ccname'], $valCol, $this->glmpdfLastY, "left", 'black', -160 ); + $this->glmpdfPlaceText( "Card Number:", $promptCol, $this->glmpdfCurrentY-5, "left", 'black' ); + $this->glmpdfPlaceText( $order['ccnumber'], $valCol, $this->glmpdfLastY, "left", 'black', -160 ); + $this->glmpdfPlaceText( "Confirmation:", $promptCol, $this->glmpdfCurrentY-5, "left", 'black' ); + $this->glmpdfPlaceText( $order['ccconf'], $valCol, $this->glmpdfLastY, "left", 'black', -160 ); + $this->glmpdfPlaceText( "Total Charged:", $promptCol, $this->glmpdfCurrentY-5, "left", 'black' ); + $this->glmpdfPlaceText( $order['charge_total'], $valCol, $this->glmpdfLastY, "left", 'black', -160 ); + + // Purchase Summary + $ticNumbCol = 20; + $perfNameCol = 80; + $ticNameCol = 200; + $secNameCol = 370; + $dateCol = 440; + $this->glmpdfPlaceText( '', $ticNumbCol, 550, "center", 'black', 0, ''); + + $this->glmpdfSetFont( "Helvetica", 8.0 ); + $this->glmpdfPlaceText( $this->config->term->voucher->cap, $ticNumbCol, $this->glmpdfCurrentY, "left", 'black', -52, ''); + $this->glmpdfPlaceText( $this->config->term->performance->cap, $perfNameCol, $this->glmpdfLastY, "left", 'black', -110, ''); + $this->glmpdfPlaceText( $this->config->term->ticket->cap, $ticNameCol, $this->glmpdfLastY, "left", 'black', -160, ''); + $this->glmpdfPlaceText( $this->config->term->section->cap, $secNameCol, $this->glmpdfLastY, "left", 'black', -60, ''); + $this->glmpdfPlaceText( 'Date / Time', $dateCol, $this->glmpdfLastY, "left", 'black', -160, ''); + + $this->glmpdfPlaceText( '', $ticNumbCol, $this->glmpdfCurrentY-3, "center", 'black', 0, ''); + + foreach( $vouchers as $t ) { + + $voucherCode = $this->addCheckCode($t['id']); + + $this->glmpdfSetFont( "Helvetica", 8.0 ); + $this->glmpdfPlaceText( $voucherCode, $ticNumbCol, $this->glmpdfCurrentY, "left", 'black', -52, ''); + $this->glmpdfPlaceText( html_entity_decode($t['performance_name'],ENT_QUOTES,"utf-8"), $perfNameCol, $this->glmpdfLastY, "left", 'black', -110, ''); + $this->glmpdfPlaceText( html_entity_decode($t['ticket_name'],ENT_QUOTES,"utf-8"), $ticNameCol, $this->glmpdfLastY, "left", 'black', -160, ''); + $this->glmpdfPlaceText( html_entity_decode($t['section_name'],ENT_QUOTES,"utf-8"), $secNameCol, $this->glmpdfLastY, "left", 'black', -60, ''); + if ($t['date_specific']['value']) { + $this->glmpdfPlaceText( $t['ticket_date']['date'], $dateCol, $this->glmpdfLastY, "left", 'black', -160, ''); + } else { + $dateRange = 'Valid From '.$t['start_date']['date'].' through '.$t['end_date']['date']; + $this->glmpdfPlaceText( $dateRange, $dateCol, $this->glmpdfLastY, "left", 'black', -160, ''); + } + + // Check for Ticket add-ons + if (isset($t['addons_sold']) && count($t['addons_sold']) > 0) { + foreach($t['addons_sold'] as $a) { + + $addonText = $a['add_on_name']; + if (($a['add_on_type']['value']-0) == 2) { + $addonText = $addonText.', '.$a['quant'].' '.$a['unit_name']; + } + $this->glmpdfPlaceText( html_entity_decode($addonText,ENT_QUOTES,"utf-8"), $ticNameCol+10, $this->glmpdfCurrentY, "left", 'black', -240, ''); + } + } + + } + + // Special Needs + $this->glmpdfSetFont( "Helvetica", 9.0 ); + if (trim($order['special_needs']) != '') { + $this->glmpdfPlaceText( "Special Needs:", 20, $this->glmpdfCurrentY-30, "left", 'black' ); + $this->glmpdfPlaceTextBox( $order['special_needs'], 100, $this->glmpdfCurrentY+16, 450, 50, "left", 'black' ); + } + + // General Member Policies + if (trim($member['def_ticket_pol']) != '') { + $this->glmpdfPlaceText( "Policies:", 20, $this->glmpdfCurrentY-30, "left", 'black' ); + $this->glmpdfPlaceTextBox( $member['def_ticket_pol'], 100, $this->glmpdfCurrentY+16, 450, 50, "left", 'black' ); + } + + // Now setup ticket forms + $this->glmpdfSetForms( + 1, + array( + 1 => array( 'x' => 25, 'y' => 495, 'xs' => 560, 'ys' => 275 ) +// 2 => array( 'x' => 25, 'y' => 210, 'xs' => 560, 'ys' => 275 ) + ), + 'US Letter' + ); + // Also reset form count + $this->glmpdfNextPage(); + + // Display Footer + $this->glmpdfSetFont( "Helvetica-Bold", 8.5 ); + $this->glmpdfPlaceText( $footer, 140.5, 2, "center", 'darkblue' ); +/*********CPS + // Display Parking Map + if ($parkingImage) { + $this->glmpdfNextForm(); + $this->glmpdfPlaceImage( $parkingImage, 0, 2, 0, 'meet', 'center', 280, 125); + $this->glmpdfSetFont( "Helvetica-Bold", 10.0 ); + $this->glmpdfPlaceText( 'Parking Map', 140, 130, "center", 'black' ); + } + + // Display Section Map + if ($sectionImage) { + $this->glmpdfNextForm(); + $this->glmpdfPlaceImage( $sectionImage, 0, 2, 0, 'meet', 'center', 280, 125); + $this->glmpdfSetFont( "Helvetica-Bold", 10.0 ); + $this->glmpdfPlaceText( 'Section Map', 140, 130, "center", 'black' ); + } +*/ + + // Load mask for darkening the bottom portion of the tickets +// $ticketMask = $this->glmpdfOpenImage(EVENT_MANAGEMENT_APP_BASE.'web/custom/greatlakesbaymag/assets/ticket-gradient.png'); + + // Clear performance image loaded flag + $performanceLoaded = false; + + // Process Vouchers - For each type of ticket purchased + $numb_tickets = 0; + foreach( $vouchers as $t ) + { + + if ($numb_tickets++ > 0) { + $this->glmpdfNextForm(); + } + $this->glmpdfPlaceBox( $this->borderWidth, 0, 275, 560, 275, $this->borderColor ); + + // Display Logo - Only get performance image if it's not currently loaded + if ($performanceLoaded != $t['performance']) { + + $performanceDetail = $Performances->getPerformanceDetail($t['performance']); + + // If we have an image but it's the wrong one, dump the temp file + if ($performanceImageFile) { + unlink($performanceImageFile); + } + + // This performance image is not currently loaded - so do that now + + $performanceImageFile = $imServer->saveImageToTemp(IMAGE_SERVER_PREFIX.'original/'.$performanceDetail['image']); + if ($performanceImageFile) { + // If we have the image, then load it + $performanceImage = $this->glmpdfOpenImage($performanceImageFile); + $performanceLoaded = $t['performance']; + } else { + + // otherwise, try the venue image + $performanceLoaded = $venueImage; + } + + } + + // If we have the performance image, display it + $haveTopImage = false; + if ($performanceImage) { + $this->glmpdfPlaceImage( $performanceImage, 85, 195, 1, 'meet', 'center', 70, 75); + $haveTopImage = true; + } elseif ($venueImageFile) { + $this->glmpdfPlaceImage($coverImage, 85, 195, 1, 'meet', 'center', 70, 75); + $haveTopImage = true; + } + + // Place owner name at top possitioned by whether or not there's an image supplied + $this->glmpdfSetFont( "Helvetica-Bold", 24.0 ); + if ($haveTopImage) { + +// $this->glmpdfPlaceText( $config->owner->name, 315, 227, "center", 'black', -300, ''); + $this->glmpdfPlaceText( html_entity_decode($t['member_name'],ENT_QUOTES,"utf-8"), 315, 227, "center", 'black', -300, ''); + } else { +// $this->glmpdfPlaceText( $config->owner->name, 280, 227, "center", 'black', -350, ''); + $this->glmpdfPlaceText( html_entity_decode($t['member_name'],ENT_QUOTES,"utf-8"), 280, 227, "center", 'black', -350, ''); + } + + // Place mask + //$this->glmpdfPlaceImage($ticketMask, 0, 52, .25, false, 'center', 280, 140); + + // If ticket has already been claimed, then mark ticket + if ($t['time_claimed']['date'] != '') { + $this->glmpdfSetFont( "Times-Bold", 72.0 ); + $this->glmpdfPlaceText( "CLAIMED", 110, 80, "left", 'orangered', 0, '' ); // last parameter can be things like "rotate=90" + } + + // Ticket Information Area + $this->glmpdfSetFont( "Helvetica-Bold", 24.0 ); + $this->glmpdfPlaceLine(1, 80, 0, 80, 275, $color = "black", $dash = false, $d_a = 1, $d_b = 1); + $this->glmpdfPlaceLine(1, 480, 0, 480, 275, $color = "black", $dash = false, $d_a = 1, $d_b = 1); + + // Left End of Ticket - NOTE: use only "left" in glmpdfPlaceText - use "position=..." in optlist instead. + if (($t['entrance']-0) > 0) { + $entranceDetail = $Entrances->getEntranceDetail($t['entrance']); + $this->glmpdfPlaceBox(1, 0, 0, 80, -275, '', $entranceDetail['color']['name'], 'miter'); + } + $this->glmpdfSetFont( "Helvetica-Bold", 10.0 ); +// $this->glmpdfPlaceText( 'Departing from:', 7, 40, 'left', 'black', 0, 'position=center rotate=90'); + $this->glmpdfSetFont( "Helvetica-Bold", 20.0 ); + $this->glmpdfPlaceText( strtoupper(html_entity_decode($t['entrance_name'],ENT_QUOTES,"utf-8")), 40, 138, 'left', 'black', -250, 'position=center rotate=90'); +// $this->glmpdfPlaceText( strtoupper(html_entity_decode($t['member_name'],ENT_QUOTES,"utf-8")), 60, 138, 'left', 'black', -250, 'position=center rotate=90'); + + // Display values + $this->glmpdfSetFont( "Helvetica-Bold", 26.0 ); + $this->glmpdfPlaceText( html_entity_decode($t['performance_name'],ENT_QUOTES,"utf-8"), 280, 170, "center", 'black', -370, ''); + $this->glmpdfSetFont( "Helvetica-Bold", 24.0 ); + $this->glmpdfPlaceText( html_entity_decode($t['ticket_name'],ENT_QUOTES,"utf-8"), 280, 140, "center", 'black', -370, '' ); + $this->glmpdfSetFont( "Helvetica-Bold", 20.0 ); +// $this->glmpdfPlaceText( html_entity_decode($t['section_name'],ENT_QUOTES,"utf-8"), 280, 130, "center", 'black', -370, '' ); + $this->glmpdfSetFont( "Helvetica", 18.0 ); + if ($t['date_specific']['value']) { + $this->glmpdfPlaceText( $t['ticket_date']['date'], 280, 110, "center", 'black', -370, '' ); + } else { + $dateRange = 'Valid From '.$t['start_date']['date'].' through '.$t['end_date']['date']; + $this->glmpdfPlaceText( $dateRange, 280, 110, "center", 'black', -370, '' ); + } + + $this->glmpdfSetFont( "Helvetica", 16.0 ); + + // Check for Ticket add-ons + if (isset($t['addons_sold']) && count($t['addons_sold']) > 0) { + $this->glmpdfSetFont( "Helvetica", 14.0 ); + foreach($t['addons_sold'] as $a) { + $addonText = $a['add_on_name']; + if (($a['add_on_type']['value']-0) == 2) { + $addonText = $addonText.', '.$a['quant'].' '.$a['unit_name']; + } + $this->glmpdfPlaceText( $addonText, 280, $this->glmpdfCurrentY, "center", 'black', -370, '' ); + } + } + + // Display NON-REFUNDABLE MESSAGE + $this->glmpdfSetFont( "Helvetica", 14.0 ); + $this->glmpdfPlaceText( "NON-REFUNDABLE", 280, $this->glmpdfCurrentY, "center", 'black', -300, ''); + + // Display address and contact information + if ($venueContact) { + $this->glmpdfSetFont( "Helvetica", 10.0 ); + $this->glmpdfPlaceText( html_entity_decode($this->config->term->prop->cap.' contact information',ENT_QUOTES,"utf-8"), 280, $this->glmpdfCurrentY-5, "center", 'black', -300, ''); + $this->glmpdfPlaceText( html_entity_decode($venueContact,ENT_QUOTES,"utf-8"), 280, $this->glmpdfCurrentY, "center", 'black', -300, ''); + } + + // Display address and contact information + if ($companyContact) { + $this->glmpdfSetFont( "Helvetica", 10.0 ); + $this->glmpdfPlaceText( html_entity_decode($companyContact,ENT_QUOTES,"utf-8"), 280, 25, "center", 'black', -380, ''); + } + + // Display additional voucher text at the bottom of the voucher if provided + $voucherText = ''; + if (trim($t['ticket_voucher_text']) != '') { + $voucherText = trim(html_entity_decode($t['ticket_voucher_text'],ENT_QUOTES,"utf-8")); + } elseif (trim($performanceDetail['voucher_text']) != '') { + $voucherText = trim(html_entity_decode($performanceDetail['voucher_text'],ENT_QUOTES,"utf-8")); + } + if ($voucherText != '') { + $this->glmpdfPlaceLine(1, 80, 20, 480, 20, 'black', false); + $this->glmpdfSetFont( "Helvetica-Bold", 14.0 ); +// $this->glmpdfPlaceBox(1, 80, 20, 400, 20, "black", "black"); + $this->glmpdfPlaceText( html_entity_decode($voucherText,ENT_QUOTES,"utf-8"), 280, 6, "center", 'black', -370, '' ); + } + + // $this->glmpdfPlaceText( $t['ticket_date']['date'].' - '.$t['ticket_time']['time'], 120, $this->glmpdfCurrentY, "left", 'black', 0, '' ); + + // Print barcode = {ticket_sold ID}-{person type}-{person_sequence} + $barcode = $this->addCheckCode($t['id']); + // If we're supposed to print barcode and voucher number on ticket + switch ($t['ticket_voucher_type']) { + + case 11: // Voucher/Ticket for Pickup - no Barcode + $this->glmpdfSetFont( "Helvetica-Bold", 20.0 ); + $this->glmpdfPlaceText( "Pickup at ".$this->config->term->prop->norm, 510, 140, 'left', 'black', -260, 'position=center rotate=90'); + $this->glmpdfSetFont( "Courier", 12.0 ); + $this->glmpdfPlaceText( $this->config->term->voucher->cap." $barcode", 540, 140, 'left', 'black', -260, 'position=center rotate=90'); + break; + + case 12; // Voucher/Ticket to be mailed Mailed - no Barcode + case 82; // Object Sold (i.e. books) to be mailed - no Barcode + $this->glmpdfSetFont( "Helvetica-Bold", 20.0 ); + $this->glmpdfPlaceText( "You will receive this by mail", 510, 140, 'left', 'black', -260, 'position=center rotate=90'); + $this->glmpdfSetFont( "Courier", 12.0 ); + $this->glmpdfPlaceText( $this->config->term->voucher->cap." $barcode", 540, 140, 'left', 'black', -260, 'position=center rotate=90'); + break; + + case 1: // Standard Voucher/Ticket with Barcode + case 81; // Object Sold (i.e. books) to be claimed - with Barcode + default: + $this->glmpdfSetFont( 'barcode', 54 ); + $this->glmpdfPlaceText( "*$barcode*", 510, 140, 'left', 'black', 0, 'position=center rotate=90'); + $this->glmpdfSetFont( "Courier", 12.0 ); + $this->glmpdfPlaceText( $this->config->term->voucher->cap." $barcode", 540, 140, 'left', 'black', -260, 'position=center rotate=90'); + break; + + } + + $this->glmpdfPlaceText( "Order #".$order['id'], 552, 140, 'left', 'black', 0, 'position=center rotate=90'); + + // Check if we need to display a coupon +// if( ++$numb_tickets % $this->pdfCouponInterval == 0 ) +// $this->printCoupon(); + + } // Each voucher + + // Make sure we print the minimum number of coupons +// $numb_coupons = 0; +// while( $numb_coupons < $this->pdfMinCoupons ) { +// $this->printCoupon(); +// $numb_coupons++; +// } + + // Close PDF setup and send to user's browser + $this->glmpdfSendToBrowser( '', 'voucher.pdf' ); + + if ($venueImageFile) { + unlink($venueImageFile); + } + if ($parkingImageFile) { + unlink($parkingImageFile); + } + if ($sectionImageFile) { + unlink($sectionImageFile); + } + if ($sectionImageFile) { + unlink($sectionImageFile); + } + + } + + + // function to print a coupon + function printCoupon() + { + // Print a Coupon + $this->glmpdfNextForm(); + $this->glmpdfPlaceBox( $this->borderWidth, 0, 142, 281, 142, $this->borderColor ); + + // Place Coupon Image + $this->glmpdfSetFont( "Helvetica-Bold", 10.0 ); + $this->glmpdfPlaceText( 'Coupon Title', 85, 130, "center", 'black' ); + $this->glmpdfPlaceText( 'Expires on: 1/1/2020', 85, 75 ); + $this->glmpdfSetFont( "Times-Bold", 30.0 ); + $this->glmpdfPlaceText( "COUPON", 85, 95, "center", 'lightgrey' ); + $this->glmpdfSetFont( "Helvetica", 8.0 ); + $this->glmpdfPlaceTextBox( 'This is a coupon description. It describes this coupon.', 5, 55, 274, 40, "left", 'black' ); + $this->glmpdfSetFont( "Helvetica-Bold", 8.5 ); + $this->glmpdfPlaceText( "Mackinaw Area Visitors Bureau - Mackinaw City, MI - 800-666-0160", 140.5, 2, "center", 'darkblue' ); + + } + + /* + * Function to add check character to end of voucher number + * + * Uses config->voucher_check_secret and voucher # to create MD5 string + * then takes last hex character off of that string and shifts it up to + * always be a character (adds 16 to numbers and 10 to the upper-case + * version of the character). + * i.e. 0 = A, 9 = J, A = K, F = + * + */ + public function addCheckCode($voucherNumb) + { + + // Create MD5 string using voucher number and secret + $md5 = md5($voucherNumb.$this->config->voucher_check_secret); + + // Get last character code of the last character in the MD5 + $cc = strtoupper(substr($md5, -2)); + $cc[0] = $this->shiftCheckCodeCharacter($cc[0]); + $cc[1] = $this->shiftCheckCodeCharacter($cc[1]); + + // Return voucher number with the new character on the end + $voucherNumb .= $cc; + return $voucherNumb; + + } + + private function shiftCheckCodeCharacter($c) { + + $x = ord($c); + + // If it's a digit, add 16 + if ($x < 65) { + $x += 17; + // otherwise, add 10 + } else { + $x += 10; + } + + // Also skip the letter O + if (x >= ord('O')) { + $x += 1; + } + + return chr($x); + } + +} // class + +// Absolutely nothing after next line +?> \ No newline at end of file diff --git a/views/NOTE.txt b/views/NOTE.txt new file mode 100755 index 0000000..0862734 --- /dev/null +++ b/views/NOTE.txt @@ -0,0 +1,2 @@ +NOTE: When adding a new interface (set of view), add both here and in the web/front directory. +Also add the new interface to the EventManagement configs/common.ini file. \ No newline at end of file diff --git a/views/admin/tickets/Accommodation/list.html b/views/admin/tickets/Accommodation/list.html new file mode 100644 index 0000000..e17688e --- /dev/null +++ b/views/admin/tickets/Accommodation/list.html @@ -0,0 +1,28 @@ +

    + +
    +{if:accomsList} + + + {foreach:accomsList,a} + + + + + + + + + {end:} +
     PropertyNameTitleCateogoryQuantity
    {a.property}{a.name}{a.title}{a.category.name}{a.quant}
    +{else:} + (No accommodations listed for selected {term.event.norm} or no {term.event.norm} selected.) +{end:} + + +{startScript:h} + $(document).ready(function(){ + $('#accomsSelectAll').html('All (' + {accomsStats.all} + ')'); + $('#accomsSelectMember').html('Selected Property (' + {accomsStats.member} + ')'); + }); + \ No newline at end of file diff --git a/views/admin/tickets/Addon/delete.html b/views/admin/tickets/Addon/delete.html new file mode 100644 index 0000000..11351b9 --- /dev/null +++ b/views/admin/tickets/Addon/delete.html @@ -0,0 +1,63 @@ +
    + +
    Delete this {term.ticket.cap} Add-On
    + +
    {AddonDetail.name}
    + +
    + + +
    + + {if:addonDetail} +
    + + + + + + + + + + + + + + + + +
    Delete {term.ticket.cap} Add-On: +

    Clicking "Confirm Delete" on the right will permanently delete this {term.ticket.norm} add-on.

    +
    {term.addon.cap} Add-On Name:{addonDetail.name}ID: {addonDetail.id}
    Description:{addonDetail.descr:h}
    Type: + {addonDetail.add_on_type.name:h} +
    Maximum Quantity: {addonDetail.max_quant} +
    Unit Name:{addonDetail.unit_name}
    Unit Cost:{addonDetail.unit_cost}
    + {else:} +

    No {term.ticket.plur} add-ons found.

    + {end:} + +
    + +
    +{startScript:h} + $(document).ready(function(){ + + $('#AddonDeleteTable').dataTable({ + "bPaginate": false, + "bLengthChange": false, + "bFilter": false, + "bSort": false, + "bInfo": false, + "bAutoWidth": false, + "bDestroy": true + }); + + f_restartOnTabSelect(); + + }); + diff --git a/views/admin/tickets/Addon/detail.html b/views/admin/tickets/Addon/detail.html new file mode 100644 index 0000000..c92ae61 --- /dev/null +++ b/views/admin/tickets/Addon/detail.html @@ -0,0 +1,74 @@ +
    + + + +
    + + +
    + + {if:addonDetail} +
    + + + + {if:addonDetail.delete} + + + + + {end:} + + + + + + + + + +
    Delete {term.ticket.cap} Add-On: + {if:addonDetail.deleteConfirmed} + {if:addonDetail.deleteFailure} +

    FAILED:

    + Sorry, we are unable to delete the entry at this time.
    + {addonDetail.reason:h} + {else:} +

    Deleted

    + {end:} + {else:} +
    +

    Clicking the button above will permanently delete this {term.ticket.norm} add-on.

    + {end:} +
    {term.ticket.cap} Add-On Name:{addonDetail.name}ID: {addonDetail.id}
    Description:{addonDetail.descr:h}
    Type: + {addonDetail.add_on_type.name:h} +
    Maximum Quantity: {addonDetail.max_quant} +
    Unit Name:{addonDetail.unit_name}
    Unit Cost:{addonDetail.unit_cost}
    + {else:} +

    No {term.ticket.norm} add-ons found.

    + {end:} + +
    + +
    +{startScript:h} + $(document).ready(function(){ + + $('#AddonDetailTable').dataTable({ + "bPaginate": false, + "bLengthChange": false, + "bFilter": false, + "bSort": false, + "bInfo": false, + "bAutoWidth": false, + "bDestroy": true + }); + + f_restartOnTabSelect(); + + }); + diff --git a/views/admin/tickets/Addon/edit.html b/views/admin/tickets/Addon/edit.html new file mode 100644 index 0000000..59c4c37 --- /dev/null +++ b/views/admin/tickets/Addon/edit.html @@ -0,0 +1,200 @@ +
    + +
    + {if:addingNewAddon}Adding New {term.ticket.cap} Add-On{end:} + {if:editingAddon}Editing {term.ticket.cap} Add-On{end:} +
    + +
    +{if:addingNewAddon} + +{else:} + +{end:} +
    + +{if:formFail} +
    Not all fields were filled in correctly. Please try again.
    +{end:} + +
    + + {if:addonDetail} + +

    Required fields in RED.

    + +
    + {if:addingNewAddon} + + {else:} + + {end:} + + + + + + + +
    + + + + + {if:fieldRequired.name} + {if:fieldFail.name} + + + {if:fieldRequired.descr} + {if:fieldFail.descr} + + + {if:fieldRequired.add_on_type} + {if:fieldFail.add_on_type} + + + {if:fieldRequired.unit_name} + {if:fieldFail.unit_name} + + + {if:fieldRequired.unit_cost_numb} + {if:fieldFail.unit_cost_numb} + + +
    {else:}{end:}{term.ticket.cap} Add-On Name:{else:}{end:} +
    + {if:fieldFail.name}
    {fieldFail.name}{end:} +
    {else:}{end:}Description:{else:}{end:} + + {if:fieldFail.descr}
    {fieldFail.descr}{end:} +
    {else:}{end:}{term.ticket.cap} Add-On Type:{else:}{end:} + + {if:fieldFail.add_on_type}
    {fieldFail.add_on_type}{end:} +
    + + {if:fieldFail.max_quant}{else:}{end:} + + + +
    Maximum quantity a user may select: + +
    This is the maximum number of these {term.ticket.norm} add-ons that a user may select. +
    +
    +
    {else:}{end:}{term.ticket.cap} Add-On Unit Name:{else:}{end:} +
    + {if:fieldFail.unit_name}
    {fieldFail.unit_name}{end:} +
    {else:}{end:}Price Per Unit:{else:}{end:} + + {if:fieldFail.unit_cost_numb}
    {fieldFail.unit_cost_numb}{end:} +
    +
    + +
    + {if:addingNewAddon} + + {end:} + {if:editingAddon} + + {end:} +
    + +
    + + {else:} +

    No {term.ticket.norm} add-on has been selected yet.

    +

    To edit a {term.ticket.norm} add-on, first select it from the list of available {term.ticket.plur} add-ons. + {end:} + +

    + +
    + + +
    + +{startScript:h} + + $(function() { + + /* + * Table operations + */ + + $('.addonEditTable').dataTable({ + "bPaginate": false, + "bLengthChange": false, + "bFilter": false, + "bSort": false, + "bInfo": false, + "bAutoWidth": false, + "bDestroy": true + }); + + /* + * AJAX form handling + */ + + $('#addonForm').ajaxForm({ + success: function(data) { + {if:addingNewAddon} + var container = $('#Addon_detail_container'); + f_replaceContents(data, container); + {end:} + {if:editingAddon} + var container = $('#Addon_detail_container'); + f_replaceContents(data, container); + {end:} + return false; + } + }); + + // Block default form submission + $("form").submit(function (e) { + $('#addonFormSubmit').html('
    Submitting, Please Wait...
    '); + e.preventDefault(); + }); + + /* + * CKeditor actions + */ + + // Code to kick off CKEditor for specific fields + f_buildCkeditor($("#descr")); + + // Remove the editors and store the data back in the textareas before the AJAX form submission + $('.emEditSubmit').click( function() { + f_removeCkeditor($("#descr")); + }); + + f_restartOnTabSelect(); + + function addonTypeCheck(e) { + typeval = $('#addonType').val(); + + // If this is a quantity selection + if (typeval == 2) { + $('#max_quant').show(); + } else { + $('#max_quant').hide(); + } + } + + $('#addonType').change( function() { + addonTypeCheck(); + }); + addonTypeCheck(); + + }); + + \ No newline at end of file diff --git a/views/admin/tickets/Addon/list.html b/views/admin/tickets/Addon/list.html new file mode 100644 index 0000000..6627904 --- /dev/null +++ b/views/admin/tickets/Addon/list.html @@ -0,0 +1,124 @@ + +
    + +
    +
    +{if:checkPermission(#10#)} + +{end:} + +
    + Search {term.ticket.cap} Add-Ons: (start typing any information in list) + + {if:addons} + +
    + + + + + + {foreach:addons,c} + + + + + + {end:} + +
    Add-On NameTypePrice
    {c.unit_cost} / {c.unit_name}
    +
    + + {else:} +

    No {term.ticket.norm} add-ons listed.

    + {end:} + +
    +
    + +
    + +
    +{startScript:h} + + // Addons Search + var addonsSearchData = [ + {foreach:addons,c} + {label:'{c.name:h}, {c.ticket_name:h}, {c.add_on_type.name}', value:'{c.id}'}, + {end:} + ]; + + $(function() { + + var AddonListTable = $('#AddonListTable').dataTable({ + "sScrollY": "100px", + "scrollX": true, + "bScrollCollapse": true, + "bPaginate": false, + "bLengthChange": false, + "bFilter": false, + "bSort": true, + "bInfo": false, + "bAutoWidth": false, + "bDestroy": true, + }); + + $(window).resize(function(){ + AddonListTable.fnDraw(); + }); + + // Toggle length of table + var AddonListTableSmall = true; + var AddonListTableHeight = $('#AddonListTable_wrapper div.dataTables_scrollBody').height(); + $('#addonListSizeChange').click(function() { + if (AddonListTableSmall) { + $('#AddonListTable_wrapper div.dataTables_scrollBody').height('auto'); + AddonListTableSmall = false; + $(this).html('Smaller Table'); + AddonListTable.fnSettings().oScroll.sY = '100%'; + AddonListTable.fnDraw(); + } else { + $('#AddonListTable_wrapper div.dataTables_scrollBody').height(AddonListTableHeight); + AddonListTableSmall = true; + $(this).html('Larger Table'); + AddonListTable.fnSettings().oScroll.sY = '100px'; + AddonListTable.fnDraw(); + } + }); + + // Close all local sliders + $('#Addon_detail').hide(duration); + + $('.addonListSelect').click(function(){ + $('#AddonListTable_wrapper div.dataTables_scrollBody').height(AddonListTableHeight); + AddonListTableSmall = true; + $('#addonListSizeChange').html('Larger Table'); + AddonListTable.fnSettings().oScroll.sY = '100px'; + AddonListTable.fnDraw(); + f_loadAction('Addon_selected', 'Addon_detail_container', 'AddonID=' + $(this).attr('emAddonId') + '&tabList={tabList}'); + }); + + // Search Addons + $("#addonsSearch").autocomplete({ + source: addonsSearchData, + minLength: 1, + focus: function(event, ui) { + // Don't auto fill on focus + return false; + }, + select: function(event, ui) { + $("#addonsSearch").attr({value: ui.item.label}); + f_loadAction('Addon_selected', 'Addon_detail_container', 'AddonID=' + ui.item.value + '&tabList={tabList}'); + return false; + } + }); + + f_restartOnTabSelect(); + + }); + + diff --git a/views/admin/tickets/Addon/selected.html b/views/admin/tickets/Addon/selected.html new file mode 100644 index 0000000..9dd8aef --- /dev/null +++ b/views/admin/tickets/Addon/selected.html @@ -0,0 +1,32 @@ +
    + +
    +
    {term.ticket.cap} Add-On: {addonDetail.name}
    +
    + +
    + + +
    +
    + +
    + +
    + + +{startScript:h} + + // jQuery Section + $(document).ready(function(){ + + // Start with ticket detail loaded + f_loadAction('Addon_detail', 'Addon_detail_container', "tabList={tabList}"); + + f_restartOnTabSelect(); + + }); + + diff --git a/views/admin/tickets/Attendance/added.html b/views/admin/tickets/Attendance/added.html new file mode 100755 index 0000000..df53b1b --- /dev/null +++ b/views/admin/tickets/Attendance/added.html @@ -0,0 +1,16 @@ +
    + +
    New {term.attendance_log.cap} Added
    + +
    + +{startScript:h} + + $(function() { + + f_loadAction('Attendance_selected', 'Attendance_selected', 'member_id={attendanceDetail.id}&tabList={tabList}'); + + }); + + + diff --git a/views/admin/tickets/Attendance/delete.html b/views/admin/tickets/Attendance/delete.html new file mode 100755 index 0000000..d59183b --- /dev/null +++ b/views/admin/tickets/Attendance/delete.html @@ -0,0 +1,90 @@ +
    + +
    Delete this {term.attendance_log.cap}
    + +
    {attendanceDetail.lname}, {attendanceDetail.fname}
    + +{if:checkPermission(#10#)} +
    + + +
    +{end:} + + {if:attendanceDetail} +
    + + + + + + + + + + + + + + + {if:attendanceDetail.org_url} + + {end:} + {if:attendanceDetail.office_phone} + + {end:} + {if:attendanceDetail.mobile_phone} + + {end:} + {if:attendanceDetail.fax} + + {end:} + {if:attendanceDetail.email} + + {end:} + {if:attendanceDetail.login_id} + + {end:} + {if:attendanceDetail.alt_email} + + {end:} + {if:attendanceDetail.notes} + + {end:} + +
    Delete {term.attendance_log.cap}: +

    Clicking "Confirm Delete" on the right will permanently delete this {term.attendance_log.norm}.

    +
    Name:{attendanceDetail.lname}, {attendanceDetail.fname}
    Organization:{attendanceDetail.org}
    Address: + {attendanceDetail.addr1}
    + {if:addr2}{attendanceDetail.addr2}
    {end:} + {attendanceDetail.city}, {attendanceDetail.state.name} {attendanceDetail.zip}
    + {attendanceDetail.country.name} +
    Active:{attendanceDetail.active.name}
    Web Address:{attendanceDetail.org_url}
    Office Phone:{attendanceDetail.office_phone}
    Mobile (cell) Phone:{attendanceDetail.mobile_phone}
    FAX:{attendanceDetail.fax}
    E-Mail Address:{attendanceDetail.email}
    Log in ID:{attendanceDetail.login_id}
    Alternate E-Mail Address:{attendanceDetail.alt_email}
    Notes:{attendanceDetail.notes}
    + {else:} +

    No {term.attendace_log.plur} found.

    + {end:} + +
    + +
    +{startScript:h} + $(document).ready(function(){ + + $('#AttendanceDeleteTable').dataTable({ + "bPaginate": false, + "bLengthChange": false, + "bFilter": false, + "bSort": false, + "bInfo": false, + "bAutoWidth": false, + "bDestroy": true + }); + + f_restartOnTabSelect(); + + }); + diff --git a/views/admin/tickets/Attendance/detail.html b/views/admin/tickets/Attendance/detail.html new file mode 100644 index 0000000..0e464f5 --- /dev/null +++ b/views/admin/tickets/Attendance/detail.html @@ -0,0 +1,115 @@ +
    + +
    + {if:addingNewAttendance}Adding New {term.attendace_log.cap}{end:} + {if:editingAttendance}Editing {term.attendance_log.cap}{end:} +
    + +
    {term.attendace_log.cap}: {attendanceDetail.lname}, {attendanceDetail.fname}
    + + {if:checkPermission(#10#)} +
    + + +
    + {end:} + + {if:attendanceDetail} +
    + + + + {if:attendanceDetail.delete} + + + + + {end:} + + + + + + + + {if:attendanceDetail.org_url} + + {end:} + {if:attendanceDetail.office_phone} + + {end:} + {if:attendanceDetail.mobile_phone} + + {end:} + {if:attendanceDetail.fax} + + {end:} + {if:attendanceDetail.email} + + {end:} + {if:attendanceDetail.login_id} + + {end:} + {if:attendanceDetail.alt_email} + + {end:} + {if:attendanceDetail.image} + + + + + {end:} + + {if:attendanceDetail.notes} + + {end:} + +
    Delete {term.attendance.cap}: + {if:attendanceDetail.deleteConfirmed} + {if:attendanceDetail.deleteFailure} +

    FAILED:

    + Sorry, we are unable to delete the entry at this time.
    + {attendanceDetail.reason:h} + {else:} +

    Deleted

    + {end:} + {else:} +
    +

    Clicking the button above will permanently delete this {term.attendance_log.norm}.

    + {end:} +
    Name:{attendanceDetail.lname}, {attendanceDetail.fname}ID: {attendanceDetail.id}
    Organization:{attendanceDetail.org}
    Address: + {attendanceDetail.addr1}
    + {if:addr2}{attendanceDetail.addr2}
    {end:} + {attendanceDetail.city}, {attendanceDetail.state.name} {attendanceDetail.zip}
    + {attendanceDetail.country.name} +
    Active:{attendanceDetail.active.name}
    Web Address:{attendanceDetail.org_url}
    Office Phone:{attendanceDetail.office_phone}
    Mobile (cell) Phone:{attendanceDetail.mobile_phone}
    FAX:{attendanceDetail.fax}
    E-Mail Address:{attendanceDetail.email}
    Log in ID:{attendanceDetail.login_id}
    Alternate E-Mail Address:{attendanceDetail.alt_email}
    Image: + +
    User Permissions:{attendanceDetail.user_rights.name}
    Notes:{attendanceDetail.notes:h}
    + {else:} +

    No {term.attendance_log.plur} found.

    + {end:} + +
    + +
    +{startScript:h} + $(document).ready(function(){ + + $('#AttendanceDetailTable').dataTable({ + "bPaginate": false, + "bLengthChange": false, + "bFilter": false, + "bSort": false, + "bInfo": false, + "bAutoWidth": false, + "bDestroy": true + }); + + f_restartOnTabSelect(); + + }); + diff --git a/views/admin/tickets/Attendance/edit.html b/views/admin/tickets/Attendance/edit.html new file mode 100755 index 0000000..ed6072c --- /dev/null +++ b/views/admin/tickets/Attendance/edit.html @@ -0,0 +1,185 @@ +
    + +
    + {if:addingNewAttendance}Adding New {term.attendance_log.cap}{end:} + {if:editingAttendance}Editing {term.attendance_log.cap}{end:} +
    + +
    +{if:addingNewAttendance} + +{else:} + +{end:} +
    + +{if:formFail} +
    Not all fields were filled in correctly. Please try again.
    +{end:} + +
    + + {if:attendanceDetail} + +

    Required fields in RED.

    + +
    + {if:addingNewAttendance} + + {else:} + + {end:} + + + + {if:attendanceDetail.attendance_type.value} + + {else:} + + {end:} + + + + + + +
    + + + + + + + + + {if:fieldRequired.name} + {if:fieldFail.name} + + + {if:fieldRequired.notes} + {if:fieldFail.notes} + + + {if:fieldRequired.attendance_date} + {if:fieldFail.attendanceDate} + + +
    {term.prop.cap}: + {if:addingNewAttendance} + + {if:fieldFail.performance}
    {fieldFail.performance}{end:} + {else:} + {attendanceDetail.member_name} + {end:} +
    {else:}{end:}Name of this {term.attendance_log.cap}:{else:}{end:} + + {if:fieldFail.attendance}
    {fieldFail.attendance}{end:} +
    {else:}{end:}Notes:{else:}{end:} + + {if:fieldFail.notes}
    {fieldFail.notes}{end:} +
    {else:}{end:}Date:{else:}{end:} + {if:addingNewAttendance} + + {else:} +
    + {end:} +
    +
    + +
    + {if:addingNewAttendance} + + {end:} + {if:editingAttendance} + + {end:} +
    + +
    + + {else:} +

    No {term.attendance_log.norm} has been selected yet.

    +

    To edit a {term.attendance_log.norm}, first select it from the list of available {term.attendance_log.plur}. + {end:} + +

    + +
    + + +
    + +{startScript:h} + + $(function() { + + /* + * Table operations + */ + + $('.attendanceEditTable').dataTable({ + "bPaginate": false, + "bLengthChange": false, + "bFilter": false, + "bSort": false, + "bInfo": false, + "bAutoWidth": false, + "bDestroy": true + }); + + /* + * AJAX form handling + */ + + $('#AttendanceForm').ajaxForm({ + success: function(data) { + {if:addingNewAttendance} + f_replaceContents(data, $('#Attendance_detail_container')); + {end:} + {if:editingAttendance} + f_replaceContents(data, $('#Attendance_detail_container')); + {end:} + return false; + } + }); + + // Block default form submission + $("form").submit(function (e) { + $('#attendanceFormSubmit').html('
    Submitting, Please Wait...
    '); + e.preventDefault(); + }); + + /* + * CKeditor actions + */ + + // Code to kick off CKEditor for specific fields +// f_buildCkeditor($("#notes")); + + // Remove the editors and store the data back in the textareas before the AJAX form submission + $('.emEditSubmit').click( function() { + f_removeCkeditor($("#notes")); + }); + + f_restartOnTabSelect(); + + // Code to start datepicker for each date input + $("#attendanceDateInput").datepicker({ + dateFormat: "mm/dd/yy", + minDate: '{attendanceDetail.attendance_date.date_list.min}', + maxDate: '{attendanceDetail.attendance_date.date_list.max}' + }); + + + }); + + \ No newline at end of file diff --git a/views/admin/tickets/Attendance/list.html b/views/admin/tickets/Attendance/list.html new file mode 100644 index 0000000..0c746ac --- /dev/null +++ b/views/admin/tickets/Attendance/list.html @@ -0,0 +1,125 @@ + +
    + +
    +{if:checkPermission(#10#)} + +{end:} + +
    + + Search {term.attendance_log.plur_cap}: (type any portion of a {term.attendance_log.norm} name) + + {if:AttendanceList.Attendance_list} + +
    + + + + + + {foreach:AttendanceList.Attendance_list,c} + + + + + + + + {end:} + +
    Last NameFirst NameOrganizationPhoneE-Mail
    {c.org}{c.office_phone}{c.email}
    +
    + + {else:} +

    No {term.attendance_log.plur} are currently listed.

    +

    You should have at least one {term.attendance_log.norm} listed for each {term.prop.norm}.

    + {end:} + +
    +
    + + +
    +{startScript:h} + + // Attendances Search + var AttendancesSearchData = [ + {foreach:AttendanceList.Attendance_list,c} + {label:'{c.lname:h}, {c.fname:h}', value:'{c.id}'}, + {end:} + ]; + + $(function() { + + var AttendanceListTable = $('#AttendanceListTable').dataTable({ + "sScrollY": "100px", + "scrollX": true, + "bScrollCollapse": true, + "bPaginate": false, + "bLengthChange": false, + "bFilter": false, + "bSort": true, + "bInfo": false, + "bAutoWidth": false, + "bDestroy": true + }); + $(window).resize(function(){ + AttendanceListTable.fnDraw(); + }); + + // Toggle length of table + var AttendanceListTableSmall = true; + var AttendanceListTableHeight = $('#AttendanceListTable_wrapper div.dataTables_scrollBody').height(); + $('#AttendanceListSizeChange').click(function() { + if (AttendanceListTableSmall) { + $('#AttendanceListTable_wrapper div.dataTables_scrollBody').height('auto'); + AttendanceListTableSmall = false; + $(this).html('Smaller Table'); + AttendanceListTable.fnSettings().oScroll.sY = '100%'; + AttendanceListTable.fnDraw(); + } else { + $('#AttendanceListTable_wrapper div.dataTables_scrollBody').height(AttendanceListTableHeight); + AttendanceListTableSmall = true; + $(this).html('Larger Table'); + AttendanceListTable.fnSettings().oScroll.sY = '100px'; + AttendanceListTable.fnDraw(); + } + }); + + // Close all local sliders + $('#Attendance_detail').hide(duration); + + $('.AttendanceListSelect').click(function(){ + $('#AttendanceListTable_wrapper div.dataTables_scrollBody').height(AttendanceListTableHeight); + AttendanceListTableSmall = true; + $('#AttendanceListSizeChange').html('Larger Table'); + AttendanceListTable.fnSettings().oScroll.sY = '100px'; + AttendanceListTable.fnDraw(); + f_loadAction('Attendance_detail', 'Attendance_detail_container', 'AttendanceID=' + $(this).attr('emAttendanceId') + '&tabList={tabList}'); + }); + + // Search Attendances + $("#AttendancesSearch").autocomplete({ + source: AttendancesSearchData, + minLength: 1, + focus: function(event, ui) { + // Don't auto fill on focus + return false; + }, + select: function(event, ui) { + $("#AttendancesSearch").attr({value: ui.item.label}); + f_loadAction('Attendance_detail', 'Attendance_detail_container', 'AttendanceID=' + ui.item.value + '&tabList={tabList}'); + return false; + } + }); + + f_restartOnTabSelect(); + + }); + + diff --git a/views/admin/tickets/Contact/added.html b/views/admin/tickets/Contact/added.html new file mode 100644 index 0000000..a851c80 --- /dev/null +++ b/views/admin/tickets/Contact/added.html @@ -0,0 +1,16 @@ +
    + +
    New Contact Added
    + +
    + +{startScript:h} + + $(function() { + + f_loadAction('Contact_selected', 'Contact_selected', 'member_id={contactDetail.id}&tabList={tabList}'); + + }); + + + diff --git a/views/admin/tickets/Contact/delete.html b/views/admin/tickets/Contact/delete.html new file mode 100644 index 0000000..3de1e46 --- /dev/null +++ b/views/admin/tickets/Contact/delete.html @@ -0,0 +1,90 @@ +
    + +
    Delete this {term.contact.cap}
    + +
    {contactDetail.lname}, {contactDetail.fname}
    + +{if:checkPermission(#10#)} +
    + + +
    +{end:} + + {if:contactDetail} +
    + + + + + + + + + + + + + + + {if:contactDetail.org_url} + + {end:} + {if:contactDetail.office_phone} + + {end:} + {if:contactDetail.mobile_phone} + + {end:} + {if:contactDetail.fax} + + {end:} + {if:contactDetail.email} + + {end:} + {if:contactDetail.login_id} + + {end:} + {if:contactDetail.alt_email} + + {end:} + {if:contactDetail.notes} + + {end:} + +
    Delete {term.contact.cap}: +

    Clicking "Confirm Delete" on the right will permanently delete this {term.contact.norm}.

    +
    Name:{contactDetail.lname}, {contactDetail.fname}
    Organization:{contactDetail.org}
    Address: + {contactDetail.addr1}
    + {if:addr2}{contactDetail.addr2}
    {end:} + {contactDetail.city}, {contactDetail.state.name} {contactDetail.zip}
    + {contactDetail.country.name} +
    Active:{contactDetail.active.name}
    Web Address:{contactDetail.org_url}
    Office Phone:{contactDetail.office_phone}
    Mobile (cell) Phone:{contactDetail.mobile_phone}
    FAX:{contactDetail.fax}
    E-Mail Address:{contactDetail.email}
    Log in ID:{contactDetail.login_id}
    Alternate E-Mail Address:{contactDetail.alt_email}
    Notes:{contactDetail.notes}
    + {else:} +

    No {term.contact.plur} found.

    + {end:} + +
    + +
    +{startScript:h} + $(document).ready(function(){ + + $('#ContactDeleteTable').dataTable({ + "bPaginate": false, + "bLengthChange": false, + "bFilter": false, + "bSort": false, + "bInfo": false, + "bAutoWidth": false, + "bDestroy": true + }); + + f_restartOnTabSelect(); + + }); + diff --git a/views/admin/tickets/Contact/detail.html b/views/admin/tickets/Contact/detail.html new file mode 100644 index 0000000..9e8b97e --- /dev/null +++ b/views/admin/tickets/Contact/detail.html @@ -0,0 +1,115 @@ +
    + +
    + {if:addingNewContact}Adding New {term.contact.cap}{end:} + {if:editingContact}Editing {term.contact.cap}{end:} +
    + +
    Contact: {contactDetail.lname}, {contactDetail.fname}
    + + {if:checkPermission(#10#)} +
    + + +
    + {end:} + + {if:contactDetail} +
    + + + + {if:contactDetail.delete} + + + + + {end:} + + + + + + + + {if:contactDetail.org_url} + + {end:} + {if:contactDetail.office_phone} + + {end:} + {if:contactDetail.mobile_phone} + + {end:} + {if:contactDetail.fax} + + {end:} + {if:contactDetail.email} + + {end:} + {if:contactDetail.login_id} + + {end:} + {if:contactDetail.alt_email} + + {end:} + {if:contactDetail.image} + + + + + {end:} + + {if:contactDetail.notes} + + {end:} + +
    Delete {term.contact.cap}: + {if:contactDetail.deleteConfirmed} + {if:contactDetail.deleteFailure} +

    FAILED:

    + Sorry, we are unable to delete the entry at this time.
    + {contactDetail.reason:h} + {else:} +

    Deleted

    + {end:} + {else:} +
    +

    Clicking the button above will permanently delete this {term.contact.norm}.

    + {end:} +
    Name:{contactDetail.lname}, {contactDetail.fname}ID: {contactDetail.id}
    Organization:{contactDetail.org}
    Address: + {contactDetail.addr1}
    + {if:addr2}{contactDetail.addr2}
    {end:} + {contactDetail.city}, {contactDetail.state.name} {contactDetail.zip}
    + {contactDetail.country.name} +
    Active:{contactDetail.active.name}
    Web Address:{contactDetail.org_url}
    Office Phone:{contactDetail.office_phone}
    Mobile (cell) Phone:{contactDetail.mobile_phone}
    FAX:{contactDetail.fax}
    E-Mail Address:{contactDetail.email}
    Log in ID:{contactDetail.login_id}
    Alternate E-Mail Address:{contactDetail.alt_email}
    Image: + +
    User Permissions:{contactDetail.user_rights.name}
    Notes:{contactDetail.notes:h}
    + {else:} +

    No {term.contact.plur} found.

    + {end:} + +
    + +
    +{startScript:h} + $(document).ready(function(){ + + $('#ContactDetailTable').dataTable({ + "bPaginate": false, + "bLengthChange": false, + "bFilter": false, + "bSort": false, + "bInfo": false, + "bAutoWidth": false, + "bDestroy": true + }); + + f_restartOnTabSelect(); + + }); + diff --git a/views/admin/tickets/Contact/edit.html b/views/admin/tickets/Contact/edit.html new file mode 100644 index 0000000..7bd32f7 --- /dev/null +++ b/views/admin/tickets/Contact/edit.html @@ -0,0 +1,341 @@ +
    + +
    + {if:addingNewContact}Adding New {term.contact.cap}{end:} + {if:editingContact}Editing {term.contact.cap}{end:} +
    + +
    +{if:addingNewContact} + +{else:} + +{end:} +
    + +{if:formFail} +
    Not all fields were filled in correctly. Please try again.
    +{end:} + +
    + + {if:contactDetail} + +

    Required fields in RED.

    + +
    + {if:addingNewContact} + + {else:} + + {end:} + + + + {if:contactDetail.contact_type.value} + + {else:} + + {end:} + + + + + + +
    + + + + + + + + +
    + + + + + + + {if:fieldRequired.fname} + {if:fieldFail.fname} + + + {if:fieldRequired.lname} + {if:fieldFail.lname} + + + {if:fieldRequired.org} + {if:fieldFail.org} + + + {if:fieldRequired.addr1} + {if:fieldFail.addr1} + + + {if:fieldRequired.addr2} + {if:fieldFail.addr2} + + + {if:fieldRequired.city} + {if:fieldFail.city} + + + {if:fieldRequired.state} + {if:fieldFail.state} + + + {if:fieldRequired.zip} + {if:fieldFail.zip} + + + {if:fieldRequired.country} + {if:fieldFail.country} + + + + + + + {if:fieldRequired.image} + {if:fieldFail.image} + + +
    {term.contact.cap} Type:{contactDetail.contact_type_name}
    Affiliation:{contactDetail.affiliation_name}
    {else:}{end:}First Name:{else:}{end:} + + {if:fieldFail.fname}
    {fieldFail.fname}{end:} +
    {else:}{end:}Last Name:{else:}{end:} + + {if:fieldFail.lname}
    {fieldFail.lname}{end:} +
    {else:}{end:}Organization Name:{else:}{end:} + + {if:fieldFail.org}
    {fieldFail.org}{end:} +
    {else:}{end:}Address:{else:}{end:} + + {if:fieldFail.addr1}
    {fieldFail.addr1}{end:} +
    {else:}{end:} {else:}{end:} + + {if:fieldFail.addr2}
    {fieldFail.addr2}{end:} +
    {else:}{end:}City:{else:}{end:} + + {if:fieldFail.city}
    {fieldFail.city}{end:} +
    {else:}{end:}State:{else:}{end:} + + {if:fieldFail.state}
    {fieldFail.state}{end:} +
    {else:}{end:}ZIP/Postal Code:{else:}{end:} + + {if:fieldFail.zip}
    {fieldFail.zip}{end:} +
    {else:}{end:}Country:{else:}{end:} + + {if:fieldFail.country}
    {fieldFail.country}{end:} +
    Active: + {if:contactDetail.active.value} + + {else:} + + {end:} +
    {else:}{end:}Image:{else:}{end:} + {if:contactDetail.image} + +
    Delete this image: + {end:} + +
    Upload or replace the image: + {if:fieldFail.image}
    {fieldFail.image}{end:} +
    +
    + + + + + {if:fieldRequired.office_phone} + {if:fieldFail.office_phone} + + + {if:fieldRequired.mobile_phone} + {if:fieldFail.mobile_phone} + + + {if:fieldRequired.alt_phone} + {if:fieldFail.alt_phone} + + + {if:fieldRequired.fax} + {if:fieldFail.fax} + + + {if:fieldRequired.email} + {if:fieldFail.email} + + + {if:fieldRequired.login_id} + {if:fieldFail.login_id} + + + {if:fieldRequired.password} + {if:fieldFail.password} + + + {if:fieldRequired.alt_email} + {if:fieldFail.alt_email} + + + {if:fieldRequired.user_rights} + {if:fieldFail.user_rights} + + + {if:fieldRequired.notes} + {if:fieldFail.notes} + + +
    {else:}{end:}Office phone:{else:}{end:} + + {if:fieldFail.office_phone}
    {fieldFail.office_phone}{end:} +
    {else:}{end:}Mobile phone:{else:}{end:} + + {if:fieldFail.mobile_phone}
    {fieldFail.mobile_phone}{end:} +
    {else:}{end:}Alternate phone:{else:}{end:} + + {if:fieldFail.alt_phone}
    {fieldFail.alt_phone}{end:} +
    {else:}{end:}FAX number:{else:}{end:} + + {if:fieldFail.fax}
    {fieldFail.fax}{end:} +
    {else:}{end:}E-Mail address:{else:}{end:} + + {if:fieldFail.email}
    {fieldFail.email}{end:} +
    {else:}{end:}Optional Log in ID:{else:}{end:} + +

    This field is optional. If a Log in ID is supplied, the user may log in either with their + E-Mail address or this Log in ID. This may be helpful for users with longer E-Mail addresses. + The password below will still be required to log in. Log in IDs are unique, so only one + contact may have a particular ID.

    + {if:fieldFail.login_id}
    {fieldFail.login_id}{end:} +
    {else:}{end:}Password:{else:}{end:} + + {if:fieldFail.password}
    {fieldFail.password:h}{end:} +
    + Passwords require at least 8 characters including at least one number, one letter, and one of the following characters.
    +    # . - _ , $ % & ! +
    {else:}{end:}Alternate E-Mail address:{else:}{end:} + + {if:fieldFail.alt_email}
    {fieldFail.alt_email}{end:} +
    {else:}{end:}User Permissions:{else:}{end:} + + {if:fieldFail.user_rights}
    {fieldFail.user_rights}{end:} +
    {else:}{end:}Notes:{else:}{end:} + + {if:fieldFail.notes}
    {fieldFail.notes}{end:} +
    +
    +
    + +
    + {if:addingNewContact} + + {end:} + {if:editingContact} + + {end:} +
    + +
    + + {else:} +

    No contact has been selected yet.

    +

    To edit a contact, first select it from the list of available contacts. + {end:} + +

    + +
    + + +
    + +{startScript:h} + + $(function() { + + /* + * Table operations + */ + + $('.contactEditTable').dataTable({ + "bPaginate": false, + "bLengthChange": false, + "bFilter": false, + "bSort": false, + "bInfo": false, + "bAutoWidth": false, + "bDestroy": true + }); + + /* + * AJAX form handling + */ + + $('#ContactForm').ajaxForm({ + success: function(data) { + {if:addingNewContact} + f_replaceContents(data, $('#Contact_detail_container')); + {end:} + {if:editingContact} + f_replaceContents(data, $('#Contact_detail_container')); + {end:} + return false; + } + }); + + // Block default form submission + $("form").submit(function (e) { + $('#contactFormSubmit').html('
    Submitting, Please Wait...
    '); + e.preventDefault(); + }); + + /* + * CKeditor actions + */ + + // Code to kick off CKEditor for specific fields +// f_buildCkeditor($("#notes")); + + // Remove the editors and store the data back in the textareas before the AJAX form submission + $('.emEditSubmit').click( function() { + f_removeCkeditor($("#notes")); + }); + + f_restartOnTabSelect(); + + }); + + \ No newline at end of file diff --git a/views/admin/tickets/Contact/list.html b/views/admin/tickets/Contact/list.html new file mode 100644 index 0000000..2e9c1bc --- /dev/null +++ b/views/admin/tickets/Contact/list.html @@ -0,0 +1,125 @@ + +
    + +
    +{if:checkPermission(#10#)} + +{end:} + +
    + + Search Contacts: (type any portion of a contact name) + + {if:contactList.contact_list} + +
    + + + + + + {foreach:contactList.contact_list,c} + + + + + + + + {end:} + +
    Last NameFirst NameOrganizationPhoneE-Mail
    {c.org}{c.office_phone}{c.email}
    +
    + + {else:} +

    No contacts are currently listed.

    +

    You should have at least one contact listed for each {term.prop.norm}.

    + {end:} + +
    +
    + + +
    +{startScript:h} + + // Contacts Search + var contactsSearchData = [ + {foreach:contactList.contact_list,c} + {label:'{c.lname:h}, {c.fname:h}', value:'{c.id}'}, + {end:} + ]; + + $(function() { + + var ContactListTable = $('#ContactListTable').dataTable({ + "sScrollY": "100px", + "scrollX": true, + "bScrollCollapse": true, + "bPaginate": false, + "bLengthChange": false, + "bFilter": false, + "bSort": true, + "bInfo": false, + "bAutoWidth": false, + "bDestroy": true + }); + $(window).resize(function(){ + ContactListTable.fnDraw(); + }); + + // Toggle length of table + var ContactListTableSmall = true; + var ContactListTableHeight = $('#ContactListTable_wrapper div.dataTables_scrollBody').height(); + $('#contactListSizeChange').click(function() { + if (ContactListTableSmall) { + $('#ContactListTable_wrapper div.dataTables_scrollBody').height('auto'); + ContactListTableSmall = false; + $(this).html('Smaller Table'); + ContactListTable.fnSettings().oScroll.sY = '100%'; + ContactListTable.fnDraw(); + } else { + $('#ContactListTable_wrapper div.dataTables_scrollBody').height(ContactListTableHeight); + ContactListTableSmall = true; + $(this).html('Larger Table'); + ContactListTable.fnSettings().oScroll.sY = '100px'; + ContactListTable.fnDraw(); + } + }); + + // Close all local sliders + $('#Contact_detail').hide(duration); + + $('.contactListSelect').click(function(){ + $('#ContactListTable_wrapper div.dataTables_scrollBody').height(ContactListTableHeight); + ContactListTableSmall = true; + $('#contactListSizeChange').html('Larger Table'); + ContactListTable.fnSettings().oScroll.sY = '100px'; + ContactListTable.fnDraw(); + f_loadAction('Contact_detail', 'Contact_detail_container', 'ContactID=' + $(this).attr('emContactId') + '&tabList={tabList}'); + }); + + // Search Contacts + $("#contactsSearch").autocomplete({ + source: contactsSearchData, + minLength: 1, + focus: function(event, ui) { + // Don't auto fill on focus + return false; + }, + select: function(event, ui) { + $("#contactsSearch").attr({value: ui.item.label}); + f_loadAction('Contact_detail', 'Contact_detail_container', 'ContactID=' + ui.item.value + '&tabList={tabList}'); + return false; + } + }); + + f_restartOnTabSelect(); + + }); + + diff --git a/views/admin/tickets/Debug/index.html b/views/admin/tickets/Debug/index.html new file mode 100644 index 0000000..c1c41c6 --- /dev/null +++ b/views/admin/tickets/Debug/index.html @@ -0,0 +1,62 @@ + + + + + + +
    Startup: {debugStartupTime}
    +
    Event Management Admin Debug
    +
    +
    + Updated: {debugUpdateTime} +
    +
    + {debugData:h} +
    +{appAdminURL} + + + + + {startScript:h} + + var reloadTimerHandle = false; + var reloadTime = 2000; + + // Reload the current window with Action = Debug_update + function reloadThisWindow() + { + window.location.assign("{appAdminURL}&Action=Debug_update"); + } + + // Sets debug reload timer to pick up new data in some period of time. - Called from emDebugWindowReloadRequest() in main .js file + function debugReloadRequest() + { + // Clear any pending reload request + if (reloadTimerHandle != false) { + window.clearTimeout(reloadTimerHandle); + } + + // Set timer to wait for additional actions before reloading debug page + reloadTimerHandle = window.setTimeout(reloadThisWindow, reloadTime); + + // Clear current debug data and display wait message + document.getElementById('debugBody').innerHTML = '
    Loading, waiting for possible additional requests...
    '; + } + + \ No newline at end of file diff --git a/views/admin/tickets/Debug/start.html b/views/admin/tickets/Debug/start.html new file mode 100644 index 0000000..20b8a62 --- /dev/null +++ b/views/admin/tickets/Debug/start.html @@ -0,0 +1,56 @@ + + + + + + +
    Startup: {debugStartupTime}
    +
    Event Management Admin Debug
    +
    +
    Debug Startup
    + + {startScript:h} + + var reloadTimerHandle = false; + var reloadTime = 4000; + + // Reload the current window with Action = Debug_update + function reloadThisWindow() + { + window.location.assign("?Action=Debug_update"); + } + + // Sets debug reload timer to pick up new data in some period of time. - Called from emDebugWindowReloadRequest() in main .js file + function debugReloadRequest() + { + // Clear any pending reload request + if (reloadTimerHandle != false) { + window.clearTimeout(reloadTimerHandle); + } + + // Set timer to wait for additional actions before reloading debug page + reloadTimerHandle = window.setTimeout(reloadThisWindow, reloadTime); + + // Clear current debug data and display wait message + document.getElementById('debugBody').innerHTML = '
    Loading, waiting for possible additional requests...
    '; + } + + + + + \ No newline at end of file diff --git a/views/admin/tickets/Entrance/delete.html b/views/admin/tickets/Entrance/delete.html new file mode 100644 index 0000000..2be67ae --- /dev/null +++ b/views/admin/tickets/Entrance/delete.html @@ -0,0 +1,55 @@ +
    + +
    Delete this {term.entrance.cap}
    + +
    {entranceDetail.name}
    + +{if:checkPermission(#10#)} +
    + + +
    +{end:} + + {if:entranceDetail} +
    + + + + + + + + + +
    Delete {term.entrance.cap}: +

    Clicking "Confirm Delete" on the right will permanently delete this {term.entrance.norm}.

    +
    Name:{entranceDetail.name}
    + {else:} +

    No {term.entrance.plur} found.

    + {end:} + +
    + +
    +{startScript:h} + $(document).ready(function(){ + + $('#EntranceDeleteTable').dataTable({ + "bPaginate": false, + "bLengthChange": false, + "bFilter": false, + "bSort": false, + "bInfo": false, + "bAutoWidth": false, + "bDestroy": true + }); + + f_restartOnTabSelect(); + + }); + diff --git a/views/admin/tickets/Entrance/detail.html b/views/admin/tickets/Entrance/detail.html new file mode 100644 index 0000000..d72db45 --- /dev/null +++ b/views/admin/tickets/Entrance/detail.html @@ -0,0 +1,104 @@ +
    + +
    {term.entrance.cap}: {entranceDetail.name}
    + +
    + + +
    + + {if:entranceDetail} +
    + + + + {if:entranceDetail.delete} + + + + + {end:} + + + + + + + + + + + + + + +
    Delete {term.entrance.cap}: + {if:entranceDetail.deleteConfirmed} + {if:entranceDetail.deleteFailure} +

    FAILED:

    + Sorry, we are unable to delete the entry at this time.
    + {entranceDetail.reason:h} + {else:} +

    Deleted

    + {end:} + {else:} +
    +

    Clicking the button above will permanently delete this {term.entrance.norm}.

    + {end:} +
    {term.entrance.cap} Name:{entranceDetail.name}
    Location: + {entranceDetail.addr1}
    + {if:entranceDetail.addr2}{entranceDetail.addr2}
    {end:} + {if:entranceDetail.city}{entranceDetail.city}{else:}(n/a){end:}, {entranceDetail.state.name} {entranceDetail.zip}
    + {if:entranceDetail.country.name}{entranceDetail.country.name}
    {end:} + + +
    (map loads here)
    +
    Phone:{entranceDetail.phone}
    Description:{entranceDetail.descr:h}
    Image: + {if:entranceDetail.image} + + {else:}(none){end:} +
    {term.voucher.cap} Color:  {entranceDetail.color.name}
    Sort Order:{entranceDetail.sort}
    + {else:} +

    No {term.entrance.plur} found.

    + {end:} + +
    + +
    +{startScript:h} + $(document).ready(function(){ + + $('#EntranceDetailTable').dataTable({ + "bPaginate": false, + "bLengthChange": false, + "bFilter": false, + "bSort": false, + "bInfo": false, + "bAutoWidth": false, + "bDestroy": true + }); + + // Code to kick off the geolocation-display feature + $("#locationMap").geolocate({ + lat: "#lat", + lng: "#lon", + mapOptions: { + disableDefaultUI: false, + mapTypeControl: true, + mapTypeId: "roadmap", + zoom: 16 + }, + markerOptions: { + draggable: false, + title: "This is your selected location" + } + }); + + f_restartOnTabSelect(); + + }); + diff --git a/views/admin/tickets/Entrance/edit.html b/views/admin/tickets/Entrance/edit.html new file mode 100644 index 0000000..36ca1ca --- /dev/null +++ b/views/admin/tickets/Entrance/edit.html @@ -0,0 +1,299 @@ +
    + +
    + {if:addingNewEntrance}Adding New {term.entrance.cap}{end:} + {if:editingEntrance}Editing {term.entrance.cap}{end:} +
    + +{if:checkPermission(#10#)} +
    + {if:addingNewEntrance} + + {else:} + + {end:} +
    +{end:} + +{if:formFail} +
    Not all fields were filled in correctly. Please try again.
    +{end:} + +
    + + {if:entranceDetail} + +

    Required fields in RED.

    + +
    + {if:addingNewEntrance} + + {else:} + + {end:} + + + + + +
    + + + + + {if:fieldRequired.name} + {if:fieldFail.name} + + + + + {if:fieldRequired.addr1} + {if:fieldFail.addr1} + + + {if:fieldRequired.addr2} + {if:fieldFail.addr2} + + + {if:fieldRequired.city} + {if:fieldFail.city} + + + {if:fieldRequired.state} + {if:fieldFail.state} + + + {if:fieldRequired.zip} + {if:fieldFail.zip} + + + {if:fieldRequired.country} + {if:fieldFail.country} + + + {if:fieldRequired.lat} + + + + {if:fieldRequired.phone} + {if:fieldFail.phone} + + + + + + {if:fieldRequired.descr} + {if:fieldFail.descr} + + + {if:fieldRequired.image} + {if:fieldFail.image} + + + {if:fieldRequired.color} + {if:fieldFail.color} + + + {if:fieldRequired.sort} + {if:fieldFail.sort} + + +
    {else:}{end:}{term.entrance.cap} Name:{else:}{end:} + + {if:fieldFail.name}
    {fieldFail.name}{end:} +
    {else:}{end:}Address:{else:}{end:} + + {if:fieldFail.addr1}
    {fieldFail.addr1}{end:} +
    {else:}{end:} {else:}{end:} + + {if:fieldFail.addr2}
    {fieldFail.addr2}{end:} +
    {else:}{end:}City:{else:}{end:} + + {if:fieldFail.city}
    {fieldFail.city}{end:} +
    {else:}{end:}State:{else:}{end:} + + {if:fieldFail.state}
    {fieldFail.state}{end:} +
    {else:}{end:}ZIP/Postal Code:{else:}{end:} + + {if:fieldFail.zip}
    {fieldFail.zip}{end:} +
    {else:}{end:}Country:{else:}{end:} + + {if:fieldFail.country}
    {fieldFail.country}{end:} +
    {else:}{end:}Location: +
    + + +
    +

    + This map will try to find the new location whenever you change the address entered above. +

    +
    (map loads here)
    +

    + MAP USE: Drag the pointer to the desired location for this {term.prop.norm}. + Use + and - buttons or the mouse wheel to zoom in or out. + Click and drag anywhere else on the map to move to another area. +

    +
    {else:}{end:}Main Phone #:{else:}{end:} + + {if:fieldFail.phone}

    {fieldFail.phone}

    {end:} +
    {else:}{end:}Description:{else:}{end:} + + {if:fieldFail.descr}
    {fieldFail.descr}{end:} +
    {else:}{end:}Image:{else:}{end:} + {if:entranceDetail.image} + +
    Delete this image: + {end:} + +
    Upload or replace the image: + {if:fieldFail.image}
    {fieldFail.image}{end:} +
    {else:}{end:}{term.voucher.cap} Color:{else:}{end:} + + {if:fieldFail.color}
    {fieldFail.color}{end:} +
    {else:}{end:}Output Order:{else:}{end:} + + {if:fieldFail.sort}
    {fieldFail.sort}{end:} +
    +
    + +
    + {if:addingNewEntrance} + + {end:} + {if:editingEntrance} + + {end:} +
    + +
    + + {else:} +

    No {term.entrance.norm} has been selected yet.

    +

    To edit a {term.entrance.norm}, first select it from the list of available {term.entrance.plur}. + {end:} + +

    + +
    + + +
    + +{startScript:h} + + $(function() { + + /* + * Table operations + */ + + $('.entranceEditTable').dataTable({ + "bPaginate": false, + "bLengthChange": false, + "bFilter": false, + "bSort": false, + "bInfo": false, + "bAutoWidth": false, + "bDestroy": true + }); + + /* + * AJAX form handling + */ + + $('#EntranceForm').ajaxForm({ + success: function(data) { + {if:addingNewEntrance} + f_replaceContents(data, $('#Member_info_container')); + {end:} + {if:editingEntrance} + f_replaceContents(data, $('#Member_info_container')); + {end:} + return false; + } + }); + + // Block default form submission + $("form").submit(function (e) { + $('#entranceFormSubmit').html('
    Submitting, Please Wait...
    '); + e.preventDefault(); + }); + + // Remove the editors and store the data back in the textareas before the AJAX form submission + $('.emEditSubmit').click( function() { + f_removeCkeditor($("#descr")); + }); + + /* + * CKeditor actions + */ + + // Code to kick off CKEditor for specific fields + f_buildCkeditor($("#descr")); + f_buildCkeditor($("#notes")); + + // Remove the editors and store the data back in the textareas before the AJAX form submission + $('.emEditSubmit').click( function() { + f_removeCkeditor($("#descr")); + }); + + /* + * Map operations + */ + + // Code to kick off the geolocation-edit feature + $("#locationMap").geolocate({ + lat: "#lat", + lng: "#lon", + address: [ + "#addr1", + "#city", + "#zip" + ], + mapOptions: { + disableDefaultUI: false, + mapTypeControl: true, + mapTypeId: "roadmap", + zoom: 16 + }, + markerOptions: { + title: "This is your selected location" + } + }); + + f_restartOnTabSelect(); + + }); + + \ No newline at end of file diff --git a/views/admin/tickets/Entrance/list.html b/views/admin/tickets/Entrance/list.html new file mode 100644 index 0000000..f3b8924 --- /dev/null +++ b/views/admin/tickets/Entrance/list.html @@ -0,0 +1,129 @@ + +
    + +
    + + +
    + + Search {term.entrance.plur_cap}: (type any portion of a {term.entrance.norm} name) + + {if:entranceList} + +
    + + + + + + {foreach:entranceList,c} + + + + + + {end:} + +
    Sort OrderName{term.voucher.cap} Color
    {c.sort}  {c.color.name}
    +
    + + {else:} +

    No {term.entrance.plur} listed.

    +

    + You do not need to have a {term.entrance.norm}. If you do decide to add {term.entrance.plur}, + you may associate specific ones with specific {term.section.plur} or {term.ticket.plur}. +

    + {end:} + +
    +
    + + +
    +{startScript:h} + + // Entrances Search + var entrancesSearchData = [ + {foreach:entranceList,c} + {label:'{c.name:h}', value:'{c.id}'}, + {end:} + ]; + + $(function() { + + var EntranceListTable = $('#EntranceListTable').dataTable({ + "sScrollY": "100px", + "scrollX": true, + "bScrollCollapse": true, + "bPaginate": false, + "bLengthChange": false, + "bFilter": false, + "bSort": true, + "bInfo": false, + "bAutoWidth": false, + "bDestroy": true, + "aoColumns" : [ + { sWidth: '80px' }, + null, + null + ] + }); + $(window).resize(function(){ + EntranceListTable.fnDraw(); + }); + + // Toggle length of table + var EntranceListTableSmall = true; + var EntranceListTableHeight = $('#EntranceListTable_wrapper div.dataTables_scrollBody').height(); + $('#entranceListSizeChange').click(function() { + if (EntranceListTableSmall) { + $('#EntranceListTable_wrapper div.dataTables_scrollBody').height('auto'); + EntranceListTableSmall = false; + $(this).html('Smaller Table'); + EntranceListTable.fnSettings().oScroll.sY = '100%'; + EntranceListTable.fnDraw(); + } else { + $('#EntranceListTable_wrapper div.dataTables_scrollBody').height(EntranceListTableHeight); + EntranceListTableSmall = true; + $(this).html('Larger Table'); + EntranceListTable.fnSettings().oScroll.sY = '100px'; + EntranceListTable.fnDraw(); + } + }); + + // Close all local sliders + $('#Entrance_detail_container').hide(duration); + + $('.entranceListSelect').click(function(){ + $('#EntranceListTable_wrapper div.dataTables_scrollBody').height(EntranceListTableHeight); + EntranceListTableSmall = true; + $('#entranceListSizeChange').html('Larger Table'); + EntranceListTable.fnSettings().oScroll.sY = '100px'; + EntranceListTable.fnDraw(); + f_loadAction('Entrance_detail', 'Entrance_detail_container', 'EntranceID=' + $(this).attr('emEntranceId') + '&tabList={tabList}'); + }); + + // Search Entrances + $("#entrancesSearch").autocomplete({ + source: entrancesSearchData, + minLength: 1, + focus: function(event, ui) { + // Don't auto fill on focus + return false; + }, + select: function(event, ui) { + $("#entrancesSearch").attr({value: ui.item.label}); + f_loadAction('Entrance_detail', 'Entrance_detail_container', 'EntranceID=' + ui.item.value + '&tabList={tabList}'); + return false; + } + }); + + f_restartOnTabSelect(); + + }); + + diff --git a/views/admin/tickets/Event/index.html b/views/admin/tickets/Event/index.html new file mode 100644 index 0000000..288c565 --- /dev/null +++ b/views/admin/tickets/Event/index.html @@ -0,0 +1,17 @@ +
    +
    +
    This is the {term.event.norm} area....
    +

    + some stuff goes here +

    +
    +
    + +{startScript:h} + + // jQuery Section + $(document).ready(function(){ + + }); + + \ No newline at end of file diff --git a/views/admin/tickets/Help/index.html b/views/admin/tickets/Help/index.html new file mode 100644 index 0000000..64ec5a2 --- /dev/null +++ b/views/admin/tickets/Help/index.html @@ -0,0 +1,43 @@ +
    +
    +
    Event Management System Help.
    +

    +

    Printable Help Documentation
    +

    +
    +
    + +
    +
    Packaging Quick Reference
    +
    +

    Location that only offers items contained in a package

    + + + + +
    Type: Other - neither vendor nor sales
    Active: Yes
    Payment: No payment setup is required
    +

    Categories that only contain times used in a package

    + + + + +
    Active: No
    Purchace by Admin Only: No
    Promote in Cart: No
    +

    Items that are only used in a package

    + + + + + + +
    Active: No
    Purchace by Admin Only: No
    Always show in cart: No
    Boarding Pass Type: Voucher/Ticket for Pickup - no Barcode
    NO ADDONS!
    +
    +
    + +{startScript:h} + + // jQuery Section + $(document).ready(function(){ + + }); + + \ No newline at end of file diff --git a/views/admin/tickets/Member/added.html b/views/admin/tickets/Member/added.html new file mode 100644 index 0000000..f877380 --- /dev/null +++ b/views/admin/tickets/Member/added.html @@ -0,0 +1,16 @@ +
    + +
    New {term.prop.cap} Added
    + +
    + +{startScript:h} + + $(function() { + f_loadAction('Member_list', 'Member_area', 'MembersListOption=all&tabList={tabList}'); + f_loadAction('Member_selected', 'Member_selected', 'member_id={memberDetail.id}&tabList={tabList}'); + + }); + + + diff --git a/views/admin/tickets/Member/delete.html b/views/admin/tickets/Member/delete.html new file mode 100644 index 0000000..e0c2ba9 --- /dev/null +++ b/views/admin/tickets/Member/delete.html @@ -0,0 +1,228 @@ +
    + +
    Delete this {term.prop.cap}
    + +{if:checkPermission(#10#)} +
    + +
    +{end:} + + {if:memberDetail} +
    + + + + + + + + {if:option.member_db_integrated} + + {end:} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {if:option.accommodations} + + + + + + + {end:} + + + + +
    Delete {term.prop.cap}: +

    +

    + WARNING: Deleting this {term.prop.norm} will remove all related data. + This will remove all history related to this {term.prop.norm} and will + remove all related data from reports. +

    +

    + You may want to simply mark this {term.prop.norm} as "inactive" by un-checking + the "Account Active" option in the {term.prop.norm} edit screen then delete the + {term.prop.norm} after all yearly reports have been produced. +

    +

    + If you are sure you want to continue, please enter exactly "Please Delete" in + the field below then click the "Confirm Delete" button. This action will not + be reversable! +

    +

    +

    + Delete Confirmation: + +
    +

    +

    +
    Name:{memberDetail.member_name}
    {term.prop.cap} Name:{memberDetail.name}
    {term.prop.cap} Type:{memberDetail.member_type.name}
    Location: + {memberDetail.addr1}
    + {if:memberDetail.addr2}{memberDetail.addr2}
    {end:} + {if:memberDetail.city}{memberDetail.city}{else:}(n/a){end:}, {memberDetail.state.name} {memberDetail.zip}
    + {if:memberDetail.country.name}{memberDetail.country.name}
    {end:} + + +
    (map loads here)
    +
    Phone:{memberDetail.phone}
    E-Mail Address:{memberDetail.email}
    Processing E-Mail Address:{memberDetail.proc_email}
    Secondary Processing E-Mail Address:{memberDetail.proc_email2}
    Send Notice of Each Customer Purchase:{memberDetail.checkout_notify.name}
    Description:{memberDetail.descr:h}
    Credit Cards Accepted: + {foreach:memberDetail.cards_accepted.names,s}{s}
    {end:} +
    Payment Gateway: + {memberDetail.payment_gateway.name}
    + + + + + + +
    {memberDetail.gateway_par1}
    {memberDetail.gateway_par2}
    {memberDetail.gateway_par3.name}
    {memberDetail.gateway_par4.name}
    {memberDetail.gateway_par5}
    +
    PayPal Payment Gateway: +

    PayPal Gateway Enabled: {memberDetail.paypal.name}

    + + + + +
    Client ID{memberDetail.paypal_client_id}
    Secret:{memberDetail.paypal_secret}
    Mode:{memberDetail.paypal_mode.name}
    +
    SSL Seal for Checkout Page: + + + +
    Head Script:{memberDetail.ssl_seal_head_script:h}
    Body Script:{memberDetail.ssl_seal_body_script:h}
    +
    Image:{memberDetail.image}
    Sections Map:{memberDetail.ticket_sec_map}
    Accept Special Requests:{memberDetail.ticket_spec_req.name}
    Check-In Time:{memberDetail.check_in.time}
    Check-Out Time:{memberDetail.check_out.time}
    Accommodation Amenities: + {if:memberDetail.amen_1.displayName}{if:memberDetail.amen_1.value}{memberDetail.amen_1.displayName}
    {end:}{end:} + {if:memberDetail.amen_2.displayName}{if:memberDetail.amen_2.value}{memberDetail.amen_2.displayName}
    {end:}{end:} + {if:memberDetail.amen_3.displayName}{if:memberDetail.amen_3.value}{memberDetail.amen_3.displayName}
    {end:}{end:} + {if:memberDetail.amen_4.displayName}{if:memberDetail.amen_4.value}{memberDetail.amen_4.displayName}
    {end:}{end:} + {if:memberDetail.amen_5.displayName}{if:memberDetail.amen_5.value}{memberDetail.amen_5.displayName}
    {end:}{end:} + {if:memberDetail.amen_6.displayName}{if:memberDetail.amen_6.value}{memberDetail.amen_6.displayName}
    {end:}{end:} + {if:memberDetail.amen_7.displayName}{if:memberDetail.amen_7.value}{memberDetail.amen_7.displayName}
    {end:}{end:} + {if:memberDetail.amen_8.displayName}{if:memberDetail.amen_8.value}{memberDetail.amen_8.displayName}
    {end:}{end:} + {if:memberDetail.amen_9.displayName}{if:memberDetail.amen_9.value}{memberDetail.amen_9.displayName}
    {end:}{end:} + {if:memberDetail.amen_10.displayName}{if:memberDetail.amen_10.value}{memberDetail.amen_10.displayName}
    {end:}{end:} +
    General Policies:{memberDetail.def_ticket_pol:h}
    Sort Order:{memberDetail.sort}
    Notes:{memberDetail.notes:h}
    +
    + {else:} + No member information available. + {end:} + +
    +{startScript:h} + + // jQuery Section + $(document).ready(function(){ + + $('#MemberDetailTable').dataTable({ + "bPaginate": false, + "bLengthChange": false, + "bFilter": false, + "bSort": false, + "bInfo": false, + "bAutoWidth": false, + "bDestroy": true + }); + + // Code to kick off the geolocation-edit feature + $("#locationMap").geolocate({ + lat: "#lat", + lng: "#lon", + mapOptions: { + disableDefaultUI: false, + mapTypeControl: true, + mapTypeId: "roadmap", + zoom: 16 + }, + markerOptions: { + draggable: false, + title: "This is your selected location" + } + }); + + // Determine which payment gateway is selected and set prompts and visible fields accordingly + // Authorize.net + var g = {memberDetail.payment_gateway.value}; + if (g == 1) { + $('#usePar1').show(duration); + $('#gatewayPar1Name').html('Login: '); + $('#usePar2').show(duration); + $('#gatewayPar2Name').html('Key: '); + $('#usePar3').show(duration); + $('#gatewayPar3Name').html('Mode: '); + $('#usePar4').show(duration); + $('#gatewayPar4Name').html('Merchant E-Mail Sent: '); + $('#usePar5').show(duration); + $('#gatewayPar5Name').html('Merchant E-Mail: '); + } + // Merchant Solutions + if (g == 2) { + $('#usePar1').show(duration); + $('#gatewayPar1Name').html('Account ID: '); + $('#usePar2').show(duration); + $('#gatewayPar2Name').html('Merchant Pin: '); + $('#usePar3').hide(duration); + $('#gatewayPar3Name').html(''); + $('#usePar4').hide(duration); + $('#gatewayPar4Name').html(''); + $('#usePar5').hide(duration); + $('#gatewayPar5Name').html(''); + } + // None selected + if (g == 0) { + $('#usePar1').hide(duration); + $('#usePar2').hide(duration); + $('#usePar3').hide(duration); + $('#usePar4').hide(duration); + $('#usePar5').hide(duration); + } + + // Check delete confirmation + $('#Member_confirmDelete').on('click', null, function() { + + // Check for proper confirmation string + var conf = $('#deleteConfirmationText').val(); + if (conf != 'Please Delete') { + alert('To confirm enter exactly "Please Delete" or click "Cancel Delete" to abort.'); + } else { + f_loadAction('Member_confirmDelete', 'Member_info_container', false); + } + return false; + }); + + f_restartOnTabSelect(); + + }); + + diff --git a/views/admin/tickets/Member/detail.html b/views/admin/tickets/Member/detail.html new file mode 100644 index 0000000..439f929 --- /dev/null +++ b/views/admin/tickets/Member/detail.html @@ -0,0 +1,411 @@ + +
    + +{if:memberNotFound} + + (member not found) + +{else:} + + {if:memberDeleted} +
    Member Deleted
    + {else:} +
    + {if:checkPermission(#0#)} + + {end:} + {if:checkPermission(#10#)} + + {end:} +
    + {end:} + +
    + {if:addingNewMember}Adding New {term.prop.cap}{end:} + {if:editingMember}Editing {term.prop.cap}{end:} +
    + +
    + + + + {if:option.member_db_integrated} + + {end:} + + + {if:checkPermission(#0#)} + + {end:} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {if:option.accommodations} + + + + + + + {end:} + + + + + + +
    Name:{memberDetail.member_name}
    {term.prop.cap} Name:{memberDetail.name:h}ID: {memberDetail.id}
    {term.prop.cap} Type:{memberDetail.member_type.name}
    Active:{memberDetail.active.name}
    Location: + {memberDetail.addr1}
    + {if:memberDetail.addr2}{memberDetail.addr2}
    {end:} + {if:memberDetail.city}{memberDetail.city}{else:}(n/a){end:}, {memberDetail.state.name} {memberDetail.zip}
    + {if:memberDetail.country.name}{memberDetail.country.name}
    {end:} + + +
    (map loads here)
    +
    Phone:{memberDetail.phone}
    E-Mail Address:{memberDetail.email}
    Processing E-Mail Address:{memberDetail.proc_email}
    Secondary Processing E-Mail Address:{memberDetail.proc_email2}
    Send Notice of Each Customer Purchase:{memberDetail.checkout_notify.name}
    Description:{memberDetail.descr:h}
    Credit Cards Accepted: + {foreach:memberDetail.cards_accepted.names,s}{s}
    {end:} +
    Credit Card Payment Gateway: +

    {memberDetail.payment_gateway.name}

    + + + + + + +
    {memberDetail.gateway_par1}
    {memberDetail.gateway_par2}
    {memberDetail.gateway_par3.name}
    {memberDetail.gateway_par4.name}
    {memberDetail.gateway_par5}
    +
    PayPal Payment Gateway: +

    PayPal Gateway Enabled: {memberDetail.paypal.name}

    + + + + +
    Client ID{memberDetail.paypal_client_id}
    Secret:{memberDetail.paypal_secret}
    Mode:{memberDetail.paypal_mode.name}
    +
    SSL Seal for Checkout Page: + + + +
    Head Script:{memberDetail.ssl_seal_head_script:h}
    Body Script:{memberDetail.ssl_seal_body_script:h}
    +
    Image: + {if:memberDetail.image} + + {fileServer.secure}{fileServer.owner_id}/{image_style.default}/{memberDetail.image} + {else:}(none){end:} +
    Parking Map: + {if:memberDetail.parking_map} + + {else:}(none){end:} +
    Sections Map: + {if:memberDetail.ticket_sec_map} + + {else:}(none){end:} +
    Accept Special Requests:{memberDetail.ticket_spec_req.name}
    {term.prop.cap} Scans For: + {if:haveMemberScansFor} +

    When scanning packages, this {term.prop.norm} also scans for the following {term.prop.plur}.

    + + + + + {foreach:memberScansFor,s} + + + + {end:} + +
    {term.prop.plur_cap}
    {s.scans_for_name}
    + {else:} + This {term.prop.norm} is not scanning package {term.ticket.plur} for other {term.prop.plur}. + {end:} +
    Check-In Time:{memberDetail.check_in.time}
    Check-Out Time:{memberDetail.check_out.time}
    Accommodation Amenities: + {if:memberDetail.amen_1.displayName}{if:memberDetail.amen_1.value}{memberDetail.amen_1.displayName}
    {end:}{end:} + {if:memberDetail.amen_2.displayName}{if:memberDetail.amen_2.value}{memberDetail.amen_2.displayName}
    {end:}{end:} + {if:memberDetail.amen_3.displayName}{if:memberDetail.amen_3.value}{memberDetail.amen_3.displayName}
    {end:}{end:} + {if:memberDetail.amen_4.displayName}{if:memberDetail.amen_4.value}{memberDetail.amen_4.displayName}
    {end:}{end:} + {if:memberDetail.amen_5.displayName}{if:memberDetail.amen_5.value}{memberDetail.amen_5.displayName}
    {end:}{end:} + {if:memberDetail.amen_6.displayName}{if:memberDetail.amen_6.value}{memberDetail.amen_6.displayName}
    {end:}{end:} + {if:memberDetail.amen_7.displayName}{if:memberDetail.amen_7.value}{memberDetail.amen_7.displayName}
    {end:}{end:} + {if:memberDetail.amen_8.displayName}{if:memberDetail.amen_8.value}{memberDetail.amen_8.displayName}
    {end:}{end:} + {if:memberDetail.amen_9.displayName}{if:memberDetail.amen_9.value}{memberDetail.amen_9.displayName}
    {end:}{end:} + {if:memberDetail.amen_10.displayName}{if:memberDetail.amen_10.value}{memberDetail.amen_10.displayName}
    {end:}{end:} +
    {term.ticket.cap} Sales Intro Text:{memberDetail.intro_text:h}
    {term.ticket.cap} Sales Checkout E-Mail Sent:{memberDetail.checkout_email:h}
    General Policies:{memberDetail.def_ticket_pol:h}
    Sort Order:{memberDetail.sort}
    Notes:{memberDetail.notes:h}
    +
    + +
    + + + + + +{end:} + diff --git a/views/admin/tickets/Member/detail.html.SAVE b/views/admin/tickets/Member/detail.html.SAVE new file mode 100644 index 0000000..2a413ae --- /dev/null +++ b/views/admin/tickets/Member/detail.html.SAVE @@ -0,0 +1,290 @@ +
    + +{if:memberNotFound} + + (member not found) + +{else:} + + {if:memberDeleted} +
    Member Deleted
    + {else:} +
    + {if:checkPermission(#0#)} + + {end:} + {if:checkPermission(#10#)} + + {end:} +
    + {end:} + +
    + {if:addingNewMember}Adding New {term.prop.cap}{end:} + {if:editingMember}Editing {term.prop.cap}{end:} +
    + +
    + + + + {if:option.member_db_integrated} + + {end:} + + + {if:checkPermission(#0#)} + + {end:} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {if:option.accommodations} + + + + + + + {end:} + + + + + + +
    Name:{memberDetail.member_name}
    {term.prop.cap} Name:{memberDetail.name:h}ID: {memberDetail.id}
    {term.prop.cap} Type:{memberDetail.member_type.name}
    Active:{memberDetail.active.name}
    Location: + {memberDetail.addr1}
    + {if:memberDetail.addr2}{memberDetail.addr2}
    {end:} + {if:memberDetail.city}{memberDetail.city}{else:}(n/a){end:}, {memberDetail.state.name} {memberDetail.zip}
    + {if:memberDetail.country.name}{memberDetail.country.name}
    {end:} + + +
    (map loads here)
    +
    Phone:{memberDetail.phone}
    E-Mail Address:{memberDetail.email}
    Processing E-Mail Address:{memberDetail.proc_email}
    Secondary Processing E-Mail Address:{memberDetail.proc_email2}
    Send Notice of Each Customer Purchase:{memberDetail.checkout_notify.name}
    Description:{memberDetail.descr:h}
    Credit Cards Accepted: + {foreach:memberDetail.cards_accepted.names,s}{s}
    {end:} +
    Credit Card Payment Gateway: +

    {memberDetail.payment_gateway.name}

    + + + + + + +
    {memberDetail.gateway_par1}
    {memberDetail.gateway_par2}
    {memberDetail.gateway_par3.name}
    {memberDetail.gateway_par4.name}
    {memberDetail.gateway_par5}
    +
    PayPal Payment Gateway: +

    PayPal Gateway Enabled: {memberDetail.paypal.name}

    + + + + +
    Client ID{memberDetail.paypal_client_id}
    Secret:{memberDetail.paypal_secret}
    Mode:{memberDetail.paypal_mode.name}
    +
    SSL Seal for Checkout Page: + + + +
    Head Script:{memberDetail.ssl_seal_head_script:h}
    Body Script:{memberDetail.ssl_seal_body_script:h}
    +
    Image: + {if:memberDetail.image} + + {fileServer.secure}{fileServer.owner_id}/{image_style.default}/{memberDetail.image} + {else:}(none){end:} +
    Parking Map: + {if:memberDetail.parking_map} + + {else:}(none){end:} +
    Sections Map: + {if:memberDetail.ticket_sec_map} + + {else:}(none){end:} +
    Accept Special Requests:{memberDetail.ticket_spec_req.name}
    {term.prop.cap} Scans For: + {if:haveMemberScansFor} +

    When scanning packages, this {term.prop.norm} also scans for the following {term.prop.plur}.

    + + + + + {foreach:memberScansFor,s} + + + + {end:} + +
    {term.prop.plur_cap}
    {s.scans_for_name}
    + {else:} + This {term.prop.norm} is not scanning package {term.ticket.plur} for other {term.prop.plur}. + {end:} +
    Check-In Time:{memberDetail.check_in.time}
    Check-Out Time:{memberDetail.check_out.time}
    Accommodation Amenities: + {if:memberDetail.amen_1.displayName}{if:memberDetail.amen_1.value}{memberDetail.amen_1.displayName}
    {end:}{end:} + {if:memberDetail.amen_2.displayName}{if:memberDetail.amen_2.value}{memberDetail.amen_2.displayName}
    {end:}{end:} + {if:memberDetail.amen_3.displayName}{if:memberDetail.amen_3.value}{memberDetail.amen_3.displayName}
    {end:}{end:} + {if:memberDetail.amen_4.displayName}{if:memberDetail.amen_4.value}{memberDetail.amen_4.displayName}
    {end:}{end:} + {if:memberDetail.amen_5.displayName}{if:memberDetail.amen_5.value}{memberDetail.amen_5.displayName}
    {end:}{end:} + {if:memberDetail.amen_6.displayName}{if:memberDetail.amen_6.value}{memberDetail.amen_6.displayName}
    {end:}{end:} + {if:memberDetail.amen_7.displayName}{if:memberDetail.amen_7.value}{memberDetail.amen_7.displayName}
    {end:}{end:} + {if:memberDetail.amen_8.displayName}{if:memberDetail.amen_8.value}{memberDetail.amen_8.displayName}
    {end:}{end:} + {if:memberDetail.amen_9.displayName}{if:memberDetail.amen_9.value}{memberDetail.amen_9.displayName}
    {end:}{end:} + {if:memberDetail.amen_10.displayName}{if:memberDetail.amen_10.value}{memberDetail.amen_10.displayName}
    {end:}{end:} +
    {term.ticket.cap} Sales Intro Text:{memberDetail.intro_text:h}
    {term.ticket.cap} Sales Checkout E-Mail Sent:{memberDetail.checkout_email:h}
    General Policies:{memberDetail.def_ticket_pol:h}
    Sort Order:{memberDetail.sort}
    Notes:{memberDetail.notes:h}
    +
    + +
    + + + + + +{end:} + diff --git a/views/admin/tickets/Member/edit.html b/views/admin/tickets/Member/edit.html new file mode 100644 index 0000000..fe78e85 --- /dev/null +++ b/views/admin/tickets/Member/edit.html @@ -0,0 +1,874 @@ +
    + +
    + {if:addingNewMember}Adding New {term.prop.cap}{end:} + {if:editingMember}Editing {term.prop.cap}{end:} +
    + +
    +{if:addingNewMember} + + +{if:formFail} +
    Please note:
    +
      +
    • Not all fields were filled in correctly. Please try again.
    • +
    +{end:} + +
    + {if:memberDetail} + +

    Required fields in RED.

    + +
    + {if:addingNewMember}{end:} + {if:editingMember}{end:} + + + + {if:checkPermission(#0#)} + {else:} + + {end:} + +
    + + + + {if:option.member_db_integrated} + + + + + {end:} + + {if:fieldRequired.name} + {if:fieldFail.name} + + {if:option.member_db_integrated} + {else:} + {if:checkPermission(#0#)} + + {if:fieldRequired.member_type} + {if:fieldFail.member_type} + + {else:} + + + + + {end:} + {if:checkPermission(#0#)} + + + + + {end:} + + {if:fieldRequired.addr1} + {if:fieldFail.addr1} + + + {if:fieldRequired.addr2} + {if:fieldFail.addr2} + + + {if:fieldRequired.city} + {if:fieldFail.city} + + + {if:fieldRequired.state} + {if:fieldFail.state} + + + {if:fieldRequired.zip} + {if:fieldFail.zip} + + + {if:fieldRequired.country} + {if:fieldFail.country} + + + {if:fieldRequired.lat} + + + {end:} + + {if:fieldRequired.phone} + {if:fieldFail.phone} + + + {if:fieldRequired.email} + {if:fieldFail.email} + + + {if:fieldRequired.proc_email} + {if:fieldFail.proc_email} + + + {if:fieldRequired.proc_email2} + {if:fieldFail.proc_email2} + + + + + + + {if:fieldRequired.descr} + {if:fieldFail.descr} + + + {if:fieldRequired.cards_accepted} + {if:fieldFail.cards_accepted} + + + {if:fieldRequired.payment_gateway} + {if:fieldFail.payment_gateway} + + + + + + + {if:fieldRequired.image} + {if:fieldFail.image} + + + {if:fieldRequired.parking_map} + {if:fieldFail.parking_map} + + + {if:fieldRequired.ticket_sec_map} + {if:fieldFail.ticket_sec_map} + + + + + + + + + + {if:option.accommodations} + + {if:fieldRequired.check_in} + {if:fieldFail.check_in} + + + {if:fieldRequired.check_out} + {if:fieldFail.check_out} + + {end:} + + {if:fieldRequired.intro_text} + {if:fieldFail.intro_text} + + + {if:fieldRequired.checkout_email} + {if:fieldFail.checkout_email} + + + {if:fieldRequired.def_ticket_pol} + {if:fieldFail.def_ticket_pol} + + + {if:fieldRequired.sort} + {if:fieldFail.sort} + + + {if:fieldRequired.notes} + {if:fieldFail.notes} + + {if:option.accommodations} + + + + + {end:} + +
    {term.prop.Cap} Name: + {if:addingNewMember} + + {else:} + {memberDetail.member_name:h} + {end:} +
    {else:}{end:}{term.prop.cap} Name:{else:}{end:} + {if:checkPermission(#0#)} + + {else:} + {memberDetail.name:h} + {end:} + {if:fieldFail.name}
    {fieldFail.name}{end:} +
    {else:}{end:}{term.prop.cap} Type:{else:}{end:} + + {if:fieldFail.member_type}
    {fieldFail.member_type}{end:} +
    {term.prop.cap} Type:{memberDetail.member_type.name}
    Account Active: + {if:memberDetail.active.value} + + {else:} + + {end:} +
    {else:}{end:}Address:{else:}{end:} + + {if:fieldFail.addr1}
    {fieldFail.addr1}{end:} +
    {else:}{end:} {else:}{end:} + + {if:fieldFail.addr2}
    {fieldFail.addr2}{end:} +
    {else:}{end:}City:{else:}{end:} + + {if:fieldFail.city}
    {fieldFail.city}{end:} +
    {else:}{end:}State:{else:}{end:} + + {if:fieldFail.state}
    {fieldFail.state}{end:} +
    {else:}{end:}ZIP/Postal Code:{else:}{end:} + + {if:fieldFail.zip}
    {fieldFail.zip}{end:} +
    {else:}{end:}Country:{else:}{end:} + + {if:fieldFail.country}
    {fieldFail.country}{end:} +
    {else:}{end:}Location: +
    + + +
    +

    + +

    +
    (map loads here)
    +

    + MAP USE: Drag the pointer to the desired location for this {term.prop.norm}. + Use + and - buttons or the mouse wheel to zoom in or out. + Click and drag anywhere else on the map to move to another area. +

    +
    {else:}{end:}Main Phone #:{else:}{end:} + + {if:fieldFail.phone}

    {fieldFail.phone}

    {end:} +
    {else:}{end:}E-Mail Address:{else:}{end:} + + {if:fieldFail.email}

    {fieldFail.email}

    {end:} +
    {else:}{end:}Processing E-Mail Address:{else:}{end:} + + {if:fieldFail.proc_email}

    {fieldFail.proc_email}

    {end:} +
    {else:}{end:}Secondary Processing E-Mail Address:{else:}{end:} + + {if:fieldFail.proc_email2}

    {fieldFail.email}

    {end:} +
    Send Notice of Each Customer Purchase: + {if:memberDetail.checkout_notify.value} + + {else:} + + {end:} +
    {else:}{end:}Description:{else:}{end:} + + {if:fieldFail.descr}
    {fieldFail.descr}{end:} +
    {else:}{end:}Credit Cards Accepted:{else:}{end:} + + {if:fieldFail.cards_accepted}
    {fieldFail.cards_accepted}{end:} +
    {else:}{end:}Credit Card Payment Gateway:{else:}{end:} +

    + +

    + {if:fieldFail.payment_gateway}
    {fieldFail.payment_gateway}{end:} +

    + + + + + + + + + + + +


    + +
    + {if:memberDetail.gateway_par4.value} + + {else:} + + {end:} + +

    +

    +
    + +
    PayPal Payment Gateway: + Enable PayPal Payment Gateway: + {if:memberDetail.paypal.value} + + {else:} + + {end:} +
    (PayPal payment option is currently unavailable - Please contact Gaslight Media if you require this option) +

    + + + + + + + +
    Client ID:
    Secret:
    Mode: + +
    +

    +
    {else:}{end:}Image:{else:}{end:} + {if:memberDetail.image} + +
    Delete this image: + {end:} + +
    Upload or replace the image: + {if:fieldFail.image}
    {fieldFail.image}{end:} +
    {else:}{end:}Parking Map:{else:}{end:} + {if:memberDetail.parking_map} + +
    Delete this image: + {end:} + +
    Upload or replace the image: + {if:fieldFail.parking_map}
    {fieldFail.parking_map}{end:} +
    {else:}{end:}Section Map:{else:}{end:} + {if:memberDetail.ticket_sec_map} + +
    Delete this image: + {end:} + +
    Upload or replace the image: + {if:fieldFail.ticket_sec_map}
    {fieldFail.ticket_sec_map}{end:} +
    Accept Ticket Special Requests: + {if:memberDetail.ticket_spec_req.value} + + {else:} + + {end:} +
    {term.prop.cap} Scans For: +
    +

    When scanning packages, this {term.prop.cap} also scans for the following {term.prop.plur}.

    +

    + + +

    + + + + + + {foreach:memberScansFor,y} + + + + + {end:} + +
    {term.prop.cap}
    {y.scans_for_name:h}
    +
    +
    {else:}{end:}Check-In Time:{else:}{end:} + + + + {if:fieldFail.check_in}

    {fieldFail.check_in}

    {end:} +
    {else:}{end:}Check-Out Time:{else:}{end:} + + + + {if:fieldFail.check_out}

    {fieldFail.check_out}

    {end:} +
    {else:}{end:}{term.ticket.cap} Sales Intro Text:{else:}{end:} + + {if:fieldFail.intro_text}
    {fieldFail.intro_text}{end:} +

    This text is displayed at the top of the page when customers first enter the ticket sales system for one of your {term.performance.plur}.

    +
    {else:}{end:}{term.ticket.cap} Sales Checkout E-Mail Sent:{else:}{end:} + + {if:fieldFail.checkout_email}
    {fieldFail.checkout_email}{end:} +

    This is the E-Mail message the system sends out to a customer when they complete a purchase for {term.performance.plur}. + You may use certain "tags" that will be replaced with relevant text. These begin with { and end with } characters. + the list of such terms you can use are below.

    +

    {first-name}, {last-name}, {address-line-1}, {address-line-2}, + {city}, {state}, {zip}, {country}, {{term.prop.norm}-text}

    +

    The {{term.performance.norm}-text} tag will insert any text in the "Text for Confirmation E-Mail:" fields of + any {term.performance.plur} selected by the customer. If the customer selected a particular {term.performance.norm} + multiple times, that text will only be used once.

    + +
    {else:}{end:}General Policies:{else:}{end:} + + {if:fieldFail.def_ticket_pol}
    {fieldFail.def_ticket_pol}{end:} +

    This field does not permit formatting because it is used on {term.voucher.plur}.

    +
    {else:}{end:}Output Order:{else:}{end:} + + {if:fieldFail.sort}
    {fieldFail.sort}{end:} +
    {else:}{end:}Notes:{else:}{end:} + + {if:fieldFail.notes}
    {fieldFail.notes}{end:} +
    Accommodation Amenities: +

    + These are pre-defined accommodation amenitities for this {term.prop.norm}. You may also add additional accommodation + amenities to this {term.prop.norm} using the "Amenities" sub-menu button. +

    + {if:memberDetail.amen_1.displayName}{if:memberDetail.amen_1.value}{else:}{end:}{memberDetail.amen_1.displayName}
    {end:} + {if:memberDetail.amen_2.displayName}{if:memberDetail.amen_2.value}{else:}{end:}{memberDetail.amen_2.displayName}
    {end:} + {if:memberDetail.amen_3.displayName}{if:memberDetail.amen_3.value}{else:}{end:}{memberDetail.amen_3.displayName}
    {end:} + {if:memberDetail.amen_4.displayName}{if:memberDetail.amen_4.value}{else:}{end:}{memberDetail.amen_4.displayName}
    {end:} + {if:memberDetail.amen_5.displayName}{if:memberDetail.amen_5.value}{else:}{end:}{memberDetail.amen_5.displayName}
    {end:} + {if:memberDetail.amen_6.displayName}{if:memberDetail.amen_6.value}{else:}{end:}{memberDetail.amen_6.displayName}
    {end:} + {if:memberDetail.amen_7.displayName}{if:memberDetail.amen_7.value}{else:}{end:}{memberDetail.amen_7.displayName}
    {end:} + {if:memberDetail.amen_8.displayName}{if:memberDetail.amen_8.value}{else:}{end:}{memberDetail.amen_8.displayName}
    {end:} + {if:memberDetail.amen_9.displayName}{if:memberDetail.amen_9.value}{else:}{end:}{memberDetail.amen_9.displayName}
    {end:} + {if:memberDetail.amen_10.displayName}{if:memberDetail.amen_10.value}{else:}{end:}{memberDetail.amen_10.displayName}
    {end:} +
    +
    + +
    + {if:addingNewMember} + + {end:} + {if:editingMember} + + {end:} +
    + +
    + + {else:} +

    No {term.prop.norm} has been selected yet.

    +

    To edit a {term.prop.norm}, first select it from the list of available {term.prop.plur}.

    + {end:} + +
    + +
    + +
    + + + + + \ No newline at end of file diff --git a/views/admin/tickets/Member/edit.html.SAVE b/views/admin/tickets/Member/edit.html.SAVE new file mode 100644 index 0000000..c92217d --- /dev/null +++ b/views/admin/tickets/Member/edit.html.SAVE @@ -0,0 +1,762 @@ +
    + +
    + {if:addingNewMember}Adding New {term.prop.cap}{end:} + {if:editingMember}Editing {term.prop.cap}{end:} +
    + +
    +{if:addingNewMember} + + +{if:formFail} +
    Please note:
    +
      +
    • Not all fields were filled in correctly. Please try again.
    • +
    +{end:} + +
    + {if:memberDetail} + +

    Required fields in RED.

    + +
    + {if:addingNewMember}{end:} + {if:editingMember}{end:} + + + + {if:checkPermission(#0#)} + {else:} + + {end:} + +
    + + + + {if:option.member_db_integrated} + + + + + {end:} + + {if:fieldRequired.name} + {if:fieldFail.name} + + {if:option.member_db_integrated} + {else:} + {if:checkPermission(#0#)} + + {if:fieldRequired.member_type} + {if:fieldFail.member_type} + + {else:} + + + + + {end:} + {if:checkPermission(#0#)} + + + + + {end:} + + {if:fieldRequired.addr1} + {if:fieldFail.addr1} + + + {if:fieldRequired.addr2} + {if:fieldFail.addr2} + + + {if:fieldRequired.city} + {if:fieldFail.city} + + + {if:fieldRequired.state} + {if:fieldFail.state} + + + {if:fieldRequired.zip} + {if:fieldFail.zip} + + + {if:fieldRequired.country} + {if:fieldFail.country} + + + {if:fieldRequired.lat} + + + {end:} + + {if:fieldRequired.phone} + {if:fieldFail.phone} + + + {if:fieldRequired.email} + {if:fieldFail.email} + + + {if:fieldRequired.proc_email} + {if:fieldFail.proc_email} + + + {if:fieldRequired.proc_email2} + {if:fieldFail.proc_email2} + + + + + + + {if:fieldRequired.descr} + {if:fieldFail.descr} + + + {if:fieldRequired.cards_accepted} + {if:fieldFail.cards_accepted} + + + {if:fieldRequired.payment_gateway} + {if:fieldFail.payment_gateway} + + + + + + + {if:fieldRequired.image} + {if:fieldFail.image} + + + {if:fieldRequired.parking_map} + {if:fieldFail.parking_map} + + + {if:fieldRequired.ticket_sec_map} + {if:fieldFail.ticket_sec_map} + + + + + + + + + + {if:option.accommodations} + + {if:fieldRequired.check_in} + {if:fieldFail.check_in} + + + {if:fieldRequired.check_out} + {if:fieldFail.check_out} + + {end:} + + {if:fieldRequired.intro_text} + {if:fieldFail.intro_text} + + + {if:fieldRequired.checkout_email} + {if:fieldFail.checkout_email} + + + {if:fieldRequired.def_ticket_pol} + {if:fieldFail.def_ticket_pol} + + + {if:fieldRequired.sort} + {if:fieldFail.sort} + + + {if:fieldRequired.notes} + {if:fieldFail.notes} + + {if:option.accommodations} + + + + + {end:} + +
    {term.prop.Cap} Name: + {if:addingNewMember} + + {else:} + {memberDetail.member_name:h} + {end:} +
    {else:}{end:}{term.prop.cap} Name:{else:}{end:} + {if:checkPermission(#0#)} + + {else:} + {memberDetail.name:h} + {end:} + {if:fieldFail.name}
    {fieldFail.name}{end:} +
    {else:}{end:}{term.prop.cap} Type:{else:}{end:} + + {if:fieldFail.member_type}
    {fieldFail.member_type}{end:} +
    {term.prop.cap} Type:{memberDetail.member_type.name}
    Account Active: + {if:memberDetail.active.value} + + {else:} + + {end:} +
    {else:}{end:}Address:{else:}{end:} + + {if:fieldFail.addr1}
    {fieldFail.addr1}{end:} +
    {else:}{end:} {else:}{end:} + + {if:fieldFail.addr2}
    {fieldFail.addr2}{end:} +
    {else:}{end:}City:{else:}{end:} + + {if:fieldFail.city}
    {fieldFail.city}{end:} +
    {else:}{end:}State:{else:}{end:} + + {if:fieldFail.state}
    {fieldFail.state}{end:} +
    {else:}{end:}ZIP/Postal Code:{else:}{end:} + + {if:fieldFail.zip}
    {fieldFail.zip}{end:} +
    {else:}{end:}Country:{else:}{end:} + + {if:fieldFail.country}
    {fieldFail.country}{end:} +
    {else:}{end:}Location: +
    + + +
    +

    + This map will try to find the new location whenever you change the address entered above. +

    +
    (map loads here)
    +

    + MAP USE: Drag the pointer to the desired location for this {term.prop.norm}. + Use + and - buttons or the mouse wheel to zoom in or out. + Click and drag anywhere else on the map to move to another area. +

    +
    {else:}{end:}Main Phone #:{else:}{end:} + + {if:fieldFail.phone}

    {fieldFail.phone}

    {end:} +
    {else:}{end:}E-Mail Address:{else:}{end:} + + {if:fieldFail.email}

    {fieldFail.email}

    {end:} +
    {else:}{end:}Processing E-Mail Address:{else:}{end:} + + {if:fieldFail.proc_email}

    {fieldFail.proc_email}

    {end:} +
    {else:}{end:}Secondary Processing E-Mail Address:{else:}{end:} + + {if:fieldFail.proc_email2}

    {fieldFail.email}

    {end:} +
    Send Notice of Each Customer Purchase: + {if:memberDetail.checkout_notify.value} + + {else:} + + {end:} +
    {else:}{end:}Description:{else:}{end:} + + {if:fieldFail.descr}
    {fieldFail.descr}{end:} +
    {else:}{end:}Credit Cards Accepted:{else:}{end:} + + {if:fieldFail.cards_accepted}
    {fieldFail.cards_accepted}{end:} +
    {else:}{end:}Credit Card Payment Gateway:{else:}{end:} +

    + +

    + {if:fieldFail.payment_gateway}
    {fieldFail.payment_gateway}{end:} +

    + + + + + + + + + + + +


    + +
    + {if:memberDetail.gateway_par4.value} + + {else:} + + {end:} + +

    +

    +
    + +
    PayPal Payment Gateway: + Enable PayPal Payment Gateway: + {if:memberDetail.paypal.value} + + {else:} + + {end:} +
    (PayPal payment option is currently unavailable - Please contact Gaslight Media if you require this option) +

    + + + + + + + +
    Client ID:
    Secret:
    Mode: + +
    +

    +
    {else:}{end:}Image:{else:}{end:} + {if:memberDetail.image} + +
    Delete this image: + {end:} + +
    Upload or replace the image: + {if:fieldFail.image}
    {fieldFail.image}{end:} +
    {else:}{end:}Parking Map:{else:}{end:} + {if:memberDetail.parking_map} + +
    Delete this image: + {end:} + +
    Upload or replace the image: + {if:fieldFail.parking_map}
    {fieldFail.parking_map}{end:} +
    {else:}{end:}Section Map:{else:}{end:} + {if:memberDetail.ticket_sec_map} + +
    Delete this image: + {end:} + +
    Upload or replace the image: + {if:fieldFail.ticket_sec_map}
    {fieldFail.ticket_sec_map}{end:} +
    Accept Ticket Special Requests: + {if:memberDetail.ticket_spec_req.value} + + {else:} + + {end:} +
    {term.prop.cap} Scans For: +
    +

    When scanning packages, this {term.prop.cap} also scans for the following {term.prop.plur}.

    +

    + + +

    + + + + + + {foreach:memberScansFor,y} + + + + + {end:} + +
    {term.prop.cap}
    {y.scans_for_name:h}
    +
    +
    {else:}{end:}Check-In Time:{else:}{end:} + + + + {if:fieldFail.check_in}

    {fieldFail.check_in}

    {end:} +
    {else:}{end:}Check-Out Time:{else:}{end:} + + + + {if:fieldFail.check_out}

    {fieldFail.check_out}

    {end:} +
    {else:}{end:}{term.ticket.cap} Sales Intro Text:{else:}{end:} + + {if:fieldFail.intro_text}
    {fieldFail.intro_text}{end:} +

    This text is displayed at the top of the page when customers first enter the ticket sales system for one of your {term.performance.plur}.

    +
    {else:}{end:}{term.ticket.cap} Sales Checkout E-Mail Sent:{else:}{end:} + + {if:fieldFail.checkout_email}
    {fieldFail.checkout_email}{end:} +

    This is the E-Mail message the system sends out to a customer when they complete a purchase for {term.performance.plur}. + You may use certain "tags" that will be replaced with relevant text. These begin with { and end with } characters. + the list of such terms you can use are below.

    +

    {first-name}, {last-name}, {address-line-1}, {address-line-2}, + {city}, {state}, {zip}, {country}, {{term.prop.norm}-text}

    +

    The {{term.performance.norm}-text} tag will insert any text in the "Text for Confirmation E-Mail:" fields of + any {term.performance.plur} selected by the customer. If the customer selected a particular {term.performance.norm} + multiple times, that text will only be used once.

    + +
    {else:}{end:}General Policies:{else:}{end:} + + {if:fieldFail.def_ticket_pol}
    {fieldFail.def_ticket_pol}{end:} +

    This field does not permit formatting because it is used on {term.voucher.plur}.

    +
    {else:}{end:}Output Order:{else:}{end:} + + {if:fieldFail.sort}
    {fieldFail.sort}{end:} +
    {else:}{end:}Notes:{else:}{end:} + + {if:fieldFail.notes}
    {fieldFail.notes}{end:} +
    Accommodation Amenities: +

    + These are pre-defined accommodation amenitities for this {term.prop.norm}. You may also add additional accommodation + amenities to this {term.prop.norm} using the "Amenities" sub-menu button. +

    + {if:memberDetail.amen_1.displayName}{if:memberDetail.amen_1.value}{else:}{end:}{memberDetail.amen_1.displayName}
    {end:} + {if:memberDetail.amen_2.displayName}{if:memberDetail.amen_2.value}{else:}{end:}{memberDetail.amen_2.displayName}
    {end:} + {if:memberDetail.amen_3.displayName}{if:memberDetail.amen_3.value}{else:}{end:}{memberDetail.amen_3.displayName}
    {end:} + {if:memberDetail.amen_4.displayName}{if:memberDetail.amen_4.value}{else:}{end:}{memberDetail.amen_4.displayName}
    {end:} + {if:memberDetail.amen_5.displayName}{if:memberDetail.amen_5.value}{else:}{end:}{memberDetail.amen_5.displayName}
    {end:} + {if:memberDetail.amen_6.displayName}{if:memberDetail.amen_6.value}{else:}{end:}{memberDetail.amen_6.displayName}
    {end:} + {if:memberDetail.amen_7.displayName}{if:memberDetail.amen_7.value}{else:}{end:}{memberDetail.amen_7.displayName}
    {end:} + {if:memberDetail.amen_8.displayName}{if:memberDetail.amen_8.value}{else:}{end:}{memberDetail.amen_8.displayName}
    {end:} + {if:memberDetail.amen_9.displayName}{if:memberDetail.amen_9.value}{else:}{end:}{memberDetail.amen_9.displayName}
    {end:} + {if:memberDetail.amen_10.displayName}{if:memberDetail.amen_10.value}{else:}{end:}{memberDetail.amen_10.displayName}
    {end:} +
    +
    + +
    + {if:addingNewMember} + + {end:} + {if:editingMember} + + {end:} +
    + +
    + + {else:} +

    No {term.prop.norm} has been selected yet.

    +

    To edit a {term.prop.norm}, first select it from the list of available {term.prop.plur}.

    + {end:} + +
    + +
    + +
    + + + + + \ No newline at end of file diff --git a/views/admin/tickets/Member/index.html b/views/admin/tickets/Member/index.html new file mode 100644 index 0000000..887b60f --- /dev/null +++ b/views/admin/tickets/Member/index.html @@ -0,0 +1,38 @@ + +
    + + +{if:checkPermission(#10#)} +
    + + +
    +{end:} + +
    +
    + +
    + + +{startScript:h} + + // jQuery Section + $(document).ready(function(){ + + $('#Member_selected').hide(duration); + + // Start with member stats loaded + f_loadAction('Member_stats', 'Member_container', 'tabList={tabList}'); + + f_restartOnTabSelect(); + + }); + + \ No newline at end of file diff --git a/views/admin/tickets/Member/list.html b/views/admin/tickets/Member/list.html new file mode 100644 index 0000000..def3c39 --- /dev/null +++ b/views/admin/tickets/Member/list.html @@ -0,0 +1,131 @@ + +
    + +
    + + +
    +{if:checkPermission(#0#)} + +{end:} + +
    + Search {term.prop.cap}: (type any portion of a {term.prop.norm} name) + + {if:membersList} +
    + + + + + + {foreach:membersList,m} + + + + + + + + {end:} + +
    SortNameTypeCityPhone
    {m.sort}
    +
    + {else:} +

    No {term.prop.plur} are currently listed.

    +

    You will need to add at least one to use this system.

    + {end:} + + +
    +
    + +
    + +
    + +{startScript:h} + + // Members Search + var membersSearchData = [ + {foreach:membersList,m} + {label:'{m.name:h}, {m.member_type.nameEsc:h}, {m.city:h}, {m.phone}', value:'{m.id}'}, + {end:} + ]; + + $(function() { + + var MemberListTable = $('#MemberListTable').dataTable({ + "sScrollY": "100px", + "scrollX": true, + "bScrollCollapse": true, + "bPaginate": false, + "bLengthChange": false, + "bFilter": false, + "bSort": true, + "bInfo": false, + "bAutoWidth": false, + "bDestroy": true + }); + $(window).resize(function(){ + MemberListTable.fnDraw(); + }); + + // Toggle length of table + var MemberListTableSmall = true; + var MemberListTableHeight = $('#MemberListTable_wrapper div.dataTables_scrollBody').height(); + $('#memberListSizeChange').click(function() { + if (MemberListTableSmall) { + $('#MemberListTable_wrapper div.dataTables_scrollBody').height('auto'); + MemberListTableSmall = false; + $(this).html('Smaller Table'); + MemberListTable.fnSettings().oScroll.sY = '100%'; + MemberListTable.fnDraw(); + } else { + $('#MemberListTable_wrapper div.dataTables_scrollBody').height(MemberListTableHeight); + MemberListTableSmall = true; + $(this).html('Larger Table'); + MemberListTable.fnSettings().oScroll.sY = '100px'; + MemberListTable.fnDraw(); + } + }); + + $('.memberListSelect').click(function(){ + $('#MemberListTable_wrapper div.dataTables_scrollBody').height(MemberListTableHeight); + MemberListTableSmall = true; + $('#memberListSizeChange').html('Larger Table'); + MemberListTable.fnSettings().oScroll.sY = '100px'; + MemberListTable.fnDraw(); + f_loadAction('Member_selected', 'Member_selected_container', 'MemberID=' + $(this).attr('emMembId') + '&tabList={tabList}'); + }); + + // Search Members + $("#membersSearch").autocomplete({ + source: membersSearchData, + minLength: 1, + focus: function(event, ui) { + // Don't auto fill on focus + return false; + }, + select: function(event, ui) { + $("#membersSearch").attr({value: ui.item.label}); + f_loadAction('Member_selected', 'Member_selected_container', 'MemberID=' + ui.item.value + '&tabList={tabList}'); + return false; + } + }); + + f_restartOnTabSelect(); + + {if:displayMember} + f_loadAction('Member_selected', 'Member_selected_container', 'MemberID={displayMember}&tabList={tabList}'); + {end:} + + }); + + diff --git a/views/admin/tickets/Member/redisplayList.html b/views/admin/tickets/Member/redisplayList.html new file mode 100644 index 0000000..fe83527 --- /dev/null +++ b/views/admin/tickets/Member/redisplayList.html @@ -0,0 +1,19 @@ +
    + Reloading... +
    + + + + + \ No newline at end of file diff --git a/views/admin/tickets/Member/selected.html b/views/admin/tickets/Member/selected.html new file mode 100644 index 0000000..a07f8e9 --- /dev/null +++ b/views/admin/tickets/Member/selected.html @@ -0,0 +1,139 @@ +
    + +
    +
    {term.prop.cap}: {memberDetail.name:h}
    + + +
    + + + +
    + + +{if:checkPermission(#10#)} +
    + + + {if:option.accommodations} + + {end:} + {if:option.tickets} + + + {if:blockTab.Performance_selected} + {else:} + {if:checkPermission(#0#)} + {if:noTab.performance}{else:} + + {end:} + {end:} + {end:} + {end:} +
    +{end:} + + +
    +
    + +
    + +
    + + +{startScript:h} + + // jQuery Section + $(document).ready(function(){ + + var x = $('#MemberSelectedStatsTable').dataTable({ + "sScrollY": "100px", + "bScrollCollapse": true, + "bPaginate": false, + "bLengthChange": false, + "bFilter": false, + "bSort": false, + "bInfo": false, + "bAutoWidth": false, + "bDestroy": true + }); + + // Close all local sliders + $('#Member_info_container').hide(duration); + + // Start with member detail loaded + f_loadAction('Member_detail', 'Member_info_container', "tabList={tabList}"); + + f_restartOnTabSelect(); + + }); + + diff --git a/views/admin/tickets/Member/stats.html b/views/admin/tickets/Member/stats.html new file mode 100644 index 0000000..c1e2634 --- /dev/null +++ b/views/admin/tickets/Member/stats.html @@ -0,0 +1,69 @@ +
    +
    +
    Statistics for all {term.prop.plur}
    +
    + + + + {if:option.events} + + {end:} + {if:option.accommodations} + + {end:} + {if:option.tickets} + + {end:} + +
    Total {term.prop.plur} in this system: {membersStats.all}
    {term.prop.plur_cap} with {term.unit.plur}: {membersStats.accom}
    {term.prop.plur_cap} with {term.ticket.plur}: {membersStats.ticket}
    +
    +
    + {if:membersStats.flag} +
    +
    Please note:
    +
      + {if:membersStats.all}{else:} +
    • No {term.prop.plur} are listed in this system.
    • + {end:} + {if:option.accommodations} + {if:membersStats.accom}{else:} +
    • No {term.prop.plur} have {term.unit.plur}.
    • + {end:} + {end:} + {if:option.tickets} + {if:membersStats.ticket}{else:} +
    • No {term.prop.plur} have {term.ticket.plur}.
    • + {end:} + {end:} + {if:option.events} + {if:membersStats.event}{else:} +
    • There are no {term.event.plur} associated with any {term.prop.plur}.
    • + {end:} + {end:} +
    +
    + {end:} + +
    + +{startScript:h} + + $(function() { + + $('#MemberStatsTable').dataTable({ + "sScrollY": "100px", + "bScrollCollapse": true, + "bPaginate": false, + "bLengthChange": false, + "bFilter": false, + "bSort": false, + "bInfo": false, + "bAutoWidth": false, + "bDestroy": true + }); + + f_restartOnTabSelect(); + + }); + + diff --git a/views/admin/tickets/Misc/blank.html b/views/admin/tickets/Misc/blank.html new file mode 100644 index 0000000..a3dcf0f --- /dev/null +++ b/views/admin/tickets/Misc/blank.html @@ -0,0 +1,2 @@ +
    +
    diff --git a/views/admin/tickets/Misc/configDetail.html b/views/admin/tickets/Misc/configDetail.html new file mode 100644 index 0000000..4e26267 --- /dev/null +++ b/views/admin/tickets/Misc/configDetail.html @@ -0,0 +1,81 @@ +
    + +
    + Miscellaneous System Configuration +
    + +
    + +
    + +
    + + + + + + + + + + + + + + + + + + + + + + + + + +
    Text for {term.performance.norm} selection page:{miscConfigDetail.intro_text:h}
    Text for {term.section.norm} selection page:{miscConfigDetail.section_text:h}
    Text for {term.ticket.norm} selection page:{miscConfigDetail.ticket_text:h}
    Text for cart page:{miscConfigDetail.cart_text:h}
    Text for checkout page:{miscConfigDetail.checkout_text:h}
    Text for checkout success page:{miscConfigDetail.success_text:h}
    Tracking script for checkout success page:
    {miscConfigDetail.tracking}
      
    Text prompts for
    optional checkout fields:
    + #1: {miscConfigDetail.opt_field_1_name}
    + #2: {miscConfigDetail.opt_field_2_name}
    + #3: {miscConfigDetail.opt_field_3_name}
    +  
    + (Blank fields are not included in the checkout page.) +
    Admin Checkout No Payment Info Reasons:{miscConfigDetail.no_payment_reasons:h}
    SSL Seal for Checkout Page: + + + +
    Head Script:{miscConfigDetail.ssl_seal_head_script}
    Body Script:{miscConfigDetail.ssl_seal_body_script}
    +
    Central Payment {term.prop.Cap}: + {if:miscConfigDetail.central_payment} + All payments will be processed through {miscConfigDetail.central_payment:h}. + {else:} + Payments will not be centrally processed. + {end:} +
    +
    + +
    +{startScript:h} + $(document).ready(function(){ + + $('#MiscConfigDetailTable').dataTable({ + "bPaginate": false, + "bLengthChange": false, + "bFilter": false, + "bSort": false, + "bInfo": false, + "bAutoWidth": false, + "bDestroy": true, + "aoColumns": [ + { "sWidth": "300px" }, + null + ] + + }); + + f_restartOnTabSelect(); + + }); + diff --git a/views/admin/tickets/Misc/configEdit.html b/views/admin/tickets/Misc/configEdit.html new file mode 100644 index 0000000..0731d8d --- /dev/null +++ b/views/admin/tickets/Misc/configEdit.html @@ -0,0 +1,222 @@ +
    + +
    + Miscellaneous System Configuration +
    + +
    + +
    + + + +
    + + + + + {if:fieldRequired.intro_text} + {if:fieldFail.intro_text} + + + {if:fieldRequired.section_text} + {if:fieldFail.section_text} + + + {if:fieldRequired.ticket_text} + {if:fieldFail.ticket_text} + + + {if:fieldRequired.cart_text} + {if:fieldFail.cart_text} + + + {if:fieldRequired.checkout_text} + {if:fieldFail.checkout_text} + + + {if:fieldRequired.success_text} + {if:fieldFail.success_text} + + + + + + + + + + + + + + + + + + + {if:fieldRequired.central_payment} + {if:fieldFail.central_payment} + + +
    {else:}{end:}Text for {term.performance.norm} selection page:{else:}{end:} + + {if:fieldFail.intro_text}
    {fieldFail.intro_text}{end:} +
    {else:}{end:}Text for {term.section.norm} selection page:{else:}{end:} + + {if:fieldFail.section_text}
    {fieldFail.section_text}{end:} +
    {else:}{end:}Text for {term.ticket.norm} selection page:{else:}{end:} + + {if:fieldFail.ticket_text}
    {fieldFail.ticket_text}{end:} +
    {else:}{end:}Text for cart page:{else:}{end:} + + {if:fieldFail.cart_text}
    {fieldFail.cart_text}{end:} +
    {else:}{end:}Text for checkout page:{else:}{end:} + + {if:fieldFail.checkout_text}
    {fieldFail.checkout_text}{end:} +
    {else:}{end:}Text for checkout success page:{else:}{end:} + + {if:fieldFail.success_text}
    {fieldFail.success_text}{end:} +
    Tracking script for checkout success page:
    Optional Checkout Fields: +

    + NOTE: Optional checkout fields below are not used if they are blank.
    + If a field name is provided, the user will be asked to provide input to a field with this name on the checkout page. +

    + + + {if:fieldRequired.opt_field_1_name} + {if:fieldFail.opt_field_1_name} + + + {if:fieldRequired.opt_field_2_name} + {if:fieldFail.opt_field_2_name} + + + {if:fieldRequired.opt_field_3_name} + {if:fieldFail.opt_field_3_name} + +
    {else:}{end:}Field #1 name:{else:}{end:} + + {if:fieldFail.opt_field_1_name}
    {fieldFail.opt_field_1_name}{end:} +
    {else:}{end:}Field #2 name:{else:}{end:} + + {if:fieldFail.opt_field_2_name}
    {fieldFail.opt_field_2_name}{end:} +
    {else:}{end:}Field #3 name:{else:}{end:} + + {if:fieldFail.opt_field_3_name}
    {fieldFail.opt_field_3_name}{end:} +
    +
    Admin Checkout No Payment Info Reasons: + +
    + Place one reason per line. Type in reasons! Do not paste text from some other source. +
    SSL Seal for Checkout Page: +

    + NOTE: SSL Seal scripts are normally entered into this form by Gaslight Media personel.
    + Please do not modify these fields unless directed to do so. +

    +

    Note also that URLs in these entries should all be "https" (SSL).

    + + + {if:fieldRequired.ssl_seal_head_script} + {if:fieldFail.ssl_seal_head_script} + + + {if:fieldRequired.ssl_seal_body_script} + {if:fieldFail.ssl_seal_body_script} + +
    {else:}{end:}Head Script:{else:}{end:} + + {if:fieldFail.ssl_seal_head_script}
    {fieldFail.ssl_seal_head_script}{end:} +
    {else:}{end:}Body Script:{else:}{end:} + + {if:fieldFail.ssl_seal_body_script}
    {fieldFail.ssl_seal_body_script}{end:} +
    +
    {else:}{end:}Central Payment {term.prop.Cap}:{else:}{end:} + All payments are processed though this {term.prop.norm}. + {if:fieldFail.central_payment}
    {fieldFail.central_payment}{end:} +
    + NOTE: Leave blank unless you want to force all payments to be processed through one selected {term.prop.norm}. + You may create a new {term.prop.norm} for this purpose that has no {term.performance.plur} and {term.ticket.plur} associated with it + to use strictly for payment processing. +
    +
    + +
    + +
    + +
    + +
    + +
    + +{startScript:h} + + $(function() { + + /* + * Table operations + */ + + $('#miscConfigTable').dataTable({ + "bPaginate": false, + "bLengthChange": false, + "bFilter": false, + "bSort": false, + "bInfo": false, + "bAutoWidth": false, + "bDestroy": true + }); + + /* + * CKeditor actions + */ + + // Code to kick off CKEditor for specific fields + f_buildCkeditor($("#intro_text")); + f_buildCkeditor($("#section_text")); + f_buildCkeditor($("#ticket_text")); + f_buildCkeditor($("#cart_text")); + f_buildCkeditor($("#checkout_text")); + f_buildCkeditor($("#success_text")); + + // Remove the editors and store the data back in the textareas before the AJAX form submission + $('.emEditSubmit').click( function() { + f_removeCkeditor($("#intro_text")); + f_removeCkeditor($("#section_text")); + f_removeCkeditor($("#ticket_text")); + f_removeCkeditor($("#cart_text")); + f_removeCkeditor($("#checkout_text")); + f_removeCkeditor($("#success_text")); + }); + + /* + * AJAX form handling + */ + + $('#miscConfigForm').ajaxForm({ + success: function(data) { + f_replaceContents(data, $('#Misc_container')); + return false; + } + }); + + // Block default form submission + $("#miscConfigForm").submit(function (e) { + $('#miscConfigFormSubmit').html('
    Submitting, Please Wait...
    '); + e.preventDefault(); + }); + + f_restartOnTabSelect(); + + }); + + + diff --git a/views/admin/tickets/Misc/index.html b/views/admin/tickets/Misc/index.html new file mode 100644 index 0000000..9f6374c --- /dev/null +++ b/views/admin/tickets/Misc/index.html @@ -0,0 +1,47 @@ +
    + +
    +
    Misc:
    +
    + +
    + + +{if:checkPermission(#0#)} +
    + + {if:customFeatures} + + {end:} +
    +{end:} + +
    +
    (select report tab above)
    +
    + +
    +
    + + +{startScript:h} + + // jQuery Section + $(document).ready(function(){ + + // Start with Upload page loaded + f_loadAction('Misc_configDetail', 'Misc_container', "tabList={tabList}"); + + f_restartOnTabSelect(); + + }); + + diff --git a/views/admin/tickets/Misc/upload.html b/views/admin/tickets/Misc/upload.html new file mode 100644 index 0000000..d1c47f6 --- /dev/null +++ b/views/admin/tickets/Misc/upload.html @@ -0,0 +1,191 @@ +
    + +
    + +
    + Files for customizing front-end appearance +
    + +
    + +{if:doingIndex} + {if:reason} +
    +
    We're sorry, we had a problem with your request:
    +
      + {foreach:reason,r}{Chuck} +
    • {r:h}
    • + {end:} +
    +
    + {end:} + {if:indexFileUploaded} +
    + * Index file uploaded successfully. + Please test to make sure your new file works correctly.
    + If not, click the "Restore Previous File" button. +
    + {end:} + {if:indexFileRestored} +
    + * Previous Index file restored. + Please test to make sure your new file works correctly.
    + If not, please try to locate a known good file to upload. +
    + {end:} +{end:} + +

    index.html: Last updated {indexTime}

    +
    + + +
    + + + + + + + + +
    Upload front-end ticket sales index file: + +
    +
    +

    + This file must include the "{GLM}" text where you would like the page + contents to be inserted. Anything else reasonable before or after that + is permitted. Please be sure to check your file to ensure that html container + tags match properly before uploading. +

    + +
    + + +
    + +
    + +
    + +
    + +{if:doingStylesheet} + {if:reason} +
    +
    We're sorry, we had a problem with your request:
    +
      + {foreach:reason,r}{Chuck} +
    • {r:h}
    • + {end:} +
    +
    + {end:} + {if:stylesheetFileUploaded} +
    + * Stylesheet file uploaded successfully.
    + Please test to make sure your new file works correctly. If not, click the "Restore Previous File" button. +
    + {end:} + {if:stylesheetFileRestored} +
    + * Previous Stylesheet file restored. + Please test to make sure your new file works correctly. If not, please try to locate a known good file to upload. +
    + {end:} +{end:} + +
    + +

    styles.css: Last updated {stylesTime}

    +
    + + +
    + + + + + + + + +
    Upload front-end ticket sales stylesheet: + +
    +
    + +
    + + +
    + +
    + +
    + + +
    + +{startScript:h} + + $(function() { + + /* + * Table operations + */ + + $('.uploadStylesheetTable').dataTable({ + "bPaginate": false, + "bLengthChange": false, + "bFilter": false, + "bSort": false, + "bInfo": false, + "bAutoWidth": false, + "bDestroy": true + }); + + $('.uploadIndexTable').dataTable({ + "bPaginate": false, + "bLengthChange": false, + "bFilter": false, + "bSort": false, + "bInfo": false, + "bAutoWidth": false, + "bDestroy": true + }); + + /* + * AJAX form handling + */ + + $('#uploadStylesheetForm').ajaxForm({ + success: function(data) { + f_replaceContents(data, $('#Misc_container')); + return false; + } + }); + + $('#uploadIndexForm').ajaxForm({ + success: function(data) { + f_replaceContents(data, $('#Misc_container')); + return false; + } + }); + + // Block default form submission + $("#uploadIndexForm").submit(function (e) { + $('#uploadIndexForm').html('
    Submitting, Please Wait...
    '); + e.preventDefault(); + }); + $("#uploadStylesheetForm").submit(function (e) { + $('#uploadStylesheetForm').html('
    Submitting, Please Wait...
    '); + e.preventDefault(); + }); + + f_restartOnTabSelect(); + + }); + + + diff --git a/views/admin/tickets/Order/detail.html b/views/admin/tickets/Order/detail.html new file mode 100644 index 0000000..b7e9c07 --- /dev/null +++ b/views/admin/tickets/Order/detail.html @@ -0,0 +1,135 @@ +
    + +
    {orderDetail.name}
    + +
    + + +
    + + {if:orderDetail} +
    + + + + {if:orderDetail.delete} + + + + + {end:} + + + + + + + + + + + + + + + + + + + + + + + +
    Delete {term.order.cap}: + {if:orderDetail.deleteConfirmed} + {if:orderDetail.deleteFailure} +

    FAILED:

    + Sorry, we are unable to delete the entry at this time.
    + {orderDetail.reason:h} + {else:} +

    Deleted

    + {end:} + {else:} + +
    + +
    + +

    Clicking this button will permanently delete this {term.order.norm}.

    + {end:} +
    {term.order.cap} #:{orderDetail.id}
    {term.order.cap} Date:{orderDetail.purchase_date.date}
    Name:{orderDetail.lname}, {orderDetail.fname}
    Address: + {orderDetail.addr1}{if:orderDetail.addr2}
    + {orderDetail.addr2}{end:}
    + {orderDetail.city}, {orderDetail.state.name} {orderDetail.zip}
    + {orderDetail.country.name} +
    Phone:{orderDetail.phone}
    E-Mail:{orderDetail.email}
    OK to Send Info:{orderDetail.email_ok.name}
    {term.prop.cap}:{orderDetail.member_name}
    Credit Card:{orderDetail.cctype}
    Name On Card:{orderDetail.ccname}
    Card Number:{orderDetail.ccnumber}
    Confirmation #:{orderDetail.ccconf}
    Total Charge:{orderDetail.charge_total}
    Special Needs:{orderDetail.special_needs:h}
    Notes:{orderDetail.notes:h}
    Print {term.voucher.cap_plur} +
    + +
    +
    +
    +
    + +
    +
    +
    +
    + {else:} +

    No {term.order.plur} found.

    + {end:} + +
    + +
    +{startScript:h} + $(document).ready(function(){ + + $('#OrderDetailTable').dataTable({ + "bPaginate": false, + "bLengthChange": false, + "bFilter": false, + "bSort": false, + "bInfo": false, + "bAutoWidth": false, + "bDestroy": true + }); + + // Print vouchers + $('.VoucherPrint').click(function(){ + // window.location.href = "{appAdminURL}&Action=Order_printVoucher&OrderID={orderDetail.id}"; + var voucherWindow = window.open('{appAdminURL}&Action=Order_printVoucher&OrderID={orderDetail.id}', + "voucherPrint", + "height=750,width=600,menubar=yes,toolbar=yes,alwaysRaised=yes,menu" + ); + voucherWindow.focus(); + voucherWindow.print(); + return false; + }); + + // Print Mobile vouchers + $('.VoucherPrintMobile').click(function(){ + // window.location.href = "{appAdminURL}&Action=Order_printVoucherMobile&OrderID={orderDetail.id}"; + var voucherWindow = window.open('{appAdminURL}&Action=Order_printVoucherMobile&OrderID={orderDetail.id}', + "voucherPrintMobile", + "height=750,width=600,menubar=yes,toolbar=yes,alwaysRaised=yes,menu" + ); + voucherWindow.focus(); + voucherWindow.print(); + return false; + }); + + f_restartOnTabSelect(); + + }); + diff --git a/views/admin/tickets/Order/edit.html b/views/admin/tickets/Order/edit.html new file mode 100644 index 0000000..01e0293 --- /dev/null +++ b/views/admin/tickets/Order/edit.html @@ -0,0 +1,243 @@ +
    + +
    + {if:addingNewOrder}Adding New {term.order.cap}{end:} + {if:editingOrder}Editing {term.order.cap}{end:} +
    + +
    + +
    + +{if:formFail} +
    Not all fields were filled in correctly. Please try again.
    +{end:} + +
    + + {if:orderDetail} + +

    Required fields in RED.

    + +
    + {if:addingNewOrder} + + {else:} + + {end:} + + + + + +
    + + + + + + + {if:fieldRequired.fname} + {if:fieldFail.fname} + + + {if:fieldRequired.lname} + {if:fieldFail.lname} + + + {if:fieldRequired.addr1} + {if:fieldFail.addr1} + + + {if:fieldRequired.addr2} + {if:fieldFail.addr2} + + + {if:fieldRequired.city} + {if:fieldFail.city} + + + {if:fieldRequired.state} + {if:fieldFail.state} + + + {if:fieldRequired.zip} + {if:fieldFail.zip} + + + {if:fieldRequired.country} + {if:fieldFail.country} + + + {if:fieldRequired.phone} + {if:fieldFail.phone} + + + {if:fieldRequired.email} + {if:fieldFail.email} + + + + + + + + + + + + + {if:fieldRequired.special_needs} + {if:fieldFail.special_needs} + + + {if:fieldRequired.notes} + {if:fieldFail.notes} + + +
    {term.order.cap} #:{orderDetail.id}
    {term.order.cap} Date:{orderDetail.purchase_date.date}
    {else:}{end:}First Name:{else:}{end:} +
    + {if:fieldFail.fname}
    {fieldFail.fname}{end:} +
    {else:}{end:}Last Name:{else:}{end:} +
    + {if:fieldFail.lname}
    {fieldFail.lname}{end:} +
    {else:}{end:}Address:{else:}{end:} +
    + {if:fieldFail.addr1}
    {fieldFail.addr1}{end:} +
    {else:}{end:} {else:}{end:} +
    + {if:fieldFail.addr2}
    {fieldFail.addr2}{end:} +
    {else:}{end:}City:{else:}{end:} +
    + {if:fieldFail.city}
    {fieldFail.city}{end:} +
    {else:}{end:}State:{else:}{end:} + + {if:fieldFail.state}
    {fieldFail.state}{end:} +
    {else:}{end:}ZIP/Postal Code:{else:}{end:} + + {if:fieldFail.zip}
    {fieldFail.zip}{end:} +
    {else:}{end:}Country:{else:}{end:} + + {if:fieldFail.country}
    {fieldFail.country}{end:} +
    {else:}{end:}Phone:{else:}{end:} + + {if:fieldFail.phone}
    {fieldFail.phone}{end:} +
    {else:}{end:}E-Mail Address:{else:}{end:} + + {if:fieldFail.email}

    {fieldFail.email}

    {end:} +
    OK to Send Info: + {if:orderDetail.email_ok.value} + + {else:} + + {end:} +
    Note that commercial E-Mail protocols require you to have positive confirmation from the addressee before you send them general E-mail or solicitations. +
    {term.prop.cap}:{orderDetail.member_name}
    Credit Card:{orderDetail.cctype}
    Name On Card:{orderDetail.ccname}
    Card Number:{orderDetail.ccnumber}
    Confirmation #:{orderDetail.ccconf}
    Total Charge:{orderDetail.charge_total}
    {else:}{end:}Special Needs:{else:}{end:} +
    + {if:fieldFail.special_needs}
    {fieldFail.special_needs}{end:} +
    {else:}{end:}Notes:{else:}{end:} +
    + {if:fieldFail.notes}
    {fieldFail.notes}{end:} +
    +
    + +
    + {if:addingNewOrder} + + {end:} + {if:editingOrder} + + {end:} +
    + +
    + + {else:} +

    No {term.order.norm} has been selected yet.

    +

    To edit a {term.order.norm}, first select it from the list of available {term.order.plur}. + {end:} + +

    + +
    + + +
    + +{startScript:h} + + $(function() { + + /* + * Table operations + */ + + $('.orderEditTable').dataTable({ + "bPaginate": false, + "bLengthChange": false, + "bFilter": false, + "bSort": false, + "bInfo": false, + "bAutoWidth": false, + "bDestroy": true + }); + + /* + * AJAX form handling + */ + + $('#orderForm').ajaxForm({ + success: function(data) { + {if:addingNewOrder} + f_replaceContents(data, $('#Order_info_container')); + {end:} + {if:editingOrder} + f_replaceContents(data, $('#Order_info_container')); + {end:} + return false; + } + }); + + // Block default form submission + $("form").submit(function (e) { + $('#orderFormSubmit').html('
    Submitting, Please Wait...
    '); + e.preventDefault(); + }); + + /* + * CKeditor actions + */ + + // Code to kick off CKEditor for specific fields + f_buildCkeditor($("#descr")); + + // Remove the editors and store the data back in the textareas before the AJAX form submission + $('.emEditSubmit').click( function() { + f_removeCkeditor($("#descr")); + }); + + f_restartOnTabSelect(); + + }); + + \ No newline at end of file diff --git a/views/admin/tickets/Order/list.html b/views/admin/tickets/Order/list.html new file mode 100644 index 0000000..98a9f22 --- /dev/null +++ b/views/admin/tickets/Order/list.html @@ -0,0 +1,132 @@ + +
    + +
    + +
    + + Search Orders: (start typing any data in list) + + {if:orderList} + +
    + + + + + + {foreach:orderList,c} + + + + + + + + + + + {end:} + +
    Order #Order DateLast NameFirst NameCityStateE-MailPhone
    {c.purchase_date.date}{c.city}{c.state.value}{c.email}{c.phone}
    +
    + + {else:} +

    No orders listed.

    + {end:} + +
    +
    + + +
    +{startScript:h} + + // Orders Search + var ordersSearchData = [ + {foreach:orderList,c} + {label:'{c.purchase_date.date} - {c.lname:h}, {c.fname:h} - {c.city}, {c.state.value} - {c.email}, {c.phone}', value:'{c.id}'}, + {end:} + ]; + + $(function() { + + var OrderListTable = $('#OrderListTable').dataTable({ + "sScrollY": "100px", + "scrollX": true, + "bScrollCollapse": true, + "bPaginate": false, + "bLengthChange": false, + "bFilter": false, + "bSort": true, + "bInfo": false, + "bAutoWidth": false, + "bDestroy": true, + "aoColumns" : [ + { "sType": "numeric" }, + null, + null, + null, + null, + null, + null, + null + ] + }); + $(window).resize(function(){ + OrderListTable.fnDraw(); + }); + + // Toggle length of table + var OrderListTableSmall = true; + var OrderListTableHeight = $('#OrderListTable_wrapper div.dataTables_scrollBody').height(); + $('#orderListSizeChange').click(function() { + if (OrderListTableSmall) { + $('#OrderListTable_wrapper div.dataTables_scrollBody').height('auto'); + OrderListTableSmall = false; + $(this).html('Smaller Table'); + OrderListTable.fnSettings().oScroll.sY = '100%'; + OrderListTable.fnDraw(); + } else { + $('#OrderListTable_wrapper div.dataTables_scrollBody').height(OrderListTableHeight); + OrderListTableSmall = true; + $(this).html('Larger Table'); + OrderListTable.fnSettings().oScroll.sY = '100px'; + OrderListTable.fnDraw(); + } + }); + + // Close all local sliders + $('#Order_detail').hide(duration); + + $('.orderListSelect').click(function(){ + $('#OrderListTable_wrapper div.dataTables_scrollBody').height(OrderListTableHeight); + OrderListTableSmall = true; + $(this).html('Larger Table'); + OrderListTable.fnSettings().oScroll.sY = '100px'; + OrderListTable.fnDraw(); + f_loadAction('Order_selected', 'Order_detail_container', 'OrderID=' + $(this).attr('emOrderId') + '&tabList={tabList}'); + }); + + // Search Orders + $("#ordersSearch").autocomplete({ + source: ordersSearchData, + minLength: 1, + focus: function(event, ui) { + // Don't auto fill on focus + return false; + }, + select: function(event, ui) { + $("#ordersSearch").attr({value: ui.item.label}); + f_loadAction('Order_selected', 'Order_detail_container', 'OrderID=' + ui.item.value + '&tabList={tabList}'); + return false; + } + }); + + f_restartOnTabSelect(); + + }); + + diff --git a/views/admin/tickets/Order/selected.html b/views/admin/tickets/Order/selected.html new file mode 100644 index 0000000..c80533b --- /dev/null +++ b/views/admin/tickets/Order/selected.html @@ -0,0 +1,45 @@ +
    + +
    +
    Order #: {orderDetail.id}
    +
    + +
    + + +{if:checkPermission(#20#)} +
    + + +
    +{end:} + +
    +
    + +
    + +
    + + +{startScript:h} + + // jQuery Section + $(document).ready(function(){ + + // Start with order detail loaded + f_loadAction('Order_detail', 'Order_info_container', "tabList={tabList}"); + + f_restartOnTabSelect(); + + }); + + diff --git a/views/admin/tickets/Performance/delete.html b/views/admin/tickets/Performance/delete.html new file mode 100644 index 0000000..1ed3468 --- /dev/null +++ b/views/admin/tickets/Performance/delete.html @@ -0,0 +1,63 @@ +
    + +
    Delete this {term.performance.cap}
    + +
    {performanceDetail.name}
    + +
    + + +
    + + {if:performanceDetail} +
    + + + + + + + + + + + + + + + + + + + +
    Delete {term.performace.cap}: +

    Clicking "Confirm Delete" on the right will permanently delete this {term.performance.norm}.

    +
    Name:{performanceDetail.name}
    Active:{performanceDetail.active.name}
    Purchase by Admin Only:{performanceDetail.admin_only.name}
    Start Date:{performanceDetail.start_date.date}
    End Date:{performanceDetail.end_date.date}
    Cuttoff Date:{performanceDetail.cutoff_date.date}
    Image:{performanceDetail.image}
    Policies:{performanceDetail.policies}
    Text for {term.voucher.cap}:{performanceDetail.voucher_text:h}
    Promote in Cart:{performanceDetail.promote_in_cart.name}
    Sort Order:{performanceDetail.sort}
    + {else:} +

    No {term.performance.plur} found.

    + {end:} + +
    + +
    +{startScript:h} + $(document).ready(function(){ + + $('#PerformanceDeleteTable').dataTable({ + "bPaginate": false, + "bLengthChange": false, + "bFilter": false, + "bSort": false, + "bInfo": false, + "bAutoWidth": false, + "bDestroy": true + }); + + f_restartOnTabSelect(); + + }); + diff --git a/views/admin/tickets/Performance/detail.html b/views/admin/tickets/Performance/detail.html new file mode 100644 index 0000000..50f378b --- /dev/null +++ b/views/admin/tickets/Performance/detail.html @@ -0,0 +1,100 @@ +
    + +
    + {if:addingNewPerformance}Adding New {term.performance.cap}{end:} + {if:editingPerformance}Editing {term.performance.cap}{end:} +
    + + + +
    + + +
    + + {if:performanceDetail} +
    + + + + {if:performanceDetail.delete} + + + + + {end:} + {if:checkPermission(#0#)} + + {end:} + + + + + + + + + + + + + + + + + + + + + + +
    Delete {term.performance.cap}: + {if:performanceDetail.deleteConfirmed} + {if:performanceDetail.deleteFailure} +

    FAILED:

    + Sorry, we are unable to delete the entry at this time.
    + {performanceDetail.reason:h} + {else:} +

    Deleted

    + {end:} + {else:} +
    +

    Clicking the button above will permanently delete this {term.performance.norm}.

    + {end:} +
    {term.prop.cap} Name:{performanceDetail.member_name:h}
    {term.performance.cap} Name:{performanceDetail.name:h}ID: {performanceDetail.id}
    Active:{performanceDetail.active.name}
    Purchase by Admin Only:{performanceDetail.admin_only.name}
    Description:{performanceDetail.descr:h}
    Short Description:{performanceDetail.short_descr:h}
    Start Date:{performanceDetail.start_date.date}
    End Date:{performanceDetail.end_date.date}
    Purchase Lead Time:{performanceDetail.purch_leadtime} hours
    Image: + {if:performanceDetail.image} + + {else:}(none){end:} +
    Policies:{performanceDetail.policy:h}
    Text for {term.voucher.cap}:{performanceDetail.voucher_text:h}
    Text for Confirmation E-Mail:{performanceDetail.conf_text:h}
    Promote in Cart:{performanceDetail.promote_in_cart.name}
    Sort Order:{performanceDetail.sort}
    Link to purchase: + + {frontEndSCRIPT}?Action=Shop_sectionSelect&PerformanceID={performanceDetail.id} + +
    + {else:} +

    No {term.performance.norm} found.

    + {end:} + +
    + +
    +{startScript:h} + $(document).ready(function(){ + + $('#PerformanceDetailTable').dataTable({ + "bPaginate": false, + "bLengthChange": false, + "bFilter": false, + "bSort": false, + "bInfo": false, + "bAutoWidth": false, + "bDestroy": true + }); + + f_restartOnTabSelect(); + + }); + diff --git a/views/admin/tickets/Performance/edit.html b/views/admin/tickets/Performance/edit.html new file mode 100644 index 0000000..5cfdb79 --- /dev/null +++ b/views/admin/tickets/Performance/edit.html @@ -0,0 +1,314 @@ +
    + +
    + {if:addingNewPerformance}Adding New {term.performance.cap}{end:} + {if:editingPerformance}Editing {term.performance.cap}{end:} +
    + +
    +{if:addingNewPerformance} + +{else:} + +{end:} +
    + +{if:formFail} +
    Not all fields were filled in correctly. Please try again.
    +{end:} + +
    + + {if:performanceDetail} + +

    Required fields in RED.

    + +
    + {if:addingNewPerformance} + + {else:} + + {end:} + + + + + {if:checkPermission(#0#)} + {else:} + + {end:} + +
    + + + + {if:checkPermission(#0#)} + + + + + {end:} + + {if:fieldRequired.name} + {if:fieldFail.name} + + + {if:fieldRequired.descr} + {if:fieldFail.descr} + + + {if:fieldRequired.short_descr} + {if:fieldFail.short_descr} + + + + + + + + + + + {if:fieldRequired.start_date} + {if:fieldFail.start_date} + + + {if:fieldRequired.end_date} + {if:fieldFail.end_date} + + + {if:fieldRequired.purch_leadtime} + {if:fieldFail.purch_leadtime} + + + {if:fieldRequired.image} + {if:fieldFail.image} + + + {if:fieldRequired.policy} + {if:fieldFail.policy} + + + {if:fieldRequired.voucher_text} + {if:fieldFail.voucher_test} + + + {if:fieldRequired.conf_text} + {if:fieldFail.conf_text} + + {if:checkPermission(#0#)} + + + + + {else:} + + {end:} + + {if:fieldRequired.sort} + {if:fieldFail.sort} + + +
    {term.prop.Cap} Name: + {if:addingNewPerformance} + + {else:} + {performanceDetail.member_name:h} + + {end:} +
    {else:}{end:}{term.performance.cap} Name:{else:}{end:} + + {if:fieldFail.name}
    {fieldFail.name}{end:} +
    {else:}{end:}Description:{else:}{end:} + + {if:fieldFail.descr}
    {fieldFail.descr}{end:} +
    {else:}{end:}Short Description:{else:}{end:} + + {if:fieldFail.short_descr}
    {fieldFail.short_descr}{end:} +
    Active: + {if:performanceDetail.active.value} + + {else:} + + {end:} +
    Purchase by Admin Only: + {if:performanceDetail.admin_only.value} + + {else:} + + {end:} +
    {else:}{end:}Start Date:{else:}{end:} + {if:addingNewPerformance} +
    + {else:} +
    + {end:} + This is a general start date. {term.ticket.cap} dates will determine when each {term.performance.norm} occurs. + {if:fieldFail.start_date}
    {fieldFail.start_date}{end:} +
    {else:}{end:}End Date:{else:}{end:} + {if:addingNewPerformance} +
    + {else:} +
    + {end:} + This is a general end date. {term.ticket.cap} dates will determine when each {term.performance.norm} occurs. + {if:fieldFail.end_date}
    {fieldFail.end_date}{end:} +
    {else:}{end:}Purchase Lead Time:{else:}{end:} + Hours
    + Person may not purchase {term.ticket.plur} if less than this number of hours before use. + {if:fieldFail.purch_leadtime}
    {fieldFail.purch_leadtime}{end:} +
    {else:}{end:}Image:{else:}{end:} + {if:performanceDetail.image} + +
    Delete this image: + {end:} + +
    Upload or replace the image: + {if:fieldFail.image}
    {fieldFail.image}{end:} +
    {else:}{end:}Policies:{else:}{end:} + + {if:fieldFail.policy}
    {fieldFail.policy}{end:} +
    {else:}{end:}Text for {term.voucher.cap}:{else:}{end:} +
    + Please be brief to conserve space on {term.voucher.plur}.
    + There is no formatting permitted for this field. + {if:fieldFail.voucher_text}
    {fieldFail.voucher_text}{end:} +
    {else:}{end:}Text for Confirmation E-Mail:{else:}{end:} + +

    This is text that will be included inside the confirmation E-Mail sent to the purchaser upon checkout. + It can be placed in the desired location by editing the checkout E-Mail for the related {term.prop.norm} + and inserting "{{term.prop.norm}-text}" at the desired location.

    +

    Note that there is one E-Mail message sent for a purchase at a particular {term.prop.norm} and that + each {term.performance.norm} that includes text in this field will contribute to the entire E-Mail. If + you add the same text to this field in multiple {term.performance.plur}, it will show up multiple times + in the confirmation E-Mail message. If there is text you would always like included, consider entering + it into the checkout E-Mail in the edit screen for the {term.prop.norm}.

    + {if:fieldFail.conf_text}
    {fieldFail.cont_text}{end:} +
    Promote in Cart: + {if:performanceDetail.promote_in_cart.value} + + {else:} + + {end:} +
    Promote in Cart:{performanceDetail.promote_in_cart.name}
    {else:}{end:}Output Order:{else:}{end:} + + {if:fieldFail.sort}
    {fieldFail.sort}{end:} +
    +
    + + +
    + {if:addingNewPerformance} + + {end:} + {if:editingPerformance} + + {end:} +
    + + +
    + + {else:} +

    No {term.performance.norm} has been selected yet.

    +

    To edit a {term.performance.norm}, first select it from the list of available {term.performance.plur}. + {end:} + +

    + +
    + + +
    + +{startScript:h} + + $(function() { + + /* + * Table operations + */ + + $('.performanceEditTable').dataTable({ + "bPaginate": false, + "bLengthChange": false, + "bFilter": false, + "bSort": false, + "bInfo": false, + "bAutoWidth": false, + "bDestroy": true + }); + + /* + * AJAX form handling + */ + + $('#PerformanceForm').ajaxForm({ + success: function(data) { + {if:addingNewPerformance} + f_replaceContents(data, $('#Performance_detail_container')); + {end:} + {if:editingPerformance} + f_replaceContents(data, $('#Performance_info_container')); + {end:} + return false; + } + }); + + // Block default form submission + $("form").submit(function (e) { + $('#performanceFormSubmit').html('
    Submitting, Please Wait...
    '); + e.preventDefault(); + }); + + /* + * CKeditor actions + */ + + // Code to kick off CKEditor for specific fields + f_buildCkeditor($("#descr")); + f_buildCkeditor($("#policy")); + f_buildCkeditor($("#conf_text")); + + // Remove the editors and store the data back in the textareas before the AJAX form submission + $('.emEditSubmit').click( function() { + f_removeCkeditor($("#descr")); + f_removeCkeditor($("#policy")); + f_removeCkeditor($("#conf_text")); + }); + + /* + * Date input operations + */ + + // Code to start datepicker for each date input + $("#startDateInput").datepicker({ + dateFormat: "mm/dd/yy", + minDate: '{performanceDetail.start_date.date_list.min}', + maxDate: '{performanceDetail.start_date.date_list.max}' + }); + $("#endDateInput").datepicker({ + dateFormat: "mm/dd/yy", + minDate: '{performanceDetail.end_date.date_list.min}', + maxDate: '{performanceDetail.end_date.date_list.max}' + }); + $("#cutoffDateInput").datepicker({ + dateFormat: "mm/dd/yy", + minDate: '{performanceDetail.cutoff_date.date_list.min}', + maxDate: '{performanceDetail.cutoff_date.date_list.max}' + }); + + f_restartOnTabSelect(); + + }); + + diff --git a/views/admin/tickets/Performance/list.html b/views/admin/tickets/Performance/list.html new file mode 100644 index 0000000..4984341 --- /dev/null +++ b/views/admin/tickets/Performance/list.html @@ -0,0 +1,144 @@ + +
    + +
    + + +
    + + Search {term.performance.plur_cap}: (type any portion of a {term.performance.norm} name) + + {if:performanceList} + +
    + + + + + + {foreach:performanceList,c} + + + + + + + + + {end:} + +
    Sort OrderNameActiveAdmin Only{term.prop.cap}Promote in Cart
    {c.sort}{c.promote_in_cart.name}
    +
    + + {else:} +

    No {term.performance.plur} listed.

    +

    + You need to have at least one {term.performance.norm} in order to sell {term.ticket.plur}. + If you have a {term.prop.norm} that sells {term.ticket.plur} through other {term.prop.plur}, + then that {term.prop.norm} will need at least one {term.performance.norm}. If you're doing that, + the {term.prop.norm} that will be selling those {term.ticket.plur} does not need a + {term.performance.norm} unless it will be selling its own. +

    + {end:} + +
    + +
    + +
    +{startScript:h} + + // Performances Search + var performancesSearchData = [ + {foreach:performanceList,c} + {label:'{c.name:h}', value:'{c.id}'}, + {end:} + ]; + + $(function() { + + var PerformanceListTable = $('#PerformanceListTable').dataTable({ + "sScrollY": "100px", + "scrollX": true, + "bScrollCollapse": true, + "bPaginate": false, + "bLengthChange": false, + "bFilter": false, + "bSort": true, + "bInfo": false, + "bAutoWidth": false, + "bDestroy": true, + "aoColumns" : [ + { sWidth: '80px', "sType": "numeric" }, + null, + null, + null, + null, + null + ] + }); + + $(window).resize(function(){ + PerformanceListTable.fnDraw(); + }); + + // Toggle length of table + var PerformanceListTableSmall = true; + var PerformanceListTableHeight = $('#PerformanceListTable_wrapper div.dataTables_scrollBody').height(); + $('#PerformanceListSizeChange').click(function() { + if (PerformanceListTableSmall) { + $('#PerformanceListTable_wrapper div.dataTables_scrollBody').height('auto'); + PerformanceListTableSmall = false; + $(this).html('Smaller Table'); + PerformanceListTable.fnSettings().oScroll.sY = '100%'; + PerformanceListTable.fnDraw(); + } else { + $('#PerformanceListTable_wrapper div.dataTables_scrollBody').height(PerformanceListTableHeight); + PerformanceListTableSmall = true; + $(this).html('Larger Table'); + PerformanceListTable.fnSettings().oScroll.sY = '100px'; + PerformanceListTable.fnDraw(); + } + }); + + // Close all local sliders + $('#Performance_detail_container').hide(duration); + + $('.performanceListSelect').click(function(){ + $('#PerformanceListTable_wrapper div.dataTables_scrollBody').height(PerformanceListTableHeight); + PerformanceListTableSmall = true; + $('#PerformanceListSizeChange').html('Larger Table'); + PerformanceListTable.fnSettings().oScroll.sY = '100px'; + PerformanceListTable.fnDraw(); + f_loadAction('Performance_selected', 'Performance_detail_container', 'PerformanceID=' + $(this).attr('emPerformanceId') + '&tabList={tabList}'); + $('#Performance_info').removeClass('emContentAreaHidden'); + }); + + // Search Performances + $("#performancesSearch").autocomplete({ + source: performancesSearchData, + minLength: 1, + focus: function(event, ui) { + // Don't auto fill on focus + return false; + }, + select: function(event, ui) { + $("#performancesSearch").attr({value: ui.item.label}); + f_loadAction('Performance_selected', 'Performance_detail_container', 'PerformanceID=' + ui.item.value + '&tabList={tabList}'); + return false; + } + }); + + f_restartOnTabSelect(); + + {if:displayPerformance} + f_loadAction('Performance_selected', 'Performance_detail_container', 'PerformanceID=' + {displayPerformance} + '&tabList={tabList}'); + {end:} + + }); + + diff --git a/views/admin/tickets/Performance/redisplayList.html b/views/admin/tickets/Performance/redisplayList.html new file mode 100644 index 0000000..b77cfda --- /dev/null +++ b/views/admin/tickets/Performance/redisplayList.html @@ -0,0 +1,18 @@ +
    + Reloading... +
    + + + + + \ No newline at end of file diff --git a/views/admin/tickets/Performance/selected.html b/views/admin/tickets/Performance/selected.html new file mode 100644 index 0000000..24fa389 --- /dev/null +++ b/views/admin/tickets/Performance/selected.html @@ -0,0 +1,53 @@ +
    + +
    +
    {term.performance.cap}: {performanceDetail.name:h}
    +
    + +
    + + +{if:checkPermission(#20#)} +
    + + {if:checkPermission(#0#)} + + {end:} + + +
    +{end:} + +
    +
    + +
    + +
    + + +{startScript:h} + + // jQuery Section + $(document).ready(function(){ + + // Start with performance detail loaded + f_loadAction('Performance_detail', 'Performance_info_container', "tabList={tabList}"); + + f_restartOnTabSelect(); + + }); + + diff --git a/views/admin/tickets/Performance/summary.html b/views/admin/tickets/Performance/summary.html new file mode 100644 index 0000000..fc30f69 --- /dev/null +++ b/views/admin/tickets/Performance/summary.html @@ -0,0 +1,113 @@ + +
    + +
    + Select Year to Display: +
    + + {if:performanceSummary} + +
    + + + + + + + + + + + + + + + + {foreach:performanceSummary,a} + {if:a.active} + + {else:} + + {end:} + + + + + + + + {if:a.held} + + {else:} + + {end:} + + + {end:} + +
    DateTimeSectionTicketQuantSoldAvailableHeldNet Available
    {a.date}{a.time}{a.section}{a.name} + {if:a.active} + {else:} + (inactive) + {end:} + {if:a.unlimited_quant}(unlim){else:}{a.quant}{end:}{a.sold}{if:a.unlimited_quant}(unlim){else:}{a.avail}{end:}{a.held}{a.netAvail}
    +
    + +

    Grayed-out entries are currently set to inactive.

    + + {else:} +

    No {term.performance.plur} listed.

    + {end:} + +
    +{startScript:h} + + $(function() { + + var PerformanceSummaryTable = $('#PerformanceSummaryTable').dataTable({ +// "sScrollY": "500px", + "bScrollCollapse": true, + "bPaginate": false, + "bLengthChange": false, + "bFilter": false, + "bSort": false, + "bInfo": false, + "bAutoWidth": false, + "bDestroy": true, + "aoColumns" : [ + { sWidth: '120px' }, + null, + null, + null, + null, + null, + null, + null, + null + ] + }); + $(window).resize(function(){ + PerformanceSummaryTable.fnDraw(); + }); + + $('#inventoryYearSelector').on('change', null, function() { + inventoryYear = $('#inventoryYearSelector').val(); + f_loadAction('Performance_summary', 'Performance_info_container', 'inventoryYear='+inventoryYear); + }); + + + + + f_restartOnTabSelect(); + + }); + + diff --git a/views/admin/tickets/Promo/delete.html b/views/admin/tickets/Promo/delete.html new file mode 100644 index 0000000..6bd1061 --- /dev/null +++ b/views/admin/tickets/Promo/delete.html @@ -0,0 +1,57 @@ +
    + +
    Delete this {term.promo.cap}
    + +
    {PromoDetail.name}
    + +
    + + +
    + + {if:promoDetail} +
    + + + + + + + + + + + + + +
    Delete {term.promo.cap}: +

    Clicking "Confirm Delete" on the right will permanently delete this {term.ticket.norm} add-on.

    +
    {term.promo.cap}:{promoDetail.name}ID: {promoDetail.id}
    Description:{promoDetail.descr:h}
    Start Date:{promoDetail.start_date.date}
    End Date:{promoDetail.end_date.date}
    Notes:{promoDetail.notes:h}
    + {else:} +

    No {term.promo.plur} found.

    + {end:} + +
    + +
    +{startScript:h} + $(document).ready(function(){ + + $('#PromoDeleteTable').dataTable({ + "bPaginate": false, + "bLengthChange": false, + "bFilter": false, + "bSort": false, + "bInfo": false, + "bAutoWidth": false, + "bDestroy": true + }); + + f_restartOnTabSelect(); + + }); + diff --git a/views/admin/tickets/Promo/detail.html b/views/admin/tickets/Promo/detail.html new file mode 100644 index 0000000..4d1ed29 --- /dev/null +++ b/views/admin/tickets/Promo/detail.html @@ -0,0 +1,168 @@ +
    + + + +
    + + +
    + + {if:promoDetail} +
    + + + + {if:promoDetail.delete} + + + + + {end:} + + + + + + + +
    Delete {term.promo.cap}: + {if:promoDetail.deleteConfirmed} + {if:promoDetail.deleteFailure} +

    FAILED:

    + Sorry, we are unable to delete the entry at this time.
    + {promoDetail.reason:h} + {else:} +

    Deleted

    + {end:} + {else:} +
    +

    Clicking the button above will permanently delete this {term.promo.norm}.

    + {end:} +
    {term.promo.cap}:{promoDetail.name}ID: {promoDetail.id}
    {term.promo.cap} Long Name:{promoDetail.long_name:h}
    Description:{promoDetail.descr:h}
    Start Date:{promoDetail.start_date.date}
    End Date:{promoDetail.end_date.date}
    Notes:{promoDetail.notes:h}
    +
    + + + +
    {term.promo.cap} {term.ticket.plur_cap} +
    + +
    + + + + + + + {foreach:promoTicketsList,p} + + + + + + + + + + {end:} + + + + + + + + + + + + + + + + + + + + +
    Delete{term.ticket.cap} NameType$ or %# Sold$ CreditNotes
    {p.ticket_name}{p.promo_type.name}{p.numberSold}{p.dollarsSold}
    + + + + + +   
       Totals{numberTotal}{dollarsTotal} 
    + +
    + {else:} +

    No {term.promo.plur} found.

    + {end:} + + +
    +{startScript:h} + $(document).ready(function(){ + + $('#PromoDetailTable').dataTable({ + "bPaginate": false, + "bLengthChange": false, + "bFilter": false, + "bSort": false, + "bInfo": false, + "bAutoWidth": false, + "bDestroy": true + }); + $('#PromoTicketTable').dataTable({ + "bPaginate": false, + "bLengthChange": false, + "bFilter": false, + "bSort": false, + "bInfo": false, + "bAutoWidth": false, + "bDestroy": true, + "aoColumns" : [ + { sWidth: '40px', "sType": "numeric" }, + null, + null, + null, + null, + null, + null + ] + }); + + f_restartOnTabSelect(); + + /* + * AJAX form handling + */ + + $('#promoTicketForm').ajaxForm({ + success: function(data) { + var container = $('#Promo_detail_container'); + f_replaceContents(data, container); + return false; + } + }); + + // Block default form submission + $("form").submit(function (e) { + $('.promoTicketFormSubmit').html('
    Submitting, Please Wait...
    '); + e.preventDefault(); + }); + + + }); + diff --git a/views/admin/tickets/Promo/edit.html b/views/admin/tickets/Promo/edit.html new file mode 100644 index 0000000..614125b --- /dev/null +++ b/views/admin/tickets/Promo/edit.html @@ -0,0 +1,207 @@ +
    + +
    + {if:addingNewPromo}Adding New {term.promo.cap}{end:} + {if:editingPromo}Editing {term.promo.cap}{end:} +
    + +
    +{if:addingNewPromo} + +{else:} + +{end:} +
    + +{if:formFail} +
    Not all fields were filled in correctly. Please try again.
    +{end:} + +
    + + {if:promoDetail} + +

    Required fields in RED.

    + +
    + {if:addingNewPromo} + + {else:} + + {end:} + + + + + +
    + + + + + {if:fieldRequired.name} + {if:fieldFail.name} + + + {if:fieldRequired.long_name} + {if:fieldFail.long_name} + + + {if:fieldRequired.descr} + {if:fieldFail.descr} + + + {if:fieldRequired.start_date} + {if:fieldFail.start_date} + + + {if:fieldRequired.end_date} + {if:fieldFail.end_date} + + +
    {else:}{end:}{term.promo.cap}:{else:}{end:} +
    + {if:fieldFail.name}
    {fieldFail.name}{end:} +
    {else:}{end:}{term.promo.cap} Long Name:{else:}{end:} +
    + For internal reference. + {if:fieldFail.long_name}
    {fieldFail.long_name}{end:} +
    {else:}{end:}Description:{else:}{end:} + + {if:fieldFail.descr}
    {fieldFail.descr}{end:} +
    {else:}{end:}Start Date:{else:}{end:} + {if:addingNewPromo} + + {else:} + + {end:} + {if:fieldFail.start_date}
    {fieldFail.start_date}{end:} +
    {else:}{end:}End Date:{else:}{end:} + {if:addingNewPromo} + + {else:} + + {end:} + {if:fieldFail.end_date}
    {fieldFail.end_date}{end:} +
    +
    + +
    + {if:addingNewPromo} + + {end:} + {if:editingPromo} + + {end:} +
    + +
    + + {else:} +

    No {term.ticket.norm} add-on has been selected yet.

    +

    To edit a {term.ticket.norm} add-on, first select it from the list of available {term.ticket.plur} add-ons. + {end:} + +

    + +
    + + +
    + +{startScript:h} + + $(function() { + + /* + * Table operations + */ + + $('.promoEditTable').dataTable({ + "bPaginate": false, + "bLengthChange": false, + "bFilter": false, + "bSort": false, + "bInfo": false, + "bAutoWidth": false, + "bDestroy": true + }); + + /* + * AJAX form handling + */ + + $('#promoForm').ajaxForm({ + success: function(data) { + {if:addingNewPromo} + var container = $('#Promo_detail_container'); + f_replaceContents(data, container); + {end:} + {if:editingPromo} + var container = $('#Promo_detail_container'); + f_replaceContents(data, container); + {end:} + return false; + } + }); + + // Block default form submission + $("form").submit(function (e) { + $('#promoFormSubmit').html('
    Submitting, Please Wait...
    '); + e.preventDefault(); + }); + + /* + * CKeditor actions + */ + + // Code to kick off CKEditor for specific fields + f_buildCkeditor($("#descr")); + + // Remove the editors and store the data back in the textareas before the AJAX form submission + $('.emEditSubmit').click( function() { + f_removeCkeditor($("#descr")); + }); + + f_restartOnTabSelect(); + + function promoTypeCheck(e) { + typeval = $('#promoType').val(); + + // If this is a quantity selection + if (typeval == 2) { + $('#max_quant').show(); + } else { + $('#max_quant').hide(); + } + } + + $('#promoType').change( function() { + promoTypeCheck(); + }); + promoTypeCheck(); + + /* + * Date input operations + */ + + // Code to start datepicker for each date input + $("#startDateInput").datepicker({ + dateFormat: "mm/dd/yy", + minDate: '{performanceDetail.start_date.date_list.min}', + maxDate: '{performanceDetail.start_date.date_list.max}' + }); + $("#endDateInput").datepicker({ + dateFormat: "mm/dd/yy", + minDate: '{performanceDetail.start_date.date_list.min}', + maxDate: '{performanceDetail.start_date.date_list.max}' + }); + + + }); + + \ No newline at end of file diff --git a/views/admin/tickets/Promo/list.html b/views/admin/tickets/Promo/list.html new file mode 100644 index 0000000..c7de28a --- /dev/null +++ b/views/admin/tickets/Promo/list.html @@ -0,0 +1,124 @@ + +
    + +
    +
    +{if:checkPermission(#10#)} + +{end:} + +
    + Search {term.promo.plur_cap}: (start typing any information in list) + + {if:promos} + +
    + + + + + + {foreach:promos,c} + + + + + + + {end:} + +
    {term.promo.cap}Long NameStart DateEnd Date
    +
    + + {else:} +

    No {term.promo.plur}.

    + {end:} + +
    +
    + +
    + +
    +{startScript:h} + + // Promotions Search + var promosSearchData = [ + {foreach:promos,c} + {label:'{c.name:h}, {c.long_name:h}, {c.start_date.date}, {c.end_date.date}', value:'{c.id}'}, + {end:} + ]; + + $(function() { + + var PromoListTable = $('#PromoListTable').dataTable({ + "sScrollY": "100px", + "scrollX": true, + "bScrollCollapse": true, + "bPaginate": false, + "bLengthChange": false, + "bFilter": false, + "bSort": true, + "bInfo": false, + "bAutoWidth": false, + "bDestroy": true, + }); + $(window).resize(function(){ + PromoListTable.fnDraw(); + }); + + // Toggle length of table + var PromoListTableSmall = true; + var PromoListTableHeight = $('#PromoListTable_wrapper div.dataTables_scrollBody').height(); + $('#promoListSizeChange').click(function() { + if (PromoListTableSmall) { + $('#PromoListTable_wrapper div.dataTables_scrollBody').height('auto'); + PromoListTableSmall = false; + $(this).html('Smaller Table'); + PromoListTable.fnSettings().oScroll.sY = '100%'; + PromoListTable.fnDraw(); + } else { + $('#PromoListTable_wrapper div.dataTables_scrollBody').height(PromoListTableHeight); + PromoListTableSmall = true; + $(this).html('Larger Table'); + PromoListTable.fnSettings().oScroll.sY = '100px'; + PromoListTable.fnDraw(); + } + }); + + // Close all local sliders + $('#Promo_detail').hide(duration); + + $('.promoListSelect').click(function(){ + $('#PromoListTable_wrapper div.dataTables_scrollBody').height(PromoListTableHeight); + PromoListTableSmall = true; + $('#promoListSizeChange').html('Larger Table'); + PromoListTable.fnSettings().oScroll.sY = '100px'; + PromoListTable.fnDraw(); + f_loadAction('Promo_selected', 'Promo_detail_container', 'PromoID=' + $(this).attr('emPromoId') + '&tabList={tabList}'); + }); + + // Search Promotions + $("#promosSearch").autocomplete({ + source: promosSearchData, + minLength: 1, + focus: function(event, ui) { + // Don't auto fill on focus + return false; + }, + select: function(event, ui) { + $("#promosSearch").attr({value: ui.item.label}); + f_loadAction('Promo_selected', 'Promo_detail_container', 'PromoID=' + ui.item.value + '&tabList={tabList}'); + return false; + } + }); + + f_restartOnTabSelect(); + + }); + + diff --git a/views/admin/tickets/Promo/selected.html b/views/admin/tickets/Promo/selected.html new file mode 100644 index 0000000..e6b9c45 --- /dev/null +++ b/views/admin/tickets/Promo/selected.html @@ -0,0 +1,32 @@ +
    + +
    +
    {term.promo.cap}: {promoDetail.name}
    +
    + +
    + + +
    +
    + +
    + +
    + + +{startScript:h} + + // jQuery Section + $(document).ready(function(){ + + // Start with ticket detail loaded + f_loadAction('Promo_detail', 'Promo_detail_container', "tabList={tabList}"); + + f_restartOnTabSelect(); + + }); + + diff --git a/views/admin/tickets/Report/customClaimed.html b/views/admin/tickets/Report/customClaimed.html new file mode 100644 index 0000000..ffb09e1 --- /dev/null +++ b/views/admin/tickets/Report/customClaimed.html @@ -0,0 +1,152 @@ + + +{if:printOutput} + + + + {startScript:h} + + // Pass some reference parameters to JAVAScript + var baseSiteURL = '{baseURL}'; + var baseAdminURL = '{baseAdminURL}'; + var appAdminURL = '{appAdminURL}'; + var memberUser = '{MemberUser}'; + var debugEnabled = {if:option.admin_debug}true{else:}false{end:}; + + + + + + + + + + + + + +{end:} + + + +
    + + Custom Report + Report Produced: {reportDate} {reportTime} +
    +
    {reportNote}
    + + +
    + + + + + + {if:checkPermission(#0#)}{end:} + + + + + + + + + + + + + + + + + {foreach:reportData,r} + + + {if:checkPermission(#0#)}{end:} + + + + + + + + + + + + + + + {end:} + + + {if:checkPermission(#0#)}{end:} + + + + + + + + + + + + + + + + + + {if:checkPermission(#0#)} + + {end:} + + + + + + + + + + + + + + +
    Scanned By{term.prop.cap}{term.performance.cap}{term.section.cap}{term.ticket.cap}Date/Time{term.voucher.cap}ScansFirst NameLast NameCityStatePhoneE-Mail
    {r.scannedBy}{r.member:h}{r.performance:h}{r.section:h}{r.ticket:h}{r.dateTime}{r.voucher}{r.scans}{r.fname:h}{r.lname:h}{r.city:h}{r.state:h}{r.phone:h}{r.email:h}
                  
    Grand Totals     {totalVouchers}{totalScans}      
    +
    +
    + +
    +{startScript:h} + + $(function() { + + var SalesReportTable = $('#SalesReportTable').dataTable({ + "sScrollY": "600px", + "sScrollX": "100%", + "bPaginate": false, + "bLengthChange": false, + "bFilter": false, + "bSort": false, + "bInfo": false + }); + $(window).resize(function(){ + SalesReportTable.fnDraw(); + }); + + + f_restartOnTabSelect(); + + }); + + + + +{if:printOutput} + + +{end:} diff --git a/views/admin/tickets/Report/customClaimedCSV.html b/views/admin/tickets/Report/customClaimedCSV.html new file mode 100755 index 0000000..955a694 --- /dev/null +++ b/views/admin/tickets/Report/customClaimedCSV.html @@ -0,0 +1,7 @@ +"Sales Report","Report Produced: {reportDate}","{reportTime}","Dates:","{dateFrom}","through","{dateTo}" + +"Scanned By",{if:checkPermission(#0#)}"{term.prop.cap}",{end:}"{term.performance.cap}","{term.section.cap}","{term.ticket.cap}","Date/Time","{term.voucher.cap}","Scans","First Name","Last Name","City","State","Phone","E-Mail" +{foreach:reportData,r}"{r.scannedBy:h}"{if:checkPermission(#0#)},"{r.memb_name:h}",{end:}"{r.performance:h}","{r.section:h}","{r.ticket:h}","{r.dateTime:h}","{r.voucher}","{r.scans}","{r.fname:h}","{r.lname:h}","{r.city:h}","{r.state:h}","{r.phone:h}","{r.email:h}" +{end:} +"Grand Totals",{if:checkPermission(#0#)}"",{end:}"","","","","{totalVouchers}","{totalScans}" + diff --git a/views/admin/tickets/Report/customClaimedDetail.html b/views/admin/tickets/Report/customClaimedDetail.html new file mode 100644 index 0000000..5ba9e86 --- /dev/null +++ b/views/admin/tickets/Report/customClaimedDetail.html @@ -0,0 +1,149 @@ + + +{if:printOutput} + + + + {startScript:h} + + // Pass some reference parameters to JAVAScript + var baseSiteURL = '{baseURL}'; + var baseAdminURL = '{baseAdminURL}'; + var appAdminURL = '{appAdminURL}'; + var memberUser = '{MemberUser}'; + var debugEnabled = {if:option.admin_debug}true{else:}false{end:}; + + + + + + + + + + + + + +{end:} + + + +
    + + Custom Report + Report Produced: {reportDate} {reportTime} +
    +
    {reportNote}
    + + {if:salesList} + +
    + + + + + {if:checkPermission(#0#)}{end:} + + + + + + + + + + + + + + + + {foreach:salesList,r} + + {if:checkPermission(#0#)}{end:} + + + + + + + + + + + + + + {end:} + + {if:checkPermission(#0#)}{end:} + + + + + + + + + + + + + + + + {if:checkPermission(#0#)} + + {end:} + + + + + + + + + + + + + +
    {term.prop.cap}{term.performance.cap}DateTimeOrder ID{term.voucher.cap}ScansScanned ByFirst NameLast NameCityState
    {r.memb_name}{r.perf_name}{r.date_date}{r.time_time}{r.order_id}{r.order_voucher_id}{r.order_numb_claims}{r.order_claims}{r.order_fname:h}{r.order_lname:h}{r.order_city:h}{r.order_state:h}
                
    Grand Totals    {numbVouchers}{numbClaims}     
    +
    +
    + + {else:} +

    No results found.

    + {end:} + +
    +{startScript:h} + + $(function() { + + var SalesReportTable = $('#SalesReportTable').dataTable({ + "sScrollY": "600px", + "sScrollX": "100%", + "bPaginate": false, + "bLengthChange": false, + "bFilter": false, + "bSort": false, + "bInfo": false + }); + $(window).resize(function(){ + SalesReportTable.fnDraw(); + }); + + + f_restartOnTabSelect(); + + }); + + + + +{if:printOutput} + + +{end:} diff --git a/views/admin/tickets/Report/customClaimedDetailCSV.html b/views/admin/tickets/Report/customClaimedDetailCSV.html new file mode 100755 index 0000000..fc89638 --- /dev/null +++ b/views/admin/tickets/Report/customClaimedDetailCSV.html @@ -0,0 +1,11 @@ +"Sales Report","Report Produced: {reportDate}","{reportTime}","Dates:","{dateFrom}","through","{dateTo}" + +{if:salesList}{if:checkPermission(#0#)}"{term.prop.cap}",{end:}"{term.performance.cap}","Date","Time","Order ID","{term.voucher.cap}","Scans","Scanned By","First Name","Last Name","City","State" +{foreach:salesList,r}{if:checkPermission(#0#)}"{r.memb_name}",{end:}"{r.perf_name}","{r.date_date}","{r.time_time}","{r.order_id}","{r.order_voucher_id}","{r.order_numb_claims}","{r.order_claims}","{r.order_fname:h}","{r.order_lname:h}","{r.order_city:h}","{r.order_state:h}" +{end:} +"Grand Totals",{if:checkPermission(#0#)}"",{end:}"","","","{numbVouchers}","{numbClaims}" + +{else:} +No results found. +{end:} + diff --git a/views/admin/tickets/Report/customManifest.html b/views/admin/tickets/Report/customManifest.html new file mode 100644 index 0000000..4c45062 --- /dev/null +++ b/views/admin/tickets/Report/customManifest.html @@ -0,0 +1,106 @@ + + +{if:printOutput} + + + + {startScript:h} + + // Pass some reference parameters to JAVAScript + var baseSiteURL = '{baseURL}'; + var baseAdminURL = '{baseAdminURL}'; + var appAdminURL = '{appAdminURL}'; + var memberUser = '{MemberUser}'; + var debugEnabled = {if:option.admin_debug}true{else:}false{end:}; + + + + + + + + + + + + + +{end:} + + + +
    + + Manifest + Report Produced: {reportDate} {reportTime} +
    +
    {reportNote}
    + + +
    + + + + + + + + + + + + + + + + + + {foreach:reportData,r} + + + + + + + + + + + + + {end:} + +
    {term.performance.cap}{term.ticket.cap}DateTimeOrderVoucherLast NameFirst NamePhoneNotes
    {r.performance_name:h}{r.ticket_name:h}{r.ticket_date}{r.ticket_time}{r.ticket_order}{r.voucher}{r.lname:h}{r.fname:h}{r.phone:h}{r.notes:h}
    +
    +
    + +
    +{startScript:h} + + $(function() { + + var SalesReportTable = $('#SalesReportTable').dataTable({ + "sScrollY": "600px", + "sScrollX": "100%", + "bPaginate": false, + "bLengthChange": false, + "bFilter": false, + "bSort": false, + "bInfo": false + }); + $(window).resize(function(){ + SalesReportTable.fnDraw(); + }); + + + f_restartOnTabSelect(); + + }); + + + + +{if:printOutput} + + +{end:} diff --git a/views/admin/tickets/Report/customManifestCSV.html b/views/admin/tickets/Report/customManifestCSV.html new file mode 100755 index 0000000..6d84eb5 --- /dev/null +++ b/views/admin/tickets/Report/customManifestCSV.html @@ -0,0 +1,6 @@ +"Manifest","Report Produced:","{reportDate}","{reportTime}","Dates:","{dateFrom}","through","{dateTo}" + +"{term.performance.cap}","{term.ticket.cap}","Date","Time","Order","Voucher","Last Name","First Name","Phone","Notes" +{foreach:reportData,r}"{r.performance_name:h}","{r.ticket_name:h}","{r.ticket_date}","{r.ticket_time}","{r.ticket_order}","{r.voucher}","{r.lname:h}","{r.fname:h}","{r.phone:h}","{r.notes:h}" +{end:} + diff --git a/views/admin/tickets/Report/customReportSelection.html b/views/admin/tickets/Report/customReportSelection.html new file mode 100644 index 0000000..916e416 --- /dev/null +++ b/views/admin/tickets/Report/customReportSelection.html @@ -0,0 +1,233 @@ +
    + +
    + Custom Report Selection +
    + +
    + +
    + + + +{if:!checkPermission(#0#)} + +{end:} +
    + + + +{if:checkPermission(#0#)} + + + + + + + + + + + + +{end:} + + + + + + + + + + + + + +
    Type of Report: + +
    {term.prop.cap}: + +
    Show inactive {term.prop.plur_cap}
    {term.performance.cap}: + (select a {term.prop.norm} first) +
    Date Range: + + +    + From:    + Through:    + +
    Output Type: + +
    +
    + +
    + +
    + +
    + +
    + +
    + + +
    + +{startScript:h} + + var mList = new Array(); + {foreach:mList,m} + mList[{m.id}] = ''; + {end:} + + $(function() { + + /* + * Table operations + */ + + $('.customReportTable').dataTable({ + "bPaginate": false, + "bLengthChange": false, + "bFilter": false, + "bSort": false, + "bInfo": false, + "bAutoWidth": false, + "bDestroy": true, + "aoColumns" : [ + { sWidth: '10%' }, + null + ] + }); + + /* + * AJAX form handling + */ + + $('#customReportForm').ajaxForm({ + beforeSubmit: function(xhr) { + + // Check if this is going to be a csv + var outputType = $('#outputType').val(); + if (outputType == 'csv') { + + // Since this is a csv, open a new window with the desired URL and parameters rather than an ajax submit. + var url = appAdminURL + '&' + $('#customReportForm').formSerialize(); + window.open(url, 'csvReport', 'toolbar=no,location=no,directories=no,menubar=no,scrollbars=no,width=100, height=10'); + return false; + } + }, + success: function(data) { + + var outputType = $('#outputType').val(); + + if (outputType == 'print') { + var w = window.open('', 'printReport', 'toolbar=no,location=no,directories=no,menubar=no,scrollbars=yes,width=1000, height=700, left=100, top=25'); + $(w.document.body).html(data); + } else { + f_replaceContents(data, $('#report_result_container')); + } + + return false; + } + }); + + // Block default form submission + $("#customReportForm").submit(function (e) { + + var outputType = $('#outputType').val(); + + if (outputType == 'html') { + $('#report_result_container').html('
    Submitting, Please Wait...
    '); + } + + e.preventDefault(); + }); + + + var currentMousePos = { x: -1, y: -1 }; + $(document).mousemove(function(event) { + currentMousePos.x = event.pageX; + currentMousePos.y = event.pageY; + }); + + // Code to start datepicker for each date input + $("#startDateInput").datepicker({ + dateFormat: "mm/dd/yy", + dialog: [{maxDate}, false, false, [100,200]], + minDate: '{minDate}', + maxDate: '{maxDate}', + beforeShow: function (input, inst) { + setTimeout(function () { + inst.dpDiv.css({ + top: currentMousePos.y, + left: currentMousePos.x + }); + }, 0); + } + }); + $("#endDateInput").datepicker({ + dateFormat: "mm/dd/yy", + dialog: [{maxDate}, false, false, [200,300]], + minDate: '{minDate}', + maxDate: '{maxDate}', + beforeShow: function (input, inst) { + setTimeout(function () { + inst.dpDiv.css({ + top: currentMousePos.y, + left: currentMousePos.x + }); + }, 0); + } + }); + + // Check if to hide dates + $('#dateType').on('change', null, function() { + var dateType = $(this).val(); + if (dateType == 'all') { + $('#dateFields').addClass('emContentAreaHidden'); + } else { + $('#dateFields').removeClass('emContentAreaHidden'); + } + }); + + // Selection of performance list + $('#memberID').on('change', null, function() { + var memberID = $(this).val(); + $('#performanceSelect').html(mList[memberID]); + }); + + f_restartOnTabSelect(); + +{if:!checkPermission(#0#)} + // This must be a member used so start with their performances loaded + $('#performanceSelect').html(mList[{userMemberID}]); +{end:} + + + + + }); + + + diff --git a/views/admin/tickets/Report/error.html b/views/admin/tickets/Report/error.html new file mode 100755 index 0000000..d8b3ff6 --- /dev/null +++ b/views/admin/tickets/Report/error.html @@ -0,0 +1,14 @@ + + +
    + + Promo Detail Report + Report Produced: {reportDate} {reportTime} +
    +
    {reportNote}
    + +

    There was a error with your request:

    +
    {errorMsg:h}
    +

     

    + +
    diff --git a/views/admin/tickets/Report/index.html b/views/admin/tickets/Report/index.html new file mode 100644 index 0000000..b2ee83f --- /dev/null +++ b/views/admin/tickets/Report/index.html @@ -0,0 +1,56 @@ +
    + +
    +
    Reports:
    +
    + +
    + + +{if:checkPermission(#20#)} +
    + + + + + +
    +{end:} + +
    +
    (select report tab above)
    +
    + +
    +
    + + +{startScript:h} + + // jQuery Section + $(document).ready(function(){ + + // Start with Ticket Sales report form loaded + f_loadAction('Report_orders', 'Report_container', "tabList={tabList}"); + + f_restartOnTabSelect(); + + }); + + diff --git a/views/admin/tickets/Report/member.html b/views/admin/tickets/Report/member.html new file mode 100644 index 0000000..c1f5579 --- /dev/null +++ b/views/admin/tickets/Report/member.html @@ -0,0 +1,119 @@ + + +{if:printOutput} + + + + {startScript:h} + + // Pass some reference parameters to JAVAScript + var baseSiteURL = '{baseURL}'; + var baseAdminURL = '{baseAdminURL}'; + var appAdminURL = '{appAdminURL}'; + var memberUser = '{MemberUser}'; + var debugEnabled = {if:option.admin_debug}true{else:}false{end:}; + + + + + + + + + + + + + +{end:} + + + +
    + + {term.prop.cap} Report + {reportDate} {reportTime} +
    + {reportNote} + + {if:membersList} + +
    + + + + + + + + + + + + + + + {foreach:membersList,m} + {if:m.active.value} + + {else:} + + {end:} + + + + + + + + + + {end:} + + + + + + + + + + + + +
    {term.prop.cap} NameActive{term.section.plur_cap}{term.performance.plur_cap}{term.ticket.plur_cap}Inventory# Sold$ Sold
    {m.name}{m.active.name}{m.sectionStats}{m.performanceStats}{m.ticketStats}{m.ticketSalesStats.totalquant}{m.ticketSalesStats.totalsold}{m.ticketSalesStats.totalMoney}
     Totals:{totals.sections}{totals.events}{totals.tickets}{totals.inventory}{totals.sold}{totals.price}
    +
    + + {else:} +

    No results found.

    + {end:} + +
    +{startScript:h} + + $(function() { + + var MemberReportTable = $('#MemberReportTable').dataTable({ + "sScrollX": "100%", + "bPaginate": false, + "bLengthChange": false, + "bFilter": false, + "bSort": false, + "bInfo": false + }); + $(window).resize(function(){ + MemberReportTable.fnDraw(); + }); + + + f_restartOnTabSelect(); + + }); + + + + +{if:printOutput} + + +{end:} diff --git a/views/admin/tickets/Report/memberCSV.html b/views/admin/tickets/Report/memberCSV.html new file mode 100644 index 0000000..9597bf5 --- /dev/null +++ b/views/admin/tickets/Report/memberCSV.html @@ -0,0 +1,9 @@ +"{term.prop.cap} Report","{reportDate}","{reportTime}","{reportNote}" + +{if:membersList}"{term.prop.cap} Name","Active","{term.section.plur_cap}","{term.performance.plur_cap}","{term.ticket.plur_cap}","Inventory","# Sold","$ Sold" +{foreach:membersList,m}"{m.name}","{m.active.name}","{m.sectionStats}","{m.performanceStats}","{m.ticketStats}","{m.ticketSalesStats.totalquant}","{m.ticketSalesStats.totalsold}","{m.ticketSalesStats.totalMoney}" +{end:} +"","Totals:","{totals.sections}","{totals.events}","{totals.tickets}","{totals.inventory}","{totals.sold}","{totals.price}" +{else:} +No results found." +{end:} diff --git a/views/admin/tickets/Report/memberReportSelection.html b/views/admin/tickets/Report/memberReportSelection.html new file mode 100644 index 0000000..076fd7c --- /dev/null +++ b/views/admin/tickets/Report/memberReportSelection.html @@ -0,0 +1,187 @@ +
    + +
    + {term.prop.cap} Report Selection +
    + +
    + +
    + + +
    + + + + + + + + + + + + + + + + + + + + +
    {term.prop.cap}: + +
    Show inactive {term.prop.plur_cap}
    Date Range for Sales Data: + + +    + From:    + Through:    + +
    Output Type: + +
    +
    + +
    + +
    + +
    + +
    + +
    + + +
    + +{startScript:h} + + $(function() { + + /* + * Table operations + */ + + $('.memberReportTable').dataTable({ + "bPaginate": false, + "bLengthChange": false, + "bFilter": false, + "bSort": false, + "bInfo": false, + "bAutoWidth": false, + "bDestroy": true, + "aoColumns" : [ + { sWidth: '10%' }, + null + ] + }); + + /* + * AJAX form handling + */ + + $('#memberReportForm').ajaxForm({ + beforeSubmit: function(xhr) { + + // Check if this is going to be a csv + var outputType = $('#outputType').val(); + if (outputType == 'csv') { + + // Since this is a csv, open a new window with the desired URL and parameters rather than an ajax submit. + var url = appAdminURL + '&' + $('#memberReportForm').formSerialize(); + window.open(url, 'csvReport', 'toolbar=no,location=no,directories=no,menubar=no,scrollbars=no,width=100, height=10'); + return false; + } + }, + success: function(data) { + + var outputType = $('#outputType').val(); + + if (outputType == 'print') { + var w = window.open('', 'printReport', 'toolbar=no,location=no,directories=no,menubar=no,scrollbars=yes,width=1000, height=700, left=100, top=25'); + $(w.document.body).html(data); + } else { + f_replaceContents(data, $('#report_result_container')); + } + + return false; + } + }); + + // Block default form submission + $("#memberReportForm").submit(function (e) { + + var outputType = $('#outputType').val(); + + if (outputType == 'html') { + $('#report_result_container').html('
    Submitting, Please Wait...
    '); + } + + e.preventDefault(); + }); + + // Code to start datepicker for each date input + $("#startDateInput").datepicker({ + dateFormat: "mm/dd/yy", + dialog: [{maxDate}, false, false, [100,200]], + minDate: '{minDate}', + maxDate: '{maxDate}', + beforeShow: function (input, inst) { + setTimeout(function () { + inst.dpDiv.css({ + top: currentMousePos.y, + left: currentMousePos.x + }); + }, 0); + } + }); + $("#endDateInput").datepicker({ + dateFormat: "mm/dd/yy", + dialog: [{maxDate}, false, false, [200,300]], + minDate: '{minDate}', + maxDate: '{maxDate}', + beforeShow: function (input, inst) { + setTimeout(function () { + inst.dpDiv.css({ + top: currentMousePos.y, + left: currentMousePos.x + }); + }, 0); + } + }); + + // Check if to hide dates + $('#dateRange').on('change', null, function() { + var dateRange = $(this).val(); + if (dateRange == 'specified') { + $('#dateFields').removeClass('emContentAreaHidden'); + } else { + $('#dateFields').addClass('emContentAreaHidden'); + } + }); + + f_restartOnTabSelect(); + + }); + + + diff --git a/views/admin/tickets/Report/orders.html b/views/admin/tickets/Report/orders.html new file mode 100644 index 0000000..e88eb94 --- /dev/null +++ b/views/admin/tickets/Report/orders.html @@ -0,0 +1,169 @@ + + +{if:printOutput} + + + + {startScript:h} + + // Pass some reference parameters to JAVAScript + var baseSiteURL = '{baseURL}'; + var baseAdminURL = '{baseAdminURL}'; + var appAdminURL = '{appAdminURL}'; + var memberUser = '{MemberUser}'; + var debugEnabled = {if:option.admin_debug}true{else:}false{end:}; + + + + + + + + + + + + + +{end:} + + + +
    + + Orders Report + {reportDate} {reportTime} +
    + + {reportNote} + + {if:ordersList} + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {foreach:ordersList,r} + + + + + + + + + + + + + + + + + + + + + + + + {end:} + + + + + + + + + + + + + + + + + + + + + + + + +
    Order #Purch DateLast NameFirst NameAddressAddressCityStateZIPCountryPhoneE-MailContact OK{term.prop.cap}Credit CardCard NumberExpirationName on CardConfirmationCharge Amount
    {r.id}{r.purchase_date.date}{r.lname}{r.fname}{r.addr1}{r.addr2}{r.city}{r.state.name}{r.zip}{r.country.name}{r.phone}{r.email}{r.email_ok.name}{r.member_name}{r.cctype}{r.ccnumber}{r.expire}{r.ccname}{r.ccconf}{r.charge_total}
              Number of Orders: {numbOrders}Average Order: {averageOrder}       Total: {totalChargesMoney}
    +
    +
    + + {else:} +

    No results found.

    + {end:} + +
    +{startScript:h} + + $(function() { + + var OrdersReportTable = $('#OrdersReportTable').dataTable({ + "sScrollY": "600px", + "sScrollX": "100%", + "bPaginate": false, + "bLengthChange": false, + "bFilter": false, + "bSort": false, + "bInfo": false, + "columnDefs": [ + { + "targets": [ 4, 5, 12, 13, 14, 15, 16, 17, 18 ], + "visible": false + } + ] + }); + + $(window).resize(function(){ + OrdersReportTable.fnDraw(); + }); + + $('.orderSelect').click( function (event) { + var orderID = $(this).attr('data-id'); + f_loadAction('Sold_claim', 'Main_container', 'orderID=' + orderID); + return false; + }); + + f_restartOnTabSelect(); + + }); + + + + +{if:printOutput} + + +{end:} diff --git a/views/admin/tickets/Report/ordersCSV.html b/views/admin/tickets/Report/ordersCSV.html new file mode 100644 index 0000000..003d9bc --- /dev/null +++ b/views/admin/tickets/Report/ordersCSV.html @@ -0,0 +1,9 @@ +"Orders Report","{reportDate}","{reportTime}","{reportNote}" + +{if:ordersList}"ID","Purch Date","Last Name","First Name","Address","Address","City","State","ZIP","Country","Phone","E-Mail","Contact OK","{term.prop.cap}","Credit Card","Card Number","Expiration","Name on Card","Confirmation","Charge Amount" +{foreach:ordersList,r}"{r.id}","{r.purchase_date.date}","{r.lname}","{r.fname}","{r.addr1}","{r.addr2}","{r.city}","{r.state.name}","{r.zip}","{r.country.name}","{r.phone}","{r.email}","{r.email_ok.name}","{r.member_name}","{r.cctype}","{r.ccnumber}","{r.expire}","{r.ccname}","{r.ccconf}","{r.charge_numb}" +{end:} +"","","","","","","","","","","","Number of Orders:","{numbOrders}","","","","","","Total:","{totalCharges}" +{else:} +No results found. +{end:} diff --git a/views/admin/tickets/Report/ordersReportSelection.html b/views/admin/tickets/Report/ordersReportSelection.html new file mode 100644 index 0000000..d0d9a42 --- /dev/null +++ b/views/admin/tickets/Report/ordersReportSelection.html @@ -0,0 +1,309 @@ +
    + +
    + {term.ticket.cap} Orders Report Selection +
    + +
    + +
    + + +{if:!checkPermission(#0#)} + +{end:} +
    + + + + + + +{if:checkPermission(#0#)} + + + + {end:} +{end:} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Order #: + + {term.prop.cap}: + +{else:} + {if:users_access_all_members} + {term.prop.cap}: + + {else:} +   
    Last Name: + + Show inactive {term.prop.plur_cap}
    First Name: + + Purchase Date Range: + + +    + From:    + Through:    +
    + Enter only "From:" date to display orders for a single date. +
    +
    +
    City: + + Ticket Date or Likely Date: + + +    + From:    + Through:    + +
    State (2 letter code): + + OK to send E-Mail: + + Show only orders where customer indicated
    it was OK to sent them general E-Mail. +
    ZIP/Postal Code: + + Sort By: + +
    Phone #: + + Output Type: + +
    +
    + +
    + +
    + +
    + +
    + +
    + + +
    + +{startScript:h} + + $(function() { + + /* + * Table operations + */ + + $('.ordersReportTable').dataTable({ + "bPaginate": false, + "bLengthChange": false, + "bFilter": false, + "bSort": false, + "bInfo": false, + "bAutoWidth": false, + "bDestroy": true, + "aoColumns" : [ + { sWidth: '25%' }, + { sWidth: '25%' }, + { sWidth: '25%' }, + { sWidth: '25%' } + ] + }); + + /* + * AJAX form handling + */ + + $('#ordersReportForm').ajaxForm({ + beforeSubmit: function(xhr) { + + // Check if this is going to be a csv + var outputType = $('#outputType').val(); + if (outputType == 'csv') { + + // Since this is a csv, open a new window with the desired URL and parameters rather than an ajax submit. + var url = appAdminURL + '&' + $('#ordersReportForm').formSerialize(); + window.open(url, 'csvReport', 'toolbar=no,location=no,directories=no,menubar=no,scrollbars=no,width=100, height=10'); + return false; + } + }, + success: function(data) { + + var outputType = $('#outputType').val(); + + if (outputType == 'print') { + var w = window.open('', 'printReport', 'toolbar=no,location=no,directories=no,menubar=no,scrollbars=yes,width=1000, height=700, left=100, top=25'); + $(w.document.body).html(data); + } else { + f_replaceContents(data, $('#report_result_container')); + } + + return false; + } + }); + + // Block default form submission + $("#ordersReportForm").submit(function (e) { + + var outputType = $('#outputType').val(); + + if (outputType == 'html') { + $('#report_result_container').html('
    Submitting, Please Wait...
    '); + } + + e.preventDefault(); + }); + + + var currentMousePos = { x: -1, y: -1 }; + $(document).mousemove(function(event) { + currentMousePos.x = event.pageX; + currentMousePos.y = event.pageY; + }); + + // Code to start datepicker for each date input + $("#startDateInput").datepicker({ + dateFormat: "mm/dd/yy", + dialog: [{maxDate}, false, false, [100,200]], + minDate: '{minDate}', + maxDate: '{maxDate}', + beforeShow: function (input, inst) { + setTimeout(function () { + inst.dpDiv.css({ + top: currentMousePos.y, + left: currentMousePos.x + }); + }, 0); + } + }); + $("#endDateInput").datepicker({ + dateFormat: "mm/dd/yy", + dialog: [{maxDate}, false, false, [200,300]], + minDate: '{minDate}', + maxDate: '{maxDate}', + beforeShow: function (input, inst) { + setTimeout(function () { + inst.dpDiv.css({ + top: currentMousePos.y, + left: currentMousePos.x + }); + }, 0); + } + }); + $("#ticketStartDateInput").datepicker({ + dateFormat: "mm/dd/yy", + dialog: [{maxDate}, false, false, [100,200]], + minDate: '{minDate}', + maxDate: '{maxDate}', + beforeShow: function (input, inst) { + setTimeout(function () { + inst.dpDiv.css({ + top: currentMousePos.y, + left: currentMousePos.x + }); + }, 0); + } + }); + $("#ticketEndDateInput").datepicker({ + dateFormat: "mm/dd/yy", + dialog: [{maxDate}, false, false, [200,300]], + minDate: '{minDate}', + maxDate: '{maxDate}', + beforeShow: function (input, inst) { + setTimeout(function () { + inst.dpDiv.css({ + top: currentMousePos.y, + left: currentMousePos.x + }); + }, 0); + } + }); + + // Check if to hide dates + $('#dateType').on('change', null, function() { + var dateType = $(this).val(); + if (dateType == 'all') { + $('#dateFields').addClass('emContentAreaHidden'); + } else { + $('#dateFields').removeClass('emContentAreaHidden'); + } + }); + $('#ticketDateType').on('change', null, function() { + var dateType = $(this).val(); + if (dateType == 'all') { + $('#ticketDateFields').addClass('emContentAreaHidden'); + } else { + $('#ticketDateFields').removeClass('emContentAreaHidden'); + } + }); + + f_restartOnTabSelect(); + + + }); + + + diff --git a/views/admin/tickets/Report/promoCSV.html b/views/admin/tickets/Report/promoCSV.html new file mode 100755 index 0000000..6909e23 --- /dev/null +++ b/views/admin/tickets/Report/promoCSV.html @@ -0,0 +1,10 @@ +"Sales Report","Report Produced: {reportDate}","{reportTime}","{reportNote}" + +{if:salesList}{if:checkPermission(#0#)}"{term.prop.cap}",{end:}"{term.performance.cap}","{term.section.cap}","{term.ticket.cap}","Add On","Add On Sold","Date","Time","Quantity","Sold","Claimed","Promo","Paid" +{foreach:salesList,r}{if:checkPermission(#0#)}"{r.memb_name}",{end:}"{r.perf_name}","{r.sect_name}","{r.tick_name}","{r.addon_name}","{r.addon_sold}","{r.date_date}","{r.time_time}","{r.time_quant}","{r.time_sold}","{r.time_claimed}","{r.time_promo}","{r.time_price}" +{end:} +"Grand Totals",{if:checkPermission(#0#)}"",{end:}"","","","","","","{totalQuant}","{totalSold}","{totalClaimed}","{totalPromos}","{totalPrice}" +"",{if:checkPermission(#0#)},""{end:},"","","","","","","","","{percentClaimed}%" +{else:} +No results found. +{end:} diff --git a/views/admin/tickets/Report/promoDetail.html b/views/admin/tickets/Report/promoDetail.html new file mode 100644 index 0000000..c6d5293 --- /dev/null +++ b/views/admin/tickets/Report/promoDetail.html @@ -0,0 +1,221 @@ + + +{if:printOutput} + + + + {startScript:h} + + // Pass some reference parameters to JAVAScript + var baseSiteURL = '{baseURL}'; + var baseAdminURL = '{baseAdminURL}'; + var appAdminURL = '{appAdminURL}'; + var memberUser = '{MemberUser}'; + var debugEnabled = {if:option.admin_debug}true{else:}false{end:}; + + + + + + + + + + + + + +{end:} + + + +
    + + Promo Detail Report + Report Produced: {reportDate} {reportTime} +
    +
    {reportNote}
    + + {if:promoList} + +
    + + + + + {if:checkPermission(#0#)}{end:} + + + + + + + + + + + + + + + + + + + + + + + + + + + {foreach:promoList,r} + + {if:checkPermission(#0#)}{end:} + + + + + + + + + + + + + + + + + + + + + + + + + {end:} + + {if:checkPermission(#0#)}{end:} + + + + + + + + + + + + + + + + + + + + + + + + + + + {if:checkPermission(#0#)} + + {end:} + + + + + + + + + + + + + + + + + + + + + + + + + + {if:checkPermission(#0#)} + + {end:} + + + + + + + + + + + + + + + + + + + + + + + + +
    {term.prop.cap}{term.performance.cap}{term.section.cap}{term.ticket.cap}Add OnAdd On
    Sold
    DateTimeQuantitySoldClaimedPromoPaidOrder ID{term.voucher.cap}First NameLast NameAddressAddress 2CityStateZIP/PostalCountryPhone #
    {r.memb_name}{r.perf_name}{r.sect_name}{r.tick_name}{r.addon_name}{r.addon_sold}{r.date_date}{r.time_time}{r.time_quant}{r.time_sold}{r.time_claimed}{r.time_promo_money}{r.time_money}{r.order_id}{r.order_voucher_id}{r.order_fname:h}{r.order_lname:h}{r.order_addr1:h}{r.order_addr2:h}{r.order_city:h}{r.order_state:h}{r.order_zip}{r.order_country}{r.order_phone}
                            
    Grand Totals       {totalQuant}{totalSold}{totalClaimed}{totalPromosMoney}{totalMoney}           
             {percentSold}%{percentClaimed}%             
    +
    +
    + + {else:} +

    No results found.

    + {end:} + +
    +{startScript:h} + + $(function() { + + var PromoReportTable = $('#PromoReportTable').dataTable({ + "sScrollY": "600px", + "sScrollX": "100%", + "bPaginate": false, + "bLengthChange": false, + "bFilter": false, + "bSort": false, + "bInfo": false + }); + $(window).resize(function(){ + PromoReportTable.fnDraw(); + }); + + + f_restartOnTabSelect(); + + }); + + + + +{if:printOutput} + + +{end:} diff --git a/views/admin/tickets/Report/promoReportSelection.html b/views/admin/tickets/Report/promoReportSelection.html new file mode 100644 index 0000000..c19969a --- /dev/null +++ b/views/admin/tickets/Report/promoReportSelection.html @@ -0,0 +1,220 @@ +
    + +
    + Promo Codes Report Selection +
    + +
    + +
    + + +{if:!checkPermission(#0#)} + +{end:} +
    + + + +{if:checkPermission(#0#)} + + + + + + + + +{end:} + + + + + + + + + +
    Type of Report: + +
    Promo Code: + +
    Date Range: + + +    + From:    + Through:    + +
    Output Type: + +
    +
    + +
    + +
    + +
    + +
    + +
    + + +
    + +{startScript:h} + + var mList = new Array(); + {foreach:mList,m} + mList[{m.id}] = ''; + {end:} + + $(function() { + + /* + * Table operations + */ + + $('.promoReportTable').dataTable({ + "bPaginate": false, + "bLengthChange": false, + "bFilter": false, + "bSort": false, + "bInfo": false, + "bAutoWidth": false, + "bDestroy": true, + "aoColumns" : [ + { sWidth: '10%' }, + null + ] + }); + + /* + * AJAX form handling + */ + + $('#promoReportForm').ajaxForm({ + beforeSubmit: function(xhr) { + + // Check if this is going to be a csv + var outputType = $('#outputType').val(); + if (outputType == 'csv') { + + // Since this is a csv, open a new window with the desired URL and parameters rather than an ajax submit. + var url = appAdminURL + '&' + $('#promoReportForm').formSerialize(); + window.open(url, 'csvReport', 'toolbar=no,location=no,directories=no,menubar=no,scrollbars=no,width=100, height=10'); + return false; + } + }, + success: function(data) { + + var outputType = $('#outputType').val(); + + if (outputType == 'print') { + var w = window.open('', 'printReport', 'toolbar=no,location=no,directories=no,menubar=no,scrollbars=yes,width=1000, height=700, left=100, top=25'); + $(w.document.body).html(data); + } else { + f_replaceContents(data, $('#report_result_container')); + } + + return false; + } + }); + + // Block default form submission + $("#promoReportForm").submit(function (e) { + + var outputType = $('#outputType').val(); + + if (outputType == 'html') { + $('#report_result_container').html('
    Submitting, Please Wait...
    '); + } + + e.preventDefault(); + }); + + + var currentMousePos = { x: -1, y: -1 }; + $(document).mousemove(function(event) { + currentMousePos.x = event.pageX; + currentMousePos.y = event.pageY; + }); + + // Code to start datepicker for each date input + $("#startDateInput").datepicker({ + dateFormat: "mm/dd/yy", + dialog: [{maxDate}, false, false, [100,200]], + minDate: '{minDate}', + maxDate: '{maxDate}', + beforeShow: function (input, inst) { + setTimeout(function () { + inst.dpDiv.css({ + top: currentMousePos.y, + left: currentMousePos.x + }); + }, 0); + } + }); + $("#endDateInput").datepicker({ + dateFormat: "mm/dd/yy", + dialog: [{maxDate}, false, false, [200,300]], + minDate: '{minDate}', + maxDate: '{maxDate}', + beforeShow: function (input, inst) { + setTimeout(function () { + inst.dpDiv.css({ + top: currentMousePos.y, + left: currentMousePos.x + }); + }, 0); + } + }); + + // Check if to hide dates + $('#dateType').on('change', null, function() { + var dateType = $(this).val(); + if (dateType == 'all') { + $('#dateFields').addClass('emContentAreaHidden'); + } else { + $('#dateFields').removeClass('emContentAreaHidden'); + } + }); + + // Selection of performance list + $('#memberID').on('change', null, function() { + var memberID = $(this).val(); + $('#performanceSelect').html(mList[memberID]); + }); + + f_restartOnTabSelect(); + +{if:!checkPermission(#0#)} + // This must be a member used so start with their performances loaded + $('#performanceSelect').html(mList[{userMemberID}]); +{end:} + + + + + }); + + + diff --git a/views/admin/tickets/Report/promoSummary.html b/views/admin/tickets/Report/promoSummary.html new file mode 100644 index 0000000..2300fc4 --- /dev/null +++ b/views/admin/tickets/Report/promoSummary.html @@ -0,0 +1,129 @@ + + +{if:printOutput} + + + + {startScript:h} + + // Pass some reference parameters to JAVAScript + var baseSiteURL = '{baseURL}'; + var baseAdminURL = '{baseAdminURL}'; + var appAdminURL = '{appAdminURL}'; + var memberUser = '{MemberUser}'; + var debugEnabled = {if:option.admin_debug}true{else:}false{end:}; + + + + + + + + + + + + + +{end:} + + +
    + + Promo Summary Report + Report Produced: {reportDate} {reportTime} +
    +
    {reportNote}
    + + {if:havePromoList} + +
    + +
    + + + + + + + + + + + + + + + + + {foreach:promoList,p} + + + + + + + + + + + + + {end:} + + + + + + + + + + + + + +
    CodePromo{term.performance.cap}{term.ticket.cap}NameDate# SoldPer TicketDiscount
    {p.promo_name}{p.long_name}{p.performance_name}{p.ticket_name}{p.fname} {p.lname}{p.purchase_date}{p.count}{p.amountMoney}{p.sumMoney}
    Grand Totals     {totalCount} {totalDiscount}
    +
    +
    +
    + + {else:} +

    No results found.

    + {end:} + +
    +{startScript:h} + + $(function() { + + var PromoReportTable = $('#PromoReportTable').dataTable({ + "sScrollY": "600px", + "sScrollX": "100%", + "bPaginate": false, + "bLengthChange": false, + "bFilter": false, + "bSort": false, + "bInfo": false + }); + $(window).resize(function(){ + PromoReportTable.fnDraw(); + }); + + + f_restartOnTabSelect(); + + }); + + + + +{if:printOutput} + + +{end:} diff --git a/views/admin/tickets/Report/sales.html b/views/admin/tickets/Report/sales.html new file mode 100644 index 0000000..a50a573 --- /dev/null +++ b/views/admin/tickets/Report/sales.html @@ -0,0 +1,171 @@ + + +{if:printOutput} + + + + {startScript:h} + + // Pass some reference parameters to JAVAScript + var baseSiteURL = '{baseURL}'; + var baseAdminURL = '{baseAdminURL}'; + var appAdminURL = '{appAdminURL}'; + var memberUser = '{MemberUser}'; + var debugEnabled = {if:option.admin_debug}true{else:}false{end:}; + + + + + + + + + + + + + +{end:} + + + +
    + + Sales Report + Report Produced: {reportDate} {reportTime} +
    +
    {reportNote}
    + + {if:salesList} + +
    + + + + + {if:checkPermission(#0#)}{end:} + + + + + + + + + + + + + + + + + {foreach:salesList,r} + + {if:checkPermission(#0#)}{end:} + + + + + + + + + + + + + + + {end:} + + {if:checkPermission(#0#)}{end:} + + + + + + + + + + + + + + + + + {if:checkPermission(#0#)} + + {end:} + + + + + + + + + + + + + + + + {if:checkPermission(#0#)} + + {end:} + + + + + + + + + + + + + + +
    {term.prop.cap}{term.performance.cap}{term.section.cap}{term.ticket.cap}Add OnAdd On
    Sold
    DateTimeQuantitySoldClaimedPromoPaid
    {r.memb_name}{r.perf_name}{r.sect_name}{r.tick_name}{r.addon_name}{r.addon_sold}{r.date_date}{r.time_time}{r.time_quant}{r.time_sold}{r.time_claimed}{r.time_promo_money}{r.time_money}
                 
    Grand Totals       {totalQuant}{totalSold}{totalClaimed}{totalPromosMoney}{totalMoney}
             {percentSold}%{percentClaimed}%  
    +
    +
    + + {else:} +

    No results found.

    + {end:} + +
    +{startScript:h} + + $(function() { + + var SalesReportTable = $('#SalesReportTable').dataTable({ + "sScrollY": "600px", + "sScrollX": "100%", + "bPaginate": false, + "bLengthChange": false, + "bFilter": false, + "bSort": false, + "bInfo": false + }); + $(window).resize(function(){ + SalesReportTable.fnDraw(); + }); + + + f_restartOnTabSelect(); + + }); + + + + +{if:printOutput} + + +{end:} diff --git a/views/admin/tickets/Report/salesCSV.html b/views/admin/tickets/Report/salesCSV.html new file mode 100644 index 0000000..6909e23 --- /dev/null +++ b/views/admin/tickets/Report/salesCSV.html @@ -0,0 +1,10 @@ +"Sales Report","Report Produced: {reportDate}","{reportTime}","{reportNote}" + +{if:salesList}{if:checkPermission(#0#)}"{term.prop.cap}",{end:}"{term.performance.cap}","{term.section.cap}","{term.ticket.cap}","Add On","Add On Sold","Date","Time","Quantity","Sold","Claimed","Promo","Paid" +{foreach:salesList,r}{if:checkPermission(#0#)}"{r.memb_name}",{end:}"{r.perf_name}","{r.sect_name}","{r.tick_name}","{r.addon_name}","{r.addon_sold}","{r.date_date}","{r.time_time}","{r.time_quant}","{r.time_sold}","{r.time_claimed}","{r.time_promo}","{r.time_price}" +{end:} +"Grand Totals",{if:checkPermission(#0#)}"",{end:}"","","","","","","{totalQuant}","{totalSold}","{totalClaimed}","{totalPromos}","{totalPrice}" +"",{if:checkPermission(#0#)},""{end:},"","","","","","","","","{percentClaimed}%" +{else:} +No results found. +{end:} diff --git a/views/admin/tickets/Report/salesDetail.html b/views/admin/tickets/Report/salesDetail.html new file mode 100644 index 0000000..518c565 --- /dev/null +++ b/views/admin/tickets/Report/salesDetail.html @@ -0,0 +1,240 @@ + + +{if:printOutput} + + + + {startScript:h} + + // Pass some reference parameters to JAVAScript + var baseSiteURL = '{baseURL}'; + var baseAdminURL = '{baseAdminURL}'; + var appAdminURL = '{appAdminURL}'; + var memberUser = '{MemberUser}'; + var debugEnabled = {if:option.admin_debug}true{else:}false{end:}; + + + + + + + + + + + + + +{end:} + + + +
    + + Sales Detail Report + Report Produced: {reportDate} {reportTime} +
    +
    {reportNote}
    + + {if:salesList} + +
    + + + + + {if:checkPermission(#0#)}{end:} + + + + + + + + + + + + + + + {if:inclClaimDetail} + + {end:} + + + + + + + + + + + + + + + {foreach:salesList,r} + + {if:checkPermission(#0#)}{end:} + + + + + + + + + + + + + + + {if:inclClaimDetail} + + {end:} + + + + + + + + + + + + + {end:} + + {if:checkPermission(#0#)}{end:} + + + + + + + + + + + + + + + {if:inclClaimDetail} {end:} + + + + + + + + + + + + + + + {if:checkPermission(#0#)} + + {end:} + + + + + + + + + + + + + + {if:inclClaimDetail} {end:} + + + + + + + + + + + + + + + {if:checkPermission(#0#)} + + {end:} + + + + + + + + + + + + + + {if:inclClaimDetail} {end:} + + + + + + + + + + + + + +
    {term.prop.cap}{term.performance.cap}{term.section.cap}{term.ticket.cap}Add OnAdd On
    Sold
    DateTimeQuantitySoldClaimedPromoPaidOrder ID{term.voucher.cap}Scanned ByFirst NameLast NameAddressAddress 2CityStateZIP/PostalCountryE-MailPhone #
    {r.memb_name}{r.perf_name}{r.sect_name}{r.tick_name}{r.addon_name}{r.addon_sold}{r.date_date}{r.time_time}{r.time_quant}{r.time_sold}{r.time_claimed}{r.time_promo_money}{r.time_money}{r.order_id}{r.order_voucher_id}{r.order_claims}{r.order_fname:h}{r.order_lname:h}{r.order_addr1:h}{r.order_addr2:h}{r.order_city:h}{r.order_state:h}{r.order_zip}{r.order_country}{r.order_email}{r.order_phone}
                              
    Grand Totals       {totalQuant}{totalSold}{totalClaimed}{totalPromosMoney}{totalMoney}             
             {percentSold}%{percentClaimed}%               
    +
    +
    + + {else:} +

    No results found.

    + {end:} + +
    +{startScript:h} + + $(function() { + + var SalesReportTable = $('#SalesReportTable').dataTable({ + "sScrollY": "600px", + "sScrollX": "100%", + "bPaginate": false, + "bLengthChange": false, + "bFilter": false, + "bSort": false, + "bInfo": false + }); + $(window).resize(function(){ + SalesReportTable.fnDraw(); + }); + + + f_restartOnTabSelect(); + + }); + + + + +{if:printOutput} + + +{end:} diff --git a/views/admin/tickets/Report/salesDetailCSV.html b/views/admin/tickets/Report/salesDetailCSV.html new file mode 100644 index 0000000..edd58c6 --- /dev/null +++ b/views/admin/tickets/Report/salesDetailCSV.html @@ -0,0 +1,11 @@ +"Sales Report","Report Produced: {reportDate}","{reportTime}","{reportNote}" + +{if:salesList}{if:checkPermission(#0#)}"{term.prop.cap}",{end:}"{term.performance.cap}","{term.section.cap}","{term.ticket.cap}","Add On","Add On Sold","Date","Time","Quantity","Sold","Claimed","Promo","Paid","Order ID","{term.voucher.cap}",{if:inclClaimDetail}"Scanned By",{end:}"First Name","Last Name","Address","Address 2","City","State","ZIP/Postal","Country","E-Mail","Phone #" +{foreach:salesList,r}{if:checkPermission(#0#)}"{r.memb_name}",{end:}"{r.perf_name}","{r.sect_name}","{r.tick_name}","{r.addon_name}","{r.addon_sold}","{r.date_date}","{r.time_time}","{r.time_quant}","{r.time_sold}","{r.time_claimed}","{r.time_promo}","{r.time_price}","{r.order_id}","{r.order_voucher_id}",{if:inclClaimDetail}"{r.order_claims}",{end:}"{r.order_fname:h}","{r.order_lname:h}","{r.order_addr1:h}","{r.order_addr2:h}","{r.order_city:h}","{r.order_state:h}","{r.order_zip}","{r.order_country}","{r.order_email}","{r.order_phone}" +{end:} +"Grand Totals",{if:checkPermission(#0#)}"",{end:}"","","","","","","{totalQuant}","{totalSold}","{totalClaimed}","{totalPromos}","{totalPrice}" +"",{if:checkPermission(#0#)},""{end:},"","","","","","","","{percentClaimed}%" +{else:} +No results found. +{end:} + diff --git a/views/admin/tickets/Report/salesPackageTickets.html b/views/admin/tickets/Report/salesPackageTickets.html new file mode 100644 index 0000000..995b8cf --- /dev/null +++ b/views/admin/tickets/Report/salesPackageTickets.html @@ -0,0 +1,141 @@ + + +{if:printOutput} + + + + {startScript:h} + + // Pass some reference parameters to JAVAScript + var baseSiteURL = '{baseURL}'; + var baseAdminURL = '{baseAdminURL}'; + var appAdminURL = '{appAdminURL}'; + var memberUser = '{MemberUser}'; + var debugEnabled = {if:option.admin_debug}true{else:}false{end:}; + + + + + + + + + + + + + +{end:} + + + +
    + + Sales Detail Report + Report Produced: {reportDate} {reportTime} +
    +
    {reportNote}
    + + {if:salesList} + +
    + + + + + {if:checkPermission(#0#)}{end:} + + + + + + + + + + + {foreach:salesList,r} + + {if:checkPermission(#0#)}{end:} + + + + + + + + + {end:} + + {if:checkPermission(#0#)}{end:} + + + + + + + + + + + {if:checkPermission(#0#)} + + {end:} + + + + + + + + + + {if:checkPermission(#0#)} + + {end:} + + + + + + + + +
    {term.prop.cap}{term.performance.cap}{term.section.cap}{term.ticket.cap}SoldClaimedPaid
    {r.memb_name}{r.perf_name}{r.sect_name}{r.tick_name}{r.time_sold}{r.time_claimed}{r.time_money}
           
    Grand Totals   {totalSold}{totalClaimed}{totalMoney}
         {percentClaimed}% 
    +
    +
    + + {else:} +

    No results found.

    + {end:} + +
    +{startScript:h} + + $(function() { + + var SalesReportTable = $('#SalesReportTable').dataTable({ + "sScrollY": "600px", + "sScrollX": "100%", + "bPaginate": false, + "bLengthChange": false, + "bFilter": false, + "bSort": false, + "bInfo": false + }); + $(window).resize(function(){ + SalesReportTable.fnDraw(); + }); + + + f_restartOnTabSelect(); + + }); + + + + +{if:printOutput} + + +{end:} diff --git a/views/admin/tickets/Report/salesPackageTicketsCSV.html b/views/admin/tickets/Report/salesPackageTicketsCSV.html new file mode 100755 index 0000000..4080f0c --- /dev/null +++ b/views/admin/tickets/Report/salesPackageTicketsCSV.html @@ -0,0 +1,11 @@ +"Sales Report","Report Produced: {reportDate}","{reportTime}","{reportNote}" + +{if:salesList}{if:checkPermission(#0#)}"{term.prop.cap}",{end:}"{term.performance.cap}","{term.section.cap}","{term.ticket.cap}","Sold","Claimed","Paid" +{foreach:salesList,r}{if:checkPermission(#0#)}"{r.memb_name}",{end:}"{r.perf_name}","{r.sect_name}","{r.tick_name}","{r.time_sold}","{r.time_claimed}","{r.time_price}" +{end:} +"Grand Totals",{if:checkPermission(#0#)}"",{end:}"","","{totalSold}","{totalClaimed}","{totalPrice}" +"",{if:checkPermission(#0#)},""{end:},"","","{percentClaimed}%" +{else:} +No results found. +{end:} + diff --git a/views/admin/tickets/Report/salesReportSelection.html b/views/admin/tickets/Report/salesReportSelection.html new file mode 100644 index 0000000..dae504c --- /dev/null +++ b/views/admin/tickets/Report/salesReportSelection.html @@ -0,0 +1,259 @@ +
    + +
    + Sales Report Selection +
    + +
    + +
    + + +{if:!checkPermission(#0#)} + +{end:} +
    + + + +{if:checkPermission(#0#)} + + + + + + + + + + + + +{end:} + + + + + + + + + + + + + + + + + + + + + +
    Type of Report: + +
    {term.prop.cap}: + +
    Show inactive {term.prop.plur_cap}
    {term.performance.cap}: + Show inactive Categories +
    + (select a {term.prop.norm} first) +
    + Note: Hold "CTRL" key to select multiple, "SHIFT" to select a range, or drag across the ones you want to select. +
    Date Range: + + +    + From:    + Through:    + +
    Claimed {term.ticket.plur_cap} Only:
    {term.ticket.cap} Claim Detail:
    Output Type: + +
    +
    + +
    + +
    + +
    + +
    + +
    + + +
    + +{startScript:h} + + $(function() { + + var mList = new Array(); + {foreach:mList,m} + mList['100'+{m.id}] = ''; + mList['200'+{m.id}] = ''; + {end:} + + + /* + * Table operations + */ + + $('.salesReportTable').dataTable({ + "bPaginate": false, + "bLengthChange": false, + "bFilter": false, + "bSort": false, + "bInfo": false, + "bAutoWidth": false, + "bDestroy": true, + "aoColumns" : [ + { sWidth: '10%' }, + null + ] + }); + + /* + * AJAX form handling + */ + + $('#salesReportForm').ajaxForm({ + beforeSubmit: function(xhr) { + + // Check if this is going to be a csv + var outputType = $('#outputType').val(); + if (outputType == 'csv') { + + // Since this is a csv, open a new window with the desired URL and parameters rather than an ajax submit. + var url = appAdminURL + '&' + $('#salesReportForm').formSerialize(); + window.open(url, 'csvReport', 'toolbar=no,location=no,directories=no,menubar=no,scrollbars=no,width=100, height=10'); + return false; + } + }, + success: function(data) { + + var outputType = $('#outputType').val(); + + if (outputType == 'print') { + var w = window.open('', 'printReport', 'toolbar=no,location=no,directories=no,menubar=no,scrollbars=yes,width=1000, height=700, left=100, top=25'); + $(w.document.body).html(data); + } else { + f_replaceContents(data, $('#report_result_container')); + } + + return false; + } + }); + + // Block default form submission + $("#salesReportForm").submit(function (e) { + + var outputType = $('#outputType').val(); + + if (outputType == 'html') { + $('#report_result_container').html('
    Submitting, Please Wait...
    '); + } + + e.preventDefault(); + }); + + + var currentMousePos = { x: -1, y: -1 }; + $(document).mousemove(function(event) { + currentMousePos.x = event.pageX; + currentMousePos.y = event.pageY; + }); + + // Code to start datepicker for each date input + $("#startDateInput").datepicker({ + dateFormat: "mm/dd/yy", + dialog: [{maxDate}, false, false, [100,200]], + minDate: '{minDate}', + maxDate: '{maxDate}', + beforeShow: function (input, inst) { + setTimeout(function () { + inst.dpDiv.css({ + top: currentMousePos.y, + left: currentMousePos.x + }); + }, 0); + } + }); + $("#endDateInput").datepicker({ + dateFormat: "mm/dd/yy", + dialog: [{maxDate}, false, false, [200,300]], + minDate: '{minDate}', + maxDate: '{maxDate}', + beforeShow: function (input, inst) { + setTimeout(function () { + inst.dpDiv.css({ + top: currentMousePos.y, + left: currentMousePos.x + }); + }, 0); + } + }); + + // Check if to hide dates + $('#dateType').on('change', null, function() { + var dateType = $(this).val(); + if (dateType == 'all') { + $('#dateFields').addClass('emContentAreaHidden'); + } else { + $('#dateFields').removeClass('emContentAreaHidden'); + } + }); + + // Selection of performance list + function performanceList(e) { + var active = $('#showInactiveCats').is(':checked')?'200':'100'; + var memberID = $('#memberID').val(); + $('#performanceSelect').html(mList[active+memberID]); + } + $('#memberID').on('change', null, performanceList); + $('#showInactiveCats').on('change', null, performanceList); + + f_restartOnTabSelect(); + +{if:!checkPermission(#0#)} + // This must be a member used so start with their performances loaded + $('#performanceSelect').html(mList[{userMemberID}]); +{end:} + + + + + }); + + + diff --git a/views/admin/tickets/Section/delete.html b/views/admin/tickets/Section/delete.html new file mode 100644 index 0000000..e9bd6d0 --- /dev/null +++ b/views/admin/tickets/Section/delete.html @@ -0,0 +1,55 @@ +
    + +
    Delete this {term.section.cap}
    + +
    {sectionDetail.name}
    + +{if:checkPermission(#10#)} +
    + + +
    +{end:} + + {if:sectionDetail} +
    + + + + + + + + + +
    Delete {term.section.cap}: +

    Clicking "Confirm Delete" on the right will permanently delete this {term.section.norm}.

    +
    Name:{sectionDetail.name}
    + {else:} +

    No {term.section.plur} found.

    + {end:} + +
    + +
    +{startScript:h} + $(document).ready(function(){ + + $('#SectionDeleteTable').dataTable({ + "bPaginate": false, + "bLengthChange": false, + "bFilter": false, + "bSort": false, + "bInfo": false, + "bAutoWidth": false, + "bDestroy": true + }); + + f_restartOnTabSelect(); + + }); + diff --git a/views/admin/tickets/Section/detail.html b/views/admin/tickets/Section/detail.html new file mode 100644 index 0000000..3f40371 --- /dev/null +++ b/views/admin/tickets/Section/detail.html @@ -0,0 +1,75 @@ +
    + +
    {term.section.cap}: {sectionDetail.name}
    + +
    + + +
    + + {if:sectionDetail} +
    + + + + {if:sectionDetail.delete} + + + + + {end:} + + + + + + + + + +
    Delete {term.section.cap}: + {if:sectionDetail.deleteConfirmed} + {if:sectionDetail.deleteFailure} +

    FAILED:

    + Sorry, we are unable to delete the entry at this time.
    + {sectionDetail.reason:h} + {else:} +

    Deleted

    + {end:} + {else:} +
    +

    Clicking the button above will permanently delete this {term.section.norm}.

    + {end:} +
    {term.section.cap} Name:{sectionDetail.name}
    Description:{sectionDetail.descr:h}
    Image: + {if:sectionDetail.image} + + {else:}(none){end:} +
    {term.entrance.cap}:{sectionDetail.entrance}
    Sort Order:{sectionDetail.sort}
    + {else:} +

    No {term.section.plur} found.

    + {end:} + +
    + +
    +{startScript:h} + $(document).ready(function(){ + + $('#SectionDetailTable').dataTable({ + "bPaginate": false, + "bLengthChange": false, + "bFilter": false, + "bSort": false, + "bInfo": false, + "bAutoWidth": false, + "bDestroy": true + }); + + f_restartOnTabSelect(); + + }); + diff --git a/views/admin/tickets/Section/edit.html b/views/admin/tickets/Section/edit.html new file mode 100644 index 0000000..d56f881 --- /dev/null +++ b/views/admin/tickets/Section/edit.html @@ -0,0 +1,186 @@ +
    + +
    + {if:addingNewSection}Adding New {term.section.cap}{end:} + {if:editingSection}Editing {term.section.cap}{end:} +
    + +{if:checkPermission(#10#)} +
    + {if:addingNewSection} + + {else:} + + {end:} +
    +{end:} + +{if:formFail} +
    Not all fields were filled in correctly. Please try again.
    +{end:} + +
    + + {if:sectionDetail} + +

    Required fields in RED.

    + +
    + {if:addingNewSection} + + {else:} + + {end:} + + + + + +
    + + + + + {if:fieldRequired.name} + {if:fieldFail.name} + + + {if:fieldRequired.descr} + {if:fieldFail.descr} + + + {if:fieldRequired.image} + {if:fieldFail.image} + + + {if:fieldRequired.entrance} + {if:fieldFail.entrance} + + + {if:fieldRequired.sort} + {if:fieldFail.sort} + + +
    {else:}{end:}{term.section.cap} Name:{else:}{end:} + + {if:fieldFail.name}
    {fieldFail.name}{end:} +
    {else:}{end:}Description:{else:}{end:} + + {if:fieldFail.descr}
    {fieldFail.descr}{end:} +
    {else:}{end:}Image:{else:}{end:} + {if:sectionDetail.image} + +
    Delete this image: + {end:} + +
    Upload or replace the image: + {if:fieldFail.image}
    {fieldFail.image}{end:} +
    {else:}{end:}{term.entrance.cap}:{else:}{end:} + + Optional + {if:fieldFail.entrance}
    {fieldFail.entrance}{end:} +
    {else:}{end:}Output Order:{else:}{end:} + + {if:fieldFail.sort}
    {fieldFail.sort}{end:} +
    +
    + +
    + {if:addingNewSection} + + {end:} + {if:editingSection} + + {end:} +
    + +
    + + {else:} +

    No {term.section.norm} has been selected yet.

    +

    To edit a {term.section.norm}, first select it from the list of available {term.section.plur}. + {end:} + +

    + +
    + + +
    + +{startScript:h} + + $(function() { + + /* + * Table operations + */ + + $('.sectionEditTable').dataTable({ + "bPaginate": false, + "bLengthChange": false, + "bFilter": false, + "bSort": false, + "bInfo": false, + "bAutoWidth": false, + "bDestroy": true + }); + + /* + * AJAX form handling + */ + + $('#SectionForm').ajaxForm({ + success: function(data) { + {if:addingNewSection} + f_replaceContents(data, $('#Member_info_container')); + {end:} + {if:editingSection} + f_replaceContents(data, $('#Member_info_container')); + {end:} + return false; + } + }); + + // Block default form submission + $("form").submit(function (e) { + $('#sectionFormSubmit').html('
    Submitting, Please Wait...
    '); + e.preventDefault(); + }); + + // Remove the editors and store the data back in the textareas before the AJAX form submission + $('.emEditSubmit').click( function() { + f_removeCkeditor($("#descr")); + }); + + /* + * CKeditor actions + */ + + // Code to kick off CKEditor for specific fields + f_buildCkeditor($("#descr")); + f_buildCkeditor($("#notes")); + + // Remove the editors and store the data back in the textareas before the AJAX form submission + $('.emEditSubmit').click( function() { + f_removeCkeditor($("#descr")); + }); + + f_restartOnTabSelect(); + + }); + + \ No newline at end of file diff --git a/views/admin/tickets/Section/list.html b/views/admin/tickets/Section/list.html new file mode 100644 index 0000000..48b7eec --- /dev/null +++ b/views/admin/tickets/Section/list.html @@ -0,0 +1,127 @@ + +
    + +
    + + +
    + + Search {term.section.plur_cap}: (type any portion of a {term.section.norm} name) + + {if:sectionList} + +
    + + + + + + {foreach:sectionList,c} + + + + + {end:} + +
    Sort OrderName
    {c.sort}
    +
    + + {else:} +

    No {term.section.plur} listed.

    +

    + You will need at least one {term.section.norm} in order to sell {term.ticket.plur}. + You may, however, use a single generic {term.section.norm} such as "General Admission". +

    + {end:} + +
    +
    + + +
    +{startScript:h} + + // Sections Search + var sectionsSearchData = [ + {foreach:sectionList,c} + {label:'{c.name:h}', value:'{c.id}'}, + {end:} + ]; + + $(function() { + + var SectionListTable = $('#SectionListTable').dataTable({ + "sScrollY": "100px", + "scrollX": true, + "bScrollCollapse": true, + "bPaginate": false, + "bLengthChange": false, + "bFilter": false, + "bSort": true, + "bInfo": false, + "bAutoWidth": false, + "bDestroy": true, + "aoColumns" : [ + { sWidth: '80px' }, + null + ] + }); + $(window).resize(function(){ + SectionListTable.fnDraw(); + }); + + // Toggle length of table + var SectionListTableSmall = true; + var SectionListTableHeight = $('#SectionListTable_wrapper div.dataTables_scrollBody').height(); + $('#sectionListSizeChange').click(function() { + if (SectionListTableSmall) { + $('#SectionListTable_wrapper div.dataTables_scrollBody').height('auto'); + SectionListTableSmall = false; + $(this).html('Smaller Table'); + SectionListTable.fnSettings().oScroll.sY = '100%'; + SectionListTable.fnDraw(); + } else { + $('#SectionListTable_wrapper div.dataTables_scrollBody').height(SectionListTableHeight); + SectionListTableSmall = true; + $(this).html('Larger Table'); + SectionListTable.fnSettings().oScroll.sY = '100px'; + SectionListTable.fnDraw(); + } + }); + + // Close all local sliders + $('#Section_detail_container').hide(duration); + + $('.sectionListSelect').click(function(){ + $('#SectionListTable_wrapper div.dataTables_scrollBody').height(SectionListTableHeight); + SectionListTableSmall = true; + $('#sectionListSizeChange').html('Larger Table'); + SectionListTable.fnSettings().oScroll.sY = '100px'; + SectionListTable.fnDraw(); + f_loadAction('Section_detail', 'Section_detail_container', 'SectionID=' + $(this).attr('emSectionId') + '&tabList={tabList}'); + }); + + // Search Sections + $("#sectionsSearch").autocomplete({ + source: sectionsSearchData, + minLength: 1, + focus: function(event, ui) { + // Don't auto fill on focus + return false; + }, + select: function(event, ui) { + $("#sectionsSearch").attr({value: ui.item.label}); + f_loadAction('Section_detail', 'Section_detail_container', 'SectionID=' + ui.item.value + '&tabList={tabList}'); + return false; + } + }); + + f_restartOnTabSelect(); + + }); + + diff --git a/views/admin/tickets/Sold/claim.html b/views/admin/tickets/Sold/claim.html new file mode 100644 index 0000000..6e6a754 --- /dev/null +++ b/views/admin/tickets/Sold/claim.html @@ -0,0 +1,87 @@ +
    + + +
    + +
    +
    + + + + + + + + + + + + +
    {term.voucher.cap} #: +
    + Mark as claimed +
    {term.order.cap} #:
    +
    +
    + +
    +
    + +
    + +
    +{startScript:h} + $(document).ready(function(){ + + var ClaimTable = $('#ClaimTable').dataTable({ + "bPaginate": false, + "bLengthChange": false, + "bFilter": false, + "bSort": false, + "bInfo": false, + "bAutoWidth": false, + "bDestroy": true + + }); + + // Display selected Voucher - if Enter key is used + $('#SoldID').keydown( function (event) { + if(event.which == 13) { + var soldID = $('#SoldID').val(); + var doClaim = $('#doClaim').is(':checked'); + + $("#SoldID").focus(); + f_loadAction('Sold_detail', 'Voucher_detail_container', 'SoldID=' + soldID + '&doClaim=' + doClaim + '&tabList={tabList}'); + $('#Voucher_detail_container').removeClass('emContentAreaHidden'); + $("#SoldID").val(''); + } + }); + + // Display selected Order + $('#OrderID').keydown( function (event) { + if(event.which == 13) { + var orderID = $('#OrderID').val(); + $("#OrderID").focus(); + f_loadAction('Order_selected', 'Voucher_detail_container', 'OrderID=' + orderID + '&tabList={tabList}'); + $('#Voucher_detail_container').removeClass('emContentAreaHidden'); + $("#OrderID").val(''); + } + }); + + $("#SoldID").focus(); + + f_restartOnTabSelect(); + + $('input').keydown( function (event) { + $('#scanVoucherIdArea').removeClass('scanVoucherResultNone'); + $('#scanVoucherIdArea').removeClass('scanVoucherResultClaimed'); + $('#scanVoucherIdArea').removeClass('scanVoucherResultUsed'); + }); + + + if ({orderID} > 0) { + f_loadAction('Order_selected', 'Voucher_detail_container', 'OrderID=' + {orderID} + '&tabList={tabList}'); + } + + }); + diff --git a/views/admin/tickets/Sold/detail.html b/views/admin/tickets/Sold/detail.html new file mode 100644 index 0000000..e57734e --- /dev/null +++ b/views/admin/tickets/Sold/detail.html @@ -0,0 +1,278 @@ +
    + +
    {soldDetail.name}
    + +{if:haveProblem} +

    We're sorry, we had a problem with your request:

    +
      + {foreach:problem,r} +
    • {r:h}
    • + {end:} +
    +
    +{end:} + + + {if:soldDetail} + +
    + + + + + + + + + +
    + +
    + + + + {if:soldDetail.delete} + + + + + {end:} + {if:markedAsClaimed} + + {end:} + + + + + + + {if:soldDetail.is_package.value} + + {else:} + {if:soldDetail.ticket_package} + + + + + {else:} + Uses available + {end:} + + + + {if:soldDetail.unlimited_use.value} + + {else:} + + {end:} + + + + + + + + + + + {if:soldDetail.date_specific.value} + + {else:} + + {end:} + {if:soldDetail.time_specific.value} + + {else:} + + {end:} + + {else:} + + + + + {else:} + Uses available + {end:} + + + + {if:soldDetail.unlimited_use.value} + + {else:} + + {end:} + + + + + + + + {if:soldDetail.assigned.value} + + {end:} + + + + + {if:soldDetail.date_specific.value} + + {else:} + + + {end:} + {if:soldDetail.time_specific.value} + + {else:} + + {end:} + + + + {end:} + {end:} + +
    Delete {term.ticket.cap} Sold: + {if:soldDetail.deleteConfirmed} + {if:soldDetail.deleteFailure} +

    FAILED:

    + Sorry, we are unable to delete the entry at this time.
    + {soldDetail.reason:h} + {else:} +

    Deleted

    + {end:} + {else:} +
    +

    Clicking the button above will permanently delete this {term.ticket.norm} sold.

    + {end:} +
    Marked as Claimed
    {term.voucher.cap} #:{soldDetail.id}
    {term.order.cap} #:{soldDetail.ticket_order}
    Type + {if:soldDetail.is_package.value} + Package +

    + + + {foreach:packageDetail,p} + + + + + + + {end:} +
    Ticket NameNumber of UsesTimes ClaimedAvailable
    {p.ticket_name}{p.numb_uses} + {p.numb_claimed} + + {if:p.fullyClaimedAlert} + FULLY CLAIMED! + {else:} + {p.remaining} + {end:} +
    +

    + {else:} + {if:soldDetail.ticket_package} + Package {term.ticket.cap} + {else:} + {term.ticket.cap} + {end:} + {end:} +
    Price Paid:{soldDetail.price_paid}
    {term.voucher.cap} Status: + + {if:fullyClaimedAlert} + FULLY CLAIMED!
    Number of Uses:Unlimited use.
    Number of Uses:{soldDetail.numb_uses}
    Number of Times Claimed: + {soldDetail.numb_claimed} + {if:soldDetail.fullyClaimedAlert} +   FULLY CLAIMED! + {end:} +
    {term.prop.cap}:{soldDetail.member_name}
    {term.entrance.cap}:{soldDetail.entrance_name}
    {term.performance.cap}:{soldDetail.performance_name}
    {term.section.cap}:{soldDetail.section_name}
    {term.ticket.cap}:{soldDetail.ticket_name}
    Specific date only:{soldDetail.date_specific.name}
    {term.ticket.cap} Date:{soldDetail.ticket_date.date}
    Dates useable:{soldDetail.start_date.date} through {soldDetail.end_date.date}
    {term.ticket.cap} Time:{soldDetail.ticket_time.time}
    {term.ticket.cap} Time:Use any time of the day.
    {term.voucher.cap} Status: + + {if:fullyClaimedAlert} + FULLY CLAIMED!
    Number of Uses:Unlimited use.
    Number of Uses:{soldDetail.numb_uses}
    Number of Times Claimed: + {soldDetail.numb_claimed} + {if:soldDetail.fullyClaimedAlert} +   FULLY CLAIMED! + {end:} +
    {term.prop.cap}:{soldDetail.member_name}
    {term.entrance.cap}:{soldDetail.entrance_name}
    Assigned from other {term.prop.norm}:{soldDetail.assigned.name}
    Assigned from:{soldDetail.assigned_from_name}
    {term.performance.cap}:{soldDetail.performance_name}
    {term.section.cap}:{soldDetail.section_name}
    {term.ticket.cap}:{soldDetail.ticket_name}
    Specific date only:{soldDetail.date_specific.name}
    {term.ticket.cap} Date:{soldDetail.ticket_date.date}
    Dates useable:{soldDetail.start_date.date} through {soldDetail.end_date.date}
    Likely use date:{soldDetail.likely_date.date}
    {term.ticket.cap} Time:{soldDetail.ticket_time.time}
    {term.ticket.cap} Time:Use any time of the day.
    Price Paid:{soldDetail.price_paid}
    + {else:} +

    No sold {term.ticket.plur} detail available.

    + {end:} + +
    + +
    +{startScript:h} + $(document).ready(function(){ + + $('#SoldDetailTable').dataTable({ + "bPaginate": false, + "bLengthChange": false, + "bFilter": false, + "bSort": false, + "bInfo": false, + "bAutoWidth": false, + "bDestroy": true + }); + + // Mark as claimed + $('#VoucherClaim').on('click', null, function() { + + $('#ClaimDateTD').html('
    Storing, Please Wait...
    '); + var voucherID = $(this).attr('voucherID'); + + $.ajax({ + url: "{adminURL}&Action=Sold_claimVoucher&VoucherID=" + voucherID, + success: function(data) { + + var code = data.substring(0, 1); + var time = data.substring(2); + + switch (code) { + + case 's': + break; + case 'c': + time = time + ' - NOTE: This voucher had already been claimed'; + break; + case 'f': + time = 'Unable to mark voucher as claimed. Is this a valid voucher?'; + break; + } + + $('#ClaimDateTD').html(time); + + } , + error: function() { + alert('No response. Unable to mark this voucher as claimed at this time.\n'); + } + }); + + }); + + f_restartOnTabSelect(); + + {if:alreadyClaimedAlert} + $('#scanVoucherIdArea').addClass('scanVoucherResultUsed'); + {else:} + {if:markedAsClaimed} + $('#scanVoucherIdArea').addClass('scanVoucherResultClaimed'); + {else:} + $('#scanVoucherIdArea').addClass('scanVoucherResultNone'); + {end:} + {end:} + + }); + diff --git a/views/admin/tickets/Sold/list.html b/views/admin/tickets/Sold/list.html new file mode 100644 index 0000000..3218df0 --- /dev/null +++ b/views/admin/tickets/Sold/list.html @@ -0,0 +1,113 @@ + +
    + + {if:soldList} + +
    + + + + + + + + + + + + + + + {foreach:soldList,c} + {if:c.is_package.value} + + + + + + + + + + + {else:} + + + {if:c.ticket_package} + + {else:} + + {end:} + + + + + + + + {end:} + {end:} + +
    Voucher #TypeUsesClaimed{term.performance.cap}{term.entrance.cap}TicketDate
    Package  {c.performance_name:h}{c.entrance_name:h}{c.ticket_name:h} 
    Package {term.ticket.cap}{term.ticket.cap}{c.numb_uses}{c.numb_claimed}{c.performance_name:h}{c.entrance_name:h}{c.ticket_name:h} + + {if:soldDetail.date_specific.value} + {c.ticket_date.date} + {else:} + {c.start_date.date} through {c.end_date.date} + {end:} +
    +
    + + {else:} +

    No Purchased {term.ticket.plur} listed.

    + {end:} + +
    +
    + + +
    +{startScript:h} + + $(function() { + + // Note, not scrolling this table - Show everything + var SoldListTable = $('#SoldListTable').dataTable({ + "bScrollCollapse": true, + "scrollX": true, + "bPaginate": false, + "bLengthChange": false, + "bFilter": false, + "bSort": false, + "bInfo": false, + "bAutoWidth": false, + "bDestroy": true, + "aoColumns" : [ + { "sWidth": "5%", "sType": "numeric" }, + null, + null, + null, + null, + null, + null, + null + ] + }); + $(window).resize(function(){ + SoldListTable.fnDraw(); + }); + + // Close all local sliders + $('#Sold_detail_container').hide(duration); + + $('.soldListSelect').click(function(){ + f_loadAction('Sold_selected', 'Sold_detail_container', 'SoldID=' + $(this).attr('emSoldId') + '&tabList={tabList}&checkBypass=true'); + }); + + + + f_restartOnTabSelect(); + + }); + + diff --git a/views/admin/tickets/Sold/selected.html b/views/admin/tickets/Sold/selected.html new file mode 100644 index 0000000..b86f13d --- /dev/null +++ b/views/admin/tickets/Sold/selected.html @@ -0,0 +1,56 @@ +
    + +
    +
    {term.voucher.cap} ID: {soldDetail.id}
    +
    + +
    + + +
    +{if:checkPermission(#30#)} + + +{end:} + +
    + + +
    +
    + +
    + +
    + + +{startScript:h} + + // jQuery Section + $(document).ready(function(){ + + // Start with ticket sold detail loaded + f_loadAction('Sold_detail', 'Sold_info_container', "tabList={tabList}&soldID={soldDetail.id}&checkBypass=true"); + + f_restartOnTabSelect(); + + }); + + diff --git a/views/admin/tickets/Ticket/addGetMember.html b/views/admin/tickets/Ticket/addGetMember.html new file mode 100644 index 0000000..3fd53ec --- /dev/null +++ b/views/admin/tickets/Ticket/addGetMember.html @@ -0,0 +1,90 @@ +
    + +
    + Adding New {term.ticket.cap} +
    + +
    + +
    + +
    + +
    + + +
    + + + + + + + + +
    Start by selecting {term.prop.cap}: + + {if:fieldFail.performance}
    {fieldFail.performance}{end:} +
    +
    + +
    + +
    + +
    + +
    + +
    + +
    + +{startScript:h} + + $(function() { + + /* + * Table operations + */ + + $('.ticketEditTable').dataTable({ + "bPaginate": false, + "bLengthChange": false, + "bFilter": false, + "bSort": false, + "bInfo": false, + "bAutoWidth": false, + "bDestroy": true + }); + + /* + * AJAX form handling + */ + + $('#ticketForm').ajaxForm({ + success: function(data) { + f_replaceContents(data, $('#Ticket_detail_container')); + return false; + } + }); + + // Block default form submission + $("form").submit(function (e) { + $('#ticketFormSubmit').html('
    Submitting, Please Wait...
    '); + e.preventDefault(); + }); + + f_restartOnTabSelect(); + + }); + + + diff --git a/views/admin/tickets/Ticket/delete.html b/views/admin/tickets/Ticket/delete.html new file mode 100644 index 0000000..27bb740 --- /dev/null +++ b/views/admin/tickets/Ticket/delete.html @@ -0,0 +1,140 @@ +
    + +
    Delete this {term.ticket.cap}
    + +
    {ticketDetail.name}
    + +
    + + +
    + + {if:ticketDetail} +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {if:checkPermission(#0#)} + + {end:} + + + + + + + + + + + + + +
    Delete {term.ticket.cap}: +

    Clicking "Confirm Delete" on the right will permanently delete this {term.ticket.norm}.

    +
    {term.prop.cap}{ticketDetail.member_name:h}
    {term.ticket.cap} Type:{ticketDetail.ticket_type.name}
    {term.ticket.cap} Name:{ticketDetail.name}
    {term.ticket.cap} Title:{ticketDetail.title}
    Active:{ticketDetail.active.name}
    Purchase by Admin Only:{ticketDetail.admin_only.name}
    {term.performance.cap}:{ticketDetail.performance}
    {term.section.cap}:{ticketDetail.section}
    Dates available for sale: + {if:ticketDetail.for_sale_start_date.date} + May be purchased starting on {ticketDetail.for_sale_start_date.date}
    + {else:} + {if:ticketDetail.for_sale_end_date.date} + {else:} + No purchase date restrictions + {end:} + {end:} + {if:ticketDetail.for_sale_end_date.date} + May be purchased through {ticketDetail.for_sale_end_date.date}
    + {end:} +
    Date: + {if:ticketDetail.date_specific.value} + Dates determined by inventory. + {else:} + {if:ticketDetail.start_date.date} + May be used from {ticketDetail.start_date.date} through {ticketDetail.end_date.date} + {else:} + May be used on any date. + {end:} + {end:} +
    Time: + {if:ticketDetail.time_specific.value} + {ticketDetail.ticket_time.time} + {else:} + No time specified. + {end:} +
    Uses per {term.ticket.cap}: + {if:ticketDetail.unlimited_use.value} + May be used an unlimited number of times. + {else:} + {ticketDetail.uses} + {end:} +
    Quantity: + {if:ticketDetail.unlimited_quant.value} + Unlimited + {else:} + {ticketDetail.quant} + {end:} +
    Consignment Type:{ticketDetail.consignment_type.name}
    Always show in cart:{ticketDetail.cart_sticky.name}
    If checked, will force this to show in the cart regardless of quantity selected.
    Show on Start Page:{ticketDetail.show_on_start.name}
    If checked (Yes), will display this ticket on the start page under the category.
    User selection of an Add-On Required:{ticketDetail.addon_required.name}
    Price:{ticketDetail.price}
    Description:{ticketDetail.descr:h}
    Image: + {if:ticketDetail.image} + + {else:}(none){end:} +
    Text for {term.voucher.cap}:{ticketDetail.voucher_text:h}
    Alternate text for left end of {term.voucher.cap}:{ticketDetail.voucher_leftend_text:h}
    {term.voucher.cap} Type:{ticketDetail.voucher_type.name}
    Sort Order:{ticketDetail.sort}
    + {else:} +

    No {term.ticket.plur} found.

    + {end:} + +
    + +
    +{startScript:h} + $(document).ready(function(){ + + $('#TicketDeleteTable').dataTable({ + "bPaginate": false, + "bLengthChange": false, + "bFilter": false, + "bSort": false, + "bInfo": false, + "bAutoWidth": false, + "bDestroy": true + }); + + f_restartOnTabSelect(); + + }); + diff --git a/views/admin/tickets/Ticket/detail.html b/views/admin/tickets/Ticket/detail.html new file mode 100644 index 0000000..047d399 --- /dev/null +++ b/views/admin/tickets/Ticket/detail.html @@ -0,0 +1,200 @@ +
    + + + +
    + + +
    + + {if:ticketDetail} +
    + + + + {if:ticketDetail.delete} + + + + + {end:} + + + + {if:option.packages} + + + + + {end:} + + + + + + + + + + + + + + + + + + + + + + + + + + {if:checkPermission(#0#)} + + {end:} + + + + + + + + + + + + + + +
    Delete {term.ticket.cap}: + {if:ticketDetail.deleteConfirmed} + {if:ticketDetail.deleteFailure} +

    FAILED:

    + Sorry, we are unable to delete the entry at this time.
    + {ticketDetail.reason:h} + {else:} +

    Deleted

    + {end:} + {else:} +
    +

    Clicking the button above will permanently delete this {term.ticket.norm}.

    + {end:} +
    {term.prop.cap}{ticketDetail.member_name:h}
    {term.ticket.cap} Name:{ticketDetail.name}ID: {ticketDetail.id}
    {term.ticket.cap} Title:{ticketDetail.title:h}
    {term.ticket.cap} Type: +

    {ticketDetail.ticket_type.name}

    + {if:isPackage} +

    Package Tickets

    + + + + + + {foreach:ticketPackage,y} + + + + + + + + + {end:} + +
    QuantSeparate VoucherLocationCategoryTicketActive
    {y.quant}{y.separate_voucher.name}{y.member_name:h}{y.performance_name:h}{y.title:h}{if:y.active}Yes{else:}No{end:}
    + {end:} +
    Active:{ticketDetail.active.name}
    Purchase by Admin Only:{ticketDetail.admin_only.name}
    {term.performance.cap}:{ticketDetail.performance:h}
    {term.section.cap}:{ticketDetail.section}
    Dates available for sale: + {if:ticketDetail.for_sale_start_date.date} + May be purchased starting on {ticketDetail.for_sale_start_date.date}
    + {else:} + {if:ticketDetail.for_sale_end_date.date} + {else:} + No purchase date restrictions + {end:} + {end:} + {if:ticketDetail.for_sale_end_date.date} + May be purchased through {ticketDetail.for_sale_end_date.date}
    + {end:} +
    Date: + {if:ticketDetail.date_specific.value} + Dates determined by inventory. +

    + Days of week: {foreach:ticketDetail.days_of_week.names,s}{s}  {end:} + {if:ticketDetail.start_date.date} +
    Inventory will be created from {ticketDetail.start_date.date} through {ticketDetail.end_date.date} + {end:} +

    + + {else:} + {if:ticketDetail.start_date.date} + May be used from {ticketDetail.start_date.date} through {ticketDetail.end_date.date} + {else:} + May be used on any date. + {end:} + {end:} +
    Time: + {if:ticketDetail.time_specific.value} + {ticketDetail.ticket_time.time} + {else:} + No time specified. + {end:} +
    Uses per {term.ticket.cap}: + {if:ticketDetail.unlimited_use.value} + May be used an unlimited number of times. + {else:} + {ticketDetail.uses} + {end:} +
    Quantity: + {if:ticketDetail.unlimited_quant.value} + Unlimited + {else:} + {ticketDetail.quant} + {end:} +
    Consignment Type:{ticketDetail.consignment_type.name}
    Always show in cart (Sticky):{ticketDetail.cart_sticky.name}
    If checked (Yes), will force this to show in the cart regardless of quantity selected.
    Show on Start Page:{ticketDetail.show_on_start.name}
    If checked (Yes), will display this ticket on the start page under the category.
    User selection of an Add-On Required:{ticketDetail.addon_required.name}
    Price:{ticketDetail.price}
    Description:{ticketDetail.descr:h}
    Image: + {if:ticketDetail.image} + + {else:}(none){end:} +
    Text for {term.voucher.cap}:{ticketDetail.voucher_text:h}
    Alternate text for left end of {term.voucher.cap}:{ticketDetail.voucher_leftend_text:h}
    {term.voucher.cap} Type:{ticketDetail.voucher_type.name}
    Sort Order:{ticketDetail.sort}
    Test VoucherPrint test {term.voucher.plur}
    + {else:} +

    No {term.ticket.plur} found.

    + {end:} + +
    + +
    +{startScript:h} + $(document).ready(function(){ + + $('#TicketDetailTable').dataTable({ + "bPaginate": false, + "bLengthChange": false, + "bFilter": false, + "bSort": false, + "bInfo": false, + "bAutoWidth": false, + "bDestroy": true + }); + + f_restartOnTabSelect(); + + // Print test vouchers + $('.voucherPrint').click(function(){ + var orderID = $(this).attr('emOrderID'); + var orderVerify = $(this).attr('emOrderVerify'); + var voucherWindow = window.open('{adminURL}&Action=Ticket_printSampleVoucher&testTicket={ticketDetail.id}', + "voucherPrint", + "height=750,width=600,menubar=yes,toolbar=yes,alwaysRaised=yes,menu" + ); + voucherWindow.focus(); + voucherWindow.print(); + return false; + }); + + + }); + diff --git a/views/admin/tickets/Ticket/edit.html b/views/admin/tickets/Ticket/edit.html new file mode 100644 index 0000000..48c2045 --- /dev/null +++ b/views/admin/tickets/Ticket/edit.html @@ -0,0 +1,663 @@ +
    + +
    + {if:addingNewTicket}Adding New {term.ticket.cap}{end:} + {if:editingTicket}Editing {term.ticket.cap}{end:} +
    + +
    +{if:addingNewTicket} + +{else:} + +{end:} +
    + +{if:formFail} +
    Not all fields were filled in correctly. Please try again.
    +{end:} + +
    + + {if:ticketDetail} + +

    Required fields in RED.

    + +
    + {if:addingNewTicket} + + {else:} + + {end:} + + + + + +
    + + + + + + + + + {if:addingNewTicket} + {if:fieldRequired.performance} + {if:fieldFail.performance} + {else:} + + + {end:} + + + {if:fieldRequired.name} + {if:fieldFail.name} + + + {if:fieldRequired.title} + {if:fieldFail.title} + + {if:option.packages} + + {if:fieldRequired.ticket_type} + {if:fieldFail.ticket_type} + + {end:} + + + + + + + + + + {if:fieldRequired.section} + {if:fieldFail.section} + + + + + + + + {if:fieldFail.date_specific} + + + + + + + + + + + + + + + {if:fieldRequired.consignment_type} + {if:fieldFail.consignment_type} + + {if:checkPermission(#0#)} + + + {if:fieldFail.cart_sticky} + + {end:} + + + {if:fieldFail.show_on_start} + + + + {if:fieldFail.addon_required} + + + {if:fieldRequired.price} + {if:fieldFail.price} + + + {if:fieldRequired.descr} + {if:fieldFail.descr} + + + {if:fieldRequired.image} + {if:fieldFail.image} + + + {if:fieldRequired.voucher_text} + {if:fieldFail.voucher_test} + + + {if:fieldRequired.voucher_leftend_text} + {if:fieldFail.voucher_test} + + + {if:fieldRequired.voucher_type} + {if:fieldFail.voucher_type} + + + {if:fieldRequired.sort} + {if:fieldFail.sort} + + +
    {term.prop.cap}{memberDetail.name}
    {else:}{end:}{term.performance.cap}:{else:}{end:} + + {if:fieldFail.performance}
    {fieldFail.performance}{end:} +
    {term.performance.cap}{ticketDetail.performance.name:h}
    {else:}{end:}{term.ticket.cap} Name:{else:}{end:} +
    (for internal use) + {if:fieldFail.name}
    {fieldFail.name}{end:} +
    {else:}{end:}{term.ticket.cap} Title:{else:}{end:} +
    (for display to customers) + {if:fieldFail.title}
    {fieldFail.title}{end:} +
    {else:}{end:}{term.ticket.cap} Type:{else:}{end:} + + {if:fieldFail.ticket_type}
    {fieldFail.ticket_type}{end:} +
    +

    Package Tickets

    +

    + + +

    + + + + + + {foreach:ticketPackage,y} + + + + + + + + + + {end:} + +
     QuantSeparate VoucherLocationCategoryTicketActive
    + {if:y.separate_voucher.value} + + {else:} + + {end:} + {y.member_name:h}{y.performance_name:h}{y.title:h}{if:y.active}Yes{else:}No{end:}
    +
    +
    Active: + {if:ticketDetail.active.value} + + {else:} + + {end:} + {if:!option.packages} + + {end:} +
    Purchase by Admin Only: + {if:ticketDetail.admin_only.value} + + {else:} + + {end:} +
    {else:}{end:}{term.ticket.cap} Section:{else:}{end:} + + {if:fieldFail.section}
    {fieldFail.section}{end:} +
    Dates available for sale: +
    + Set range of dates during which a user may purchase these {term.ticket.plur}.
    + Clear either or both fields if no start or end date is desired. + + + {if:fieldRequired.for_sale_start_date} + {if:fieldFail.for_sale_start_date} + + + {if:fieldRequired.for_sale_end_date} + {if:fieldFail.for_sale_end_date} + +
    {else:}{end:}Start Date:{else:}{end:} + {if:addingNewTicket} +
    + {else:} + + {end:} + This is the first date on which these {term.ticket.plur} may be purchased. +
    {else:}{end:}End Date:{else:}{end:} + {if:addingNewTicket} +
    + {else:} + + {end:} + This is the last date on which these {term.ticket.plur} may be purchaced. +
    +
    +
    Specified Dates:{else:}{end:} + {if:ticketDetail.date_specific.value} + + {else:} + + {end:} + Check if {term.ticket.plur} are for specific dates as determined by inventory.
    +
    +

    + Select days of the week for default inventory.
    + {foreach:ticketDetail.days_of_week.bitmap,s} + {if:s.default} + {s.name} + {else:} + {s.name} + {end:} + {end:} +

    +
    +
    + Set a range of dates during which this {term.ticket.norm} may be used. + + + {if:fieldRequired.start_date} + {if:fieldFail.start_date} + + + {if:fieldRequired.end_date} + {if:fieldFail.end_date} + +
    {else:}{end:}Start Date:{else:}{end:} + + {if:addingNewTicket} +
    + {else:} + + {end:} + This is the first date on which these {term.ticket.plur} can be used. +
    {else:}{end:}End Date:{else:}{end:} + {if:addingNewTicket} +
    + {else:} + + {end:} + This is the last date on which these {term.ticket.plur} can be used. +
    +
    + {if:fieldFail.date_specific}
    {fieldFail.date_specific}{end:} +
    Specified Time: + {if:ticketDetail.time_specific.value} + + {else:} + + {end:} + Check if there is a specific time for this {term.ticket.norm}. +
    + + {if:fieldFail.ticket_time}{else:}{end:} + + + +
    Time: + +
    +
    +
    Uses per {term.ticket.cap}: + {if:ticketDetail.unlimited_use.value} + + {else:} + + {end:} + Check if this {term.ticket.norm} can be scanned/claimed an unlimited number of times. +
    + + {if:fieldFail.unlimited_use}{else:}{end:} + + + +
    Number of Uses: + +
    +
    +
    Quantity: + {if:ticketDetail.unlimited_quant.value} + + {else:} + + {end:} + Check if the number of {term.ticket.plur} available is unlimited. +
    + + {if:fieldFail.quant}{else:}{end:} + + + +
    Quantity: + +
    Number of these {term.ticket.plur} normally available. Used as default when creating inventory. +
    +
    +
    {else:}{end:}Consignment Type:{else:}{end:} + + {if:fieldFail.consignment_type}
    {fieldFail.consignment_type}{end:} +
    Always show in cart:{else:}{end:} + {if:ticketDetail.cart_sticky.value} + + {else:} + + {end:} + {if:fieldFail.cart_sticky}
    {fieldFail.cart_sticky}{end:} +
    Show Ticket on Start Page:{else:}{end:} + {if:ticketDetail.show_on_start.value} + + {else:} + + {end:} + {if:fieldFail.show_on_start}
    {fieldFail.show_on_start}{end:} +
    User Selection of Add-On is Required:{else:}{end:} + {if:ticketDetail.addon_required.value} + + {else:} + + {end:} + {if:fieldFail.addon_required}
    {fieldFail.addon_required}{end:} +

    + Select this option if you need the user to select at least one add-on at some cost + for this ticket to be included in the cart selection. +

    +
    {else:}{end:}Price:{else:}{end:} + + {if:fieldFail.price}
    {fieldFail.price}{end:} +
    {else:}{end:}Description:{else:}{end:} + + {if:fieldFail.descr}
    {fieldFail.descr}{end:} +
    {else:}{end:}Image:{else:}{end:} + {if:ticketDetail.image} + +
    Delete this image: + {end:} + +
    Upload or replace the image: + {if:fieldFail.image}
    {fieldFail.image}{end:} +
    {else:}{end:}Text for {term.voucher.cap}:{else:}{end:} +
    + Please be brief to conserve space on {term.voucher.plur}.
    + There is no formatting permitted for this field. + {if:fieldFail.voucher_text}
    {fieldFail.voucher_text}{end:} +
    {else:}{end:}Alternate text for left end of {term.voucher.cap}:{else:}{end:} +
    + Please be brief to conserve space on {term.voucher.plur}.
    + There is no formatting permitted for this field. KEEP SHORT! + {if:fieldFail.voucher_leftend_text}
    {fieldFail.voucher_leftend_text}{end:} +
    {else:}{end:}{term.voucher.cap} Type:{else:}{end:} + + {if:fieldFail.voucher_type}
    {fieldFail.voucher_type}{end:} +
    {else:}{end:}Output Order:{else:}{end:} + + {if:fieldFail.sort}
    {fieldFail.sort}{end:} +
    +
    + +
    + {if:addingNewTicket} + + {end:} + {if:editingTicket} + + {end:} +
    + +
    + + {else:} +

    No {term.ticket.norm} has been selected yet.

    +

    To edit a {term.ticket.norm}, first select it from the list of available {term.ticket.plur}. + {end:} + +

    + +
    + + +
    + +{startScript:h} + + $(function() { + + /* + * Table operations + */ + + $('.ticketEditTable').dataTable({ + "bPaginate": false, + "bLengthChange": false, + "bFilter": false, + "bSort": false, + "bInfo": false, + "bAutoWidth": false, + "bDestroy": true + }); + + /* + * AJAX form handling + */ + + $('#ticketForm').ajaxForm({ + success: function(data) { + {if:addingNewTicket} + var container = $('#Ticket_detail_container'); + f_replaceContents(data, container); + {end:} + {if:editingTicket} + var container = $('#Ticket_info_container'); + f_replaceContents(data, container); + {end:} + return false; + } + }); + + // Block default form submission + $("form").submit(function (e) { + $('#ticketFormSubmit').html('
    Submitting, Please Wait...
    '); + e.preventDefault(); + }); + + /* + * CKeditor actions + */ + + // Code to kick off CKEditor for specific fields + f_buildCkeditor($("#descr")); + + // Remove the editors and store the data back in the textareas before the AJAX form submission + $('.emEditSubmit').click( function() { + f_removeCkeditor($("#descr")); + }); + + f_restartOnTabSelect(); + + // Handle show/hide for check fields with additional form fields + function checkField(name, reverse, opposite = false) { + f = $("input[name='" + name + "']"); + if (!reverse) { + if (f.is(':checked')) { + $('#' + name).show(); + } else { + $('#' + name).hide(); + } + } else { + if (f.is(':checked')) { + $('#' + name).hide(); + } else { + $('#' + name).show(); + } + } + + // check for opposite selection + if (opposite) { + if (reverse) { + if (f.is(':checked')) { + $('#' + opposite).show(); + } else { + $('#' + opposite).hide(); + } + } else { + if (f.is(':checked')) { + $('#' + opposite).hide(); + } else { + $('#' + opposite).show(); + } + } + + } + } + + $('.fieldSelect').change( function() { + name = $(this).attr('name'); + checkField(name, false); + }); + $('.fieldSelectRev').change( function() { + name = $(this).attr('name'); + checkField(name, true); + }); + + // Special case for date specific + $('.fieldSelectDateSpecific').change( function() { + checkField('date_specific', false); + }); + + // Setup additional form field show/hide when loading + checkField('section_specific', false); + checkField('date_specific', false); + checkField('time_specific', false); + checkField('unlimited_use', true); + checkField('unlimited_quant', true); + + // Code to start datepicker for each date input + $("#saleStartDateInput").datepicker({ + dateFormat: "mm/dd/yy", + minDate: '{ticketDetail.for_sale_start_date.date_list.min}', + maxDate: '{ticketDetail.for_sale_start_date.date_list.max}' + }); + $("#saleEndDateInput").datepicker({ + dateFormat: "mm/dd/yy", + minDate: '{ticketDetail.for_sale_end_date.date_list.min}', + maxDate: '{ticketDetail.for_sale_end_date.date_list.max}' + }); + $("#startDateInput").datepicker({ + dateFormat: "mm/dd/yy", + minDate: '{ticketDetail.start_date.date_list.min}', + maxDate: '{ticketDetail.start_date.date_list.max}' + }); + $("#endDateInput").datepicker({ + dateFormat: "mm/dd/yy", + minDate: '{ticketDetail.end_date.date_list.min}', + maxDate: '{ticketDetail.end_date.date_list.max}' + }); + + // Check for ticket_type being package and show the package table. + if ($('#ticket_type').val() == 20) { + $('#ticketPackageContents').show(); + } else { + $('#ticketPackageContents').hide(); + } + $('#ticket_type').change( function() { + if ($(this).val() == 20) { + $('#ticketPackageContents').show(); + } else { + $('#ticketPackageContents').hide(); + } + }); + + // Add selected package ticket + $('#addPackageTicket').click( function() { + var tickID = $('#packageTicketSelect').val(); + + // Check if this tickID is already selected + if (document.querySelector('#selectedTicket_' + tickID)) { + alert('This ticket has already been added to the package.\n Adjust quantity to add more.'); + return false; + }; + + // If we have a good ticket ID that hasn't been added, do it now + if (tickID) { + var t = $('#packageTicketOption_' + tickID); + var tickMember = t.attr('data-member'); + var tickPerformance = t.attr('data-performance'); + var tickTitle = t.attr('data-title'); + var tickActive = t.attr('data-active'); + $('#selectedTicketList').append(' \ + \ + \ + \ + \ + ' + tickMember + ' \ + ' + tickPerformance + ' \ + ' + tickTitle + ' \ + ' + tickActive + ' \ + \ + '); + } + }); + + // Delete selected package ticket + $( document ).on( "click", ".deleteSelectedTicket", function() { + var tickID = $(this).attr('data-id'); + + $('#selectedTicket_' + tickID).remove(); + }); + + }); + + \ No newline at end of file diff --git a/views/admin/tickets/Ticket/inventory.html b/views/admin/tickets/Ticket/inventory.html new file mode 100644 index 0000000..0e2563c --- /dev/null +++ b/views/admin/tickets/Ticket/inventory.html @@ -0,0 +1,262 @@ + +
    + + + +
    + {foreach:ticketCalendar,m} +
    +
    {m.month} {m.year}
    +
    +
    +
    +
    +
    +
    +
    +
    +
    Sun
    +
    Mon
    +
    Tue
    +
    Wed
    +
    Thu
    +
    Fri
    +
    Sat
    +
    + {foreach:m.weeks,w} + {if:w.weekUsed} +
    + {foreach:w.days,d} + {if:d.isDate} + {if:d.selectable} + {if:d.active.value} +
    + {else:} +
    + {end:} +
    +
    {d.dom}
    + +
    +
    +
    +
    Time:
    +
    {d.ticket_time.time}
    + +
    + {if:ticketDetail.unlimited_quant.value} +
    +
    Quantity:
    +
    Unlimited
    +
    + {else:} +
    +
    Quantity:
    +
    {d.quant}
    + +
    +
    +
    Avail:
    +
    {d.available}
    + +
    + {end:} +
    +
    Sold:
    +
    {d.sold}
    + +
    +
    +
    +
    + {else:} +
    +
    +
    {d.dom}
    + +
    +
    +
    +
    + {end:} + {else:} +
     
    + {end:} + {end:} +
    + {end:} + {end:} +
    + {end:} +
    + +
      +
    • Click date cell to dissable or enable a partcular date.
    • +
    • Click on edit icon to change the values.
    • +
    + + +
    + +{startScript:h} + + $(function() { + + // Send user notice if they click a non-inventory cell + $('.emCalDateCellNotice').click( function() { + alert('This is not within the date range for the {term.performance.norm}. To add inventory for this date, edit the {term.performance.norm} and change the start or end date.'); + }); + + // Toggle date cell on-off + $('.emCalDateCellSelectable').click( function() { + + var thisCell = $(this); + var thisId = $(this).attr('invId'); + var invStatus; + + // If the cell is currently selected + if (thisCell.hasClass("emCalDateCellSelected")) { + invStatus = 0; // Change to not selected + } else { + invStatus = 1; // Otherwise change to selected + } + + + $.ajax({ + url: "{adminURL}&Action=Ticket_setActive&TicketInventoryID=" + thisId + "&TicketInventoryStatus=" + invStatus, + success: function() { + // Update cell status display + if (invStatus == 1) { + thisCell.addClass('emCalDateCellSelected'); + } else { + thisCell.removeClass('emCalDateCellSelected'); + } + } , + error: function() { + alert( + 'There was an error while submitting this information.\n' + + 'The information may not have been updated.\n' + + 'Please try again later or call for support.' + ); + } + }); + + }); + + + // Pop-up calendar edit forms + $('.emCalDateEditIcon').click( function() { + + // get needed parameters + var dateTime = $(this).attr('calDate'); + var thisId = $(this).attr('invId'); + var thisTime = $('#ticket_time_' + dateTime).html(); + var thisQuant = $('#quant_' + dateTime).html(); + var thisAvail = $('#avail_' + dateTime).html(); + var thisSold = $('#sold_' + dateTime).html(); + + // Place edit form in cell edit container + $('#edit_'+dateTime).html(' \ +
    \ +
    \ + \ + \ + \ + {if:ticketDetail.unlimited_quant.value} +
    \ +
    Quantity:
    \ +
    Unlimited
    \ +
    \ + {else:} +
    \ +
    Quantity:
    \ + \ +
    \ +
    \ +
    Available:
    \ + \ +
    \ + {end:} +
    \ +
    Sold:
    \ + \ +
    \ +
    \ +
    \ +
    \ + '); + + // Start dialog pop-up + $('#calEdit').dialog({ + autoOpen: true, + modal: true, + position: { + my: "bottom", + at: "top", + of: "#" + dateTime + }, + buttons: { + "Update": function() { + + $('#calEditForm').addClass('emCalEditContainerHidden'); + $('#calEditPleaseWait').html('
    Storing, Please Wait...
    '); + + var tf = $(this); + + // Submit form + $('#calEditForm').ajaxForm({ + success: function(data) { + + // Copy data from pop-up back to selected calendar date + var valEditTime = $("#calEditTime").val(); + var valEditQuant = $("#calEditQuant").val(); + var valEditAvail = $("#calEditAvail").val(); + var valEditSold = $("#calEditSold").val(); + $('#ticket_time_' + dateTime).html( valEditTime ); + $('#quant_' + dateTime).html( valEditQuant ); + $('#avail_' + dateTime).html( valEditAvail ); + $('#sold_' + dateTime).html( valEditSold ); + + // Destroy dialog pop-up + tf.dialog( "close" ); + tf.dialog('destroy').remove(); + return false; + + } , + error: function() { + + // If the data was not able to be submitted + alert( + 'There was an error while submitting this information.\n' + + 'The information may not have been updated.\n' + + 'Please try again later or call for support.' + ); + + // Destroy dialog pop-up + tf.dialog( "close" ); + tf.dialog('destroy').remove(); + return false; + + } + }); + + // Kick ajaxForm submission + $('#calEditForm').submit(); + + } + } + }); + + return false; + }); + + f_restartOnTabSelect(); + + }); + + diff --git a/views/admin/tickets/Ticket/inventoryNoCalendar.html b/views/admin/tickets/Ticket/inventoryNoCalendar.html new file mode 100644 index 0000000..e755884 --- /dev/null +++ b/views/admin/tickets/Ticket/inventoryNoCalendar.html @@ -0,0 +1,80 @@ + +
    +
    +

    Editing {term.ticket.norm} inventory for all dates

    +

    This {term.ticket.norm} is not date specific.

    + {foreach:inventoryData,d} +
    + + + + + + + + {if:ticketDetail.unlimited_quant.value} + + {else:} + + + + + + + + + {end:} + + + + + +
    {term.performance.cap}:{ticketDetail.performance}
    {term.ticket.cap}:{ticketDetail.name}
    Quantity:
    UnlimitedInv ID: {d.id}
    Quantity:
    + + Inv ID: {d.id} +
    Available:
    Sold:
     
    +
    +
    {if:inventoryUpdated}Updated{end:}
    + {end:} + +
    + +
    + +{startScript:h} + + $(function() { + + /* + * Table operations + */ + + $('.invEditTable').dataTable({ + "bPaginate": false, + "bLengthChange": false, + "bFilter": false, + "bSort": false, + "bInfo": false, + "bAutoWidth": false, + "bDestroy": true + }); + + /* + * AJAX form handling + */ + + $('#invEditForm').ajaxForm({ + beforeSend: function(e) { + $('#calEditPleaseWait').html('
    Storing, Please Wait...
    '); + }, + success: function(data) { + var container = $('#Ticket_info_container'); + f_replaceContents(data, container); + return false; + } + }); + + + }); + + diff --git a/views/admin/tickets/Ticket/list.html b/views/admin/tickets/Ticket/list.html new file mode 100644 index 0000000..b6d3f5c --- /dev/null +++ b/views/admin/tickets/Ticket/list.html @@ -0,0 +1,166 @@ + +
    + +
    +
    +{if:checkPermission(#10#)} + +{end:} + +
    + Search {term.ticket.plur_cap}: (start typing any information in list) + + {if:tickets} + +
    + + + + + + {if:option.packages} + + {end:} + + + + + + + + + + + + {foreach:tickets,c} + + + + {if:option.packages} + + {end:} + + + + + + + + + + {end:} + +
    Sort OrderTicket NameTypeActiveAdmin Only{term.prop.cap}{term.performance.cap}StickyShow on StartSectionTime
    {c.sort}{c.cart_sticky.name}{c.show_on_start.name}{c.section} + {if:c.time_specific.value} + {c.ticket_time.time} + {end:} +
    +
    + + {else:} +

    No {term.ticket.plur} listed.

    + {end:} + +
    +
    + +
    + +
    +{startScript:h} + + // Tickets Search + var ticketsSearchData = [ + {foreach:tickets,c} + {label:'{c.performance}, {c.name:h}, {c.section}, {c.ticket_time.time}', value:'{c.id}'}, + {end:} + ]; + + $(function() { + + var TicketListTable = $('#TicketListTable').dataTable({ + "sScrollY": "100px", + "scrollX": true, + "bScrollCollapse": true, + "bPaginate": false, + "bLengthChange": false, + "bFilter": false, + "bSort": true, + "bInfo": false, + "bAutoWidth": false, + "bDestroy": true, + "aoColumns" : [ + { sWidth: '80px', "sType": "numeric" }, + null, + null, + {if:option.packages} + null, + {end:} + null, + null, + null, + null, + null, + null, + { sWidth: '80px' } + ] + }); + $(window).resize(function(){ + TicketListTable.fnDraw(); + }); + + // Toggle length of table + var TicketListTableSmall = true; + var TicketListTableHeight = $('#TicketListTable_wrapper div.dataTables_scrollBody').height(); + $('#ticketListSizeChange').click(function() { + if (TicketListTableSmall) { + $('#TicketListTable_wrapper div.dataTables_scrollBody').height('auto'); + TicketListTableSmall = false; + $(this).html('Smaller Table'); + TicketListTable.fnSettings().oScroll.sY = '100%'; + TicketListTable.fnDraw(); + } else { + $('#TicketListTable_wrapper div.dataTables_scrollBody').height(TicketListTableHeight); + TicketListTableSmall = true; + $(this).html('Larger Table'); + TicketListTable.fnSettings().oScroll.sY = '100px'; + TicketListTable.fnDraw(); + } + }); + + // Close all local sliders + $('#Ticket_detail').hide(duration); + + $('.ticketListSelect').click(function(){ + $('#TicketListTable_wrapper div.dataTables_scrollBody').height(TicketListTableHeight); + TicketListTableSmall = true; + $('#ticketListSizeChange').html('Larger Table'); + TicketListTable.fnSettings().oScroll.sY = '100px'; + TicketListTable.fnDraw(); + f_loadAction('Ticket_selected', 'Ticket_detail_container', 'TicketID=' + $(this).attr('emTicketId') + '&tabList={tabList}'); + }); + + // Search Tickets + $("#ticketsSearch").autocomplete({ + source: ticketsSearchData, + minLength: 1, + focus: function(event, ui) { + // Don't auto fill on focus + return false; + }, + select: function(event, ui) { + $("#ticketsSearch").attr({value: ui.item.label}); + f_loadAction('Ticket_selected', 'Ticket_detail_container', 'TicketID=' + ui.item.value + '&tabList={tabList}'); + return false; + } + }); + + f_restartOnTabSelect(); + + }); + + diff --git a/views/admin/tickets/Ticket/selected.html b/views/admin/tickets/Ticket/selected.html new file mode 100644 index 0000000..0c520e3 --- /dev/null +++ b/views/admin/tickets/Ticket/selected.html @@ -0,0 +1,74 @@ +
    + +
    +
    {term.ticket.cap}: {ticketDetail.name}
    +
    + +
    + + +
    +{if:checkPermission(#30#)} + +{end:} +{if:checkPermission(#20#)} + +{end:} +{if:checkPermission(#10#)} + + +{end:} + +{if:checkPermission(#10#)} + {if:noTicketInventory} + + {else:} + + {end:} +{end:} +{if:checkPermission(#20#)} + +{end:} + +
    + + +
    +
    + +
    + +
    + + +{startScript:h} + + // jQuery Section + $(document).ready(function(){ + + // Start with ticket detail loaded + f_loadAction('Ticket_detail', 'Ticket_info_container', "tabList={tabList}"); + + f_restartOnTabSelect(); + + }); + + diff --git a/views/admin/tickets/User/index.html b/views/admin/tickets/User/index.html new file mode 100644 index 0000000..6d55633 --- /dev/null +++ b/views/admin/tickets/User/index.html @@ -0,0 +1,85 @@ + + + + {startScript:h} + + // Pass some reference parameters to JAVAScript + var baseSiteURL = '{baseURL}'; + var baseAdminURL = '{baseAdminURL}'; + var appAdminURL = '{appAdminURL}'; + var memberUser = '{MemberUser}'; + var debugEnabled = {if:option.admin_debug}true{else:}false{end:}; + + + + + + + + + + + + + + + + + + + +
    + + + {if:option.tickets} + + + + + + {end:} + {if:option.events} + + {end:} + + + + +
    + + +
    + +
    + +
    + Gaslight Media - Event Management and Ticketing System +
    + + + + + + diff --git a/views/admin/tickets/User/loginForm.html b/views/admin/tickets/User/loginForm.html new file mode 100644 index 0000000..6ee438d --- /dev/null +++ b/views/admin/tickets/User/loginForm.html @@ -0,0 +1,105 @@ + + + + {startScript:h} + + // Pass some reference parameters to JAVAScript + var baseSiteURL = '{baseURL}'; + var baseAdminURL = '{baseAdminURL}'; + var appAdminURL = '{appAdminURL}'; + var memberUser = '{MemberUser}'; + var debugEnabled = {if:option.admin_debug}true{else:}false{end:}; + var debugWidth = {option.admin_debug_size}; + + + + + + + + + + + + + + + + + + + {config.owner.name} + +
    +
    +
    +
    {owner.name} Event Ticket System
    +

    + Please log in using your user E-Mail address or ID and your password. +

    +
    + + {if:reason} +
    +
    We're sorry, we had a problem with your request:
    +
      + {foreach:reason,r} +
    • {r:h}
    • + {end:} +
    +
    + {end:} + +
    +
    + + + + + + + + + + + + + +
    E-Mail Address or Log in ID:
    Password:
    + +
    + +
    + +
    +
    + +

    + This section of this Web site is for authorized persons only. + Tampering and unauthorized access will be reported. +

    + +
    +
    + +
    + Gaslight Media - Event Management System +
    + + {startScript:h} + + $(document).ready(function(){ + + $("#email").focus(); + + }); + + + + + + + + diff --git a/views/admin/tickets/VoucherCoupon/delete.html b/views/admin/tickets/VoucherCoupon/delete.html new file mode 100755 index 0000000..f1f3f57 --- /dev/null +++ b/views/admin/tickets/VoucherCoupon/delete.html @@ -0,0 +1,66 @@ +
    + +
    Delete this {term.coupon.cap}
    + +
    {VoucherCouponDetail.name}
    + +
    + + +
    + + {if:voucherCouponDetail} +
    + + + + + + + + + + + + + + + + + + + + + + +
    Delete {term.coupon.cap}: +

    Clicking "Confirm Delete" on the right will permanently delete this {term.ticket.norm} add-on.

    +
    {term.coupon.cap}:{voucherCouponDetail.name:h}ID: {voucherCouponDetail.id}
    Type:{voucherCouponDetail.coupon_type.name:h}
    Active:{voucherCouponDetail.active.name}
    Position:{voucherCouponDetail.coupon_position.name:h}
    Display From:{voucherCouponDetail.display_from.date}
    Display To:{voucherCouponDetail.display_to.date}
    Image:
    Stretch to Fit:{voucherCouponDetail.stretch_to_fit.name}
    Padding:{voucherCouponDetail.padding}
    Show Border:{voucherCouponDetail.show_border.name}
    Maximum Display Count:{voucherCouponDetail.max_display_count}
    Current Display Count:{voucherCouponDetail.display_count}
    Notes:{voucherCouponDetail.notes:h}
    + {else:} +

    No {term.coupon.plur} found.

    + {end:} + +
    + +
    +{startScript:h} + $(document).ready(function(){ + + $('#VoucherCouponDeleteTable').dataTable({ + "bPaginate": false, + "bLengthChange": false, + "bFilter": false, + "bSort": false, + "bInfo": false, + "bAutoWidth": false, + "bDestroy": true + }); + + f_restartOnTabSelect(); + + }); + diff --git a/views/admin/tickets/VoucherCoupon/detail.html b/views/admin/tickets/VoucherCoupon/detail.html new file mode 100644 index 0000000..66ce610 --- /dev/null +++ b/views/admin/tickets/VoucherCoupon/detail.html @@ -0,0 +1,76 @@ +
    + + + +
    + + +
    + + {if:voucherCouponDetail} +
    + + + + {if:voucherCouponDetail.delete} + + + + + {end:} + + + + + + + + + + + + + + +
    Delete {term.coupon.cap}: + {if:voucherCouponDetail.deleteConfirmed} + {if:voucherCouponDetail.deleteFailure} +

    FAILED:

    + Sorry, we are unable to delete the entry at this time.
    + {voucherCouponDetail.reason:h} + {else:} +

    Deleted

    + {end:} + {else:} +
    +

    Clicking the button above will permanently delete this {term.coupon.norm}.

    + {end:} +
    {term.coupon.cap}:{voucherCouponDetail.name:h}ID: {voucherCouponDetail.id}
    Active:{voucherCouponDetail.active.name}
    Type:{voucherCouponDetail.coupon_type.name:h}
    Position:{voucherCouponDetail.coupon_position.name:h}
    Display From:{voucherCouponDetail.display_from.date}
    Display To:{voucherCouponDetail.display_to.date}
    Image:
    Stretch to Fit:{voucherCouponDetail.stretch_to_fit.name}
    Padding:{voucherCouponDetail.padding}
    Show Border:{voucherCouponDetail.show_border.name}
    Maximum Display Count:{voucherCouponDetail.max_display_count}
    Current Display Count:{voucherCouponDetail.display_count}
    Notes:{voucherCouponDetail.notes:h}
    +
    + {else:} +

    No {term.coupon.plur} found.

    + {end:} + + +
    +{startScript:h} + $(document).ready(function(){ + + $('#VoucherCouponDetailTable').dataTable({ + "bPaginate": false, + "bLengthChange": false, + "bFilter": false, + "bSort": false, + "bInfo": false, + "bAutoWidth": false, + "bDestroy": true + }); + + f_restartOnTabSelect(); + + }); + diff --git a/views/admin/tickets/VoucherCoupon/edit.html b/views/admin/tickets/VoucherCoupon/edit.html new file mode 100755 index 0000000..594512e --- /dev/null +++ b/views/admin/tickets/VoucherCoupon/edit.html @@ -0,0 +1,283 @@ +
    + +
    + {if:addingNewVoucherCoupon}Adding New {term.coupon.cap}{end:} + {if:editingVoucherCoupon}Editing {term.coupon.cap}{end:} +
    a + +
    +{if:addingNewVoucherCoupon} + +{else:} + +{end:} +
    + +{if:formFail} +
    Not all fields were filled in correctly. Please try again.
    +{end:} + +
    + + {if:voucherCouponDetail} + +

    Required fields in RED.

    + +
    + {if:addingNewVoucherCoupon} + + {else:} + + {end:} + + + + + +
    + + + + + {if:fieldRequired.name} + {if:fieldFail.name} + + + + + + + {if:fieldRequired.coupon_type} + {if:fieldFail.coupon_type} + + + {if:fieldRequired.coupon_position} + {if:fieldFail.coupon_position} + + + {if:fieldRequired.display_from} + {if:fieldFail.display_from} + + + {if:fieldRequired.display_to} + {if:fieldFail.display_to} + + + {if:fieldRequired.coupon_image} + {if:fieldFail.coupon_image} + + + + + + + {if:fieldRequired.padding} + {if:fieldFail.padding} + + + + + + + {if:fieldRequired.max_display_count} + {if:fieldFail.max_display_count} + + + {if:fieldRequired.display_count} + {if:fieldFail.display_count} + + + {if:fieldRequired.notes} + {if:fieldFail.notes} + + +
    {else:}{end:}{term.coupon.cap} Name:{else:}{end:} +
    + {if:fieldFail.name}
    {fieldFail.name}{end:} +
    This is for reference only, it is not displayed to users. +
    Active: + {if:voucherCouponDetail.active.value} + + {else:} + + {end:} +
    {else:}{end:}{term.coupon.cap} Type:{else:}{end:} + + {if:fieldFail.coupon_type}
    {fieldFail.coupon_type}{end:} +
    {else:}{end:}{term.coupon.cap} Position:{else:}{end:} + + {if:fieldFail.coupon_position}
    {fieldFail.coupon_position}{end:} +
    {else:}{end:}Display From:{else:}{end:} + {if:addingNewVoucherCoupon} + + {else:} + + {end:} + {if:fieldFail.display_from}
    {fieldFail.display_from}{end:} +
    {else:}{end:}Display To:{else:}{end:} + {if:addingNewVoucherCoupon} + + {else:} + + {end:} + {if:fieldFail.display_to}
    {fieldFail.display_to}{end:} +
    {else:}{end:}{term.coupon.cap} Image:{else:}{end:} + {if:voucherCouponDetail.coupon_image} + +
    Delete this image: + {end:} + +
    Upload or replace the image: + {if:fieldFail.coupon_image}
    {fieldFail.coupon_image}{end:} +
    Stretch to Fit: + {if:voucherCouponDetail.stretch_to_fit.value} + + {else:} + + {end:} +
    {else:}{end:}Padding:{else:}{end:} + + {if:fieldFail.padding}
    {fieldFail.padding}{end:} +
    This is the minimum amount of space between the image and all sides of the Ad/Coupon box.
    + The value is in the units displayed when you select the "Test" button at the upper-right. +
    Show Border: + {if:voucherCouponDetail.show_border.value} + + {else:} + + {end:} +
    {else:}{end:}Maximum Display Count:{else:}{end:} + + {if:fieldFail.max_display_count}
    {fieldFail.max_display_count}{end:} +
    Maximum number of times this {term.coupon.norm} will be included in a {term.voucher.norm}. Set to -1 for unlimited. +
    {else:}{end:}Current Display Count:{else:}{end:} + + {if:fieldFail.display_count}
    {fieldFail.display_count}{end:} +
    This is the number of times this {term.coupon.norm} has been included in a {term.voucher.norm}. +
    {else:}{end:}Notes:{else:}{end:} + + {if:fieldFail.notes}
    {fieldFail.notes}{end:} +
    +
    + +
    + {if:addingNewVoucherCoupon} + + {end:} + {if:editingVoucherCoupon} + + {end:} +
    + +
    + + {else:} +

    No {term.coupon.norm} has been selected yet.

    +

    To edit a {term.coupon.norm}, first select it from the list of available {term.coupon.plur}. + {end:} + +

    + +
    + + +
    + +{startScript:h} + + $(function() { + + /* + * Table operations + */ + + $('.voucherCouponEditTable').dataTable({ + "bPaginate": false, + "bLengthChange": false, + "bFilter": false, + "bSort": false, + "bInfo": false, + "bAutoWidth": false, + "bDestroy": true + }); + + /* + * AJAX form handling + */ + + $('#voucherCouponForm').ajaxForm({ + success: function(data) { + {if:addingNewVoucherCoupon} + var container = $('#VoucherCoupon_detail_container'); + f_replaceContents(data, container); + {end:} + {if:editingVoucherCoupon} + var container = $('#VoucherCoupon_detail_container'); + f_replaceContents(data, container); + {end:} + return false; + } + }); + + // Block default form submission + $("form").submit(function (e) { + $('#voucherCouponFormSubmit').html('
    Submitting, Please Wait...
    '); + e.preventDefault(); + }); + + /* + * CKeditor actions + */ + + // Code to kick off CKEditor for specific fields + f_buildCkeditor($("#notes")); + + // Remove the editors and store the data back in the textareas before the AJAX form submission + $('.emEditSubmit').click( function() { + f_removeCkeditor($("#notes")); + }); + + f_restartOnTabSelect(); + + /* + * Date input operations + */ + + // Code to start datepicker for each date input + $("#displayFromInput").datepicker({ + dateFormat: "mm/dd/yy", + minDate: '{voucherCouponDetail.display_from.date_list.min}', + maxDate: '{voucherCouponDetail.display_from.date_list.max}' + }); + $("#displayToInput").datepicker({ + dateFormat: "mm/dd/yy", + minDate: '{voucherCouponDetail.display_to.date_list.min}', + maxDate: '{voucherCouponDetail.display_to.date_list.max}' + }); + + + }); + + \ No newline at end of file diff --git a/views/admin/tickets/VoucherCoupon/list.html b/views/admin/tickets/VoucherCoupon/list.html new file mode 100644 index 0000000..78c12ec --- /dev/null +++ b/views/admin/tickets/VoucherCoupon/list.html @@ -0,0 +1,131 @@ + +
    + +
    +
    +{if:checkPermission(#10#)} + + +{end:} + +
    + Search {term.coupon.plur_cap}: (start typing any information in list) + + {if:voucherCoupons} + +
    + + + + + + {foreach:voucherCoupons,c} + + + + + + + + + + + {end:} + +
    {term.coupon.cap}ActiveTypePositionFromToMaxCount
    +
    + + {else:} +

    No {term.coupon.plur}.

    + {end:} + +
    +
    + +
    + +
    +{startScript:h} + + // Voucher Coupons Search + var voucherCouponsSearchData = [ + {foreach:voucherCoupons,c} + {label:'{c.name:h}, {c.coupon_position.name:h}, {c.display_from.date}, {c.display_to.date}', value:'{c.id}'}, + {end:} + ]; + + $(function() { + + var VoucherCouponListTable = $('#VoucherCouponListTable').dataTable({ + "sScrollY": "100px", + "scrollX": true, + "bScrollCollapse": true, + "bPaginate": false, + "bLengthChange": false, + "bFilter": false, + "bSort": true, + "bInfo": false, + "bAutoWidth": false, + "bDestroy": true, + }); + $(window).resize(function(){ + VoucherCouponListTable.fnDraw(); + }); + + // Toggle length of table + var VoucherCouponListTableSmall = true; + var VoucherCouponListTableHeight = $('#VoucherCouponListTable_wrapper div.dataTables_scrollBody').height(); + $('#voucherCouponListSizeChange').click(function() { + if (VoucherCouponListTableSmall) { + $('#VoucherCouponListTable_wrapper div.dataTables_scrollBody').height('auto'); + VoucherCouponListTableSmall = false; + $(this).html('Smaller Table'); + VoucherCouponListTable.fnSettings().oScroll.sY = '100%'; + VoucherCouponListTable.fnDraw(); + } else { + $('#VoucherCouponListTable_wrapper div.dataTables_scrollBody').height(VoucherCouponListTableHeight); + VoucherCouponListTableSmall = true; + $(this).html('Larger Table'); + VoucherCouponListTable.fnSettings().oScroll.sY = '100px'; + VoucherCouponListTable.fnDraw(); + } + }); + + // Close all local sliders + $('#VoucherCoupon_detail').hide(duration); + + $('.voucherCouponListSelect').click(function(){ + $('#VoucherCouponListTable_wrapper div.dataTables_scrollBody').height(VoucherCouponListTableHeight); + VoucherCouponListTableSmall = true; + $('#voucherCouponListSizeChange').html('Larger Table'); + VoucherCouponListTable.fnSettings().oScroll.sY = '100px'; + VoucherCouponListTable.fnDraw(); + f_loadAction('VoucherCoupon_selected', 'VoucherCoupon_detail_container', 'VoucherCouponID=' + $(this).attr('emVoucherCouponId') + '&tabList={tabList}'); + }); + + // Search Voucher Coupons + $("#voucherCouponsSearch").autocomplete({ + source: voucherCouponsSearchData, + minLength: 1, + focus: function(event, ui) { + // Don't auto fill on focus + return false; + }, + select: function(event, ui) { + $("#voucherCouponsSearch").attr({value: ui.item.label}); + f_loadAction('VoucherCoupon_selected', 'VoucherCoupon_detail_container', 'VoucherCouponID=' + ui.item.value + '&tabList={tabList}'); + return false; + } + }); + + f_restartOnTabSelect(); + + }); + + diff --git a/views/admin/tickets/VoucherCoupon/selected.html b/views/admin/tickets/VoucherCoupon/selected.html new file mode 100755 index 0000000..0094ebe --- /dev/null +++ b/views/admin/tickets/VoucherCoupon/selected.html @@ -0,0 +1,32 @@ +
    + +
    +
    {term.coupon.cap}: {voucherCouponDetail.name}
    +
    + +
    + + +
    +
    + +
    + +
    + + +{startScript:h} + + // jQuery Section + $(document).ready(function(){ + + // Start with ticket detail loaded + f_loadAction('VoucherCoupon_detail', 'VoucherCoupon_detail_container', "tabList={tabList}"); + + f_restartOnTabSelect(); + + }); + + diff --git a/views/admin/tickets/VoucherCoupon/test.html b/views/admin/tickets/VoucherCoupon/test.html new file mode 100755 index 0000000..c7aff4b --- /dev/null +++ b/views/admin/tickets/VoucherCoupon/test.html @@ -0,0 +1,142 @@ +
    + +
    + Test {term.coupon.plur_cap} +
    + +
    + +

    Required fields in RED.

    + +
    + +
    + + + + + + + + + + + + + + + + + + + + + + + + +
    {term.coupon.cap} Name: + +
    Active: + +
    {term.coupon.cap} Type: + +
    {term.coupon.cap} Position: + +
    Date: + +
    +
    + + + +
    + +
    + +
    + + +
    + +{startScript:h} + + $(function() { + + /* + * Table operations + */ + + $('.voucherCouponEditTable').dataTable({ + "bPaginate": false, + "bLengthChange": false, + "bFilter": false, + "bSort": false, + "bInfo": false, + "bAutoWidth": false, + "bDestroy": true + }); + + // Block default form submission + $("form").submit(function (e) { + var date = $('#date').val(); + var voucherWindow = window.open('{adminURL}&Action=Ticket_printSampleVoucher&testCoupons=true&date=' + date, + "voucherPrint", + "height=750,width=600,menubar=yes,toolbar=yes,alwaysRaised=yes,menu" + ); + return false; + }); + + /* + * CKeditor actions + */ + + // Code to kick off CKEditor for specific fields + f_buildCkeditor($("#notes")); + + // Remove the editors and store the data back in the textareas before the AJAX form submission + $('.emEditSubmit').click( function() { + f_removeCkeditor($("#notes")); + }); + + f_restartOnTabSelect(); + + /* + * Date input operations + */ + + // Code to start datepicker for each date input + $("#date").datepicker({ + dateFormat: "mm/dd/yy", + minDate: '{voucherCouponDetail.display_from.date_list.min}', + maxDate: '{voucherCouponDetail.display_from.date_list.max}' + }); + + // Print test vouchers + $('.voucherPrint').click(function(){ + var date = $(this).attr('emOrderID'); + var orderVerify = $(this).attr('emOrderVerify'); + var voucherWindow = window.open('{adminURL}&Action=Ticket_printSampleVoucher&testTicket={ticketDetail.id}', + "voucherPrint", + "height=750,width=600,menubar=yes,toolbar=yes,alwaysRaised=yes,menu" + ); + voucherWindow.focus(); + voucherWindow.print(); + return false; + }); + + + + }); + + \ No newline at end of file diff --git a/views/admin/tickets/Welcome/index.html b/views/admin/tickets/Welcome/index.html new file mode 100644 index 0000000..e2c8932 --- /dev/null +++ b/views/admin/tickets/Welcome/index.html @@ -0,0 +1,60 @@ +
    + +{if:userMemberID} +
    +
    {userMemberVenueName} {term.ticket.cap} Management System
    + {if:checkPermission(#10#)} +

    + For assistance with this system please call {owner.name} at {owner.phone} +

    + {else:} + + {end:} + +
    +{else:} +
    +
    Welcome to the Gaslight Media Event Management / Ticketing System.
    +

    + In an effort to provide our customers with the best possible service, Gaslight Media will from time to + time make improvements to this application and correct problems that we have noticed + or that have been reported to us. Updates will be posted here so that you can be aware of improvements. + As always, please let us know if you have any concerns, need any assistance, or would like to suggest new features. +

    +
    +
    +
    + +
    +
    +

    The following updates have been included in this version...

    +
      +
    • +

      + "Admin Only" Sales: There is now a tab at the upper-right of the Event Management / Ticketing System admin interface called + "Place an Order". When you click this, it will take you to the front-end of the the Event/Ticketing system to place an order. It + will also know that you are an admin user and will include certain categories and items that are not available to regular + users. To specify which items you would like to mark as "Admin Only", select either the "Categories" or "Items" tab, select + the desired entry from the list, edit that entry and check the "Purchase by Admin Only" checkbox then save by clicking the Update button. +

      +

      + Note that when you are in the front end as an "Admin" user, you will see the "Purchasing By Admin User" banner across the top of each + page. +

      +
    • +
    +
    +
    +
    +{end:} + +
    + +{startScript:h} + + // jQuery Section + $(document).ready(function(){ + + }); + + \ No newline at end of file diff --git a/views/admin/tickets/index.html b/views/admin/tickets/index.html new file mode 100644 index 0000000..94a2289 --- /dev/null +++ b/views/admin/tickets/index.html @@ -0,0 +1,158 @@ + + + + {startScript:h} + + // Pass some reference parameters to JAVAScript + var baseSiteURL = '{baseURL}'; + var baseAdminURL = '{baseAdminURL}'; + var appAdminURL = '{appAdminURL}'; + var memberUser = '{MemberUser}'; + var debugEnabled = {if:option.admin_debug}true{else:}false{end:}; + var debugWidth = {option.admin_debug_size}; + var startWithClaims = {startWithClaims}; + + + + + + + + + + + + + + + + + + + + + + {if:userMemberID} +

    + Logged in: {memberName} (Logout) + +

    + {end:} + + +
    + + {if:userMemberID} + + {else:} + + {end:} + {if:option.tickets} + + + + + +
    + + + +
    + {end:} + {if:option.events} + +
    + {end:} + + + + + +
    + + +
    + +
    + +
    + +{if:userMemberID} + {userMemberVenueName} {term.ticket.cap} Management System
    + {if:checkPermission(#10#)} + For assistance with this system please call {owner.name} at {owner.phone} + {else:} + + {end:} +{else:} + + Gaslight Media - Event Management and Ticketing System +{end:} +
    + + {startScript:h} + + $(function() { + + if (startWithClaims) { + f_loadAction('Sold_claim', 'Main_container', "tabList="); + $('#claimStatusTab').addClass('emTabSelected'); + } + + }); + + // Link to front-end ticket ordering + $('#placeOrder').click( function() { + window.open('{frontEndOrderLink}?adminUserCheck={adminUserFrontLinkCheck}','_blank'); + }); + + + + + + + + + diff --git a/views/admin/tickets/index.html.SAVE b/views/admin/tickets/index.html.SAVE new file mode 100644 index 0000000..4630d9f --- /dev/null +++ b/views/admin/tickets/index.html.SAVE @@ -0,0 +1,155 @@ + + + + {startScript:h} + + // Pass some reference parameters to JAVAScript + var baseSiteURL = '{baseURL}'; + var baseAdminURL = '{baseAdminURL}'; + var appAdminURL = '{appAdminURL}'; + var memberUser = '{MemberUser}'; + var debugEnabled = {if:option.admin_debug}true{else:}false{end:}; + var debugWidth = {option.admin_debug_size}; + var startWithClaims = {startWithClaims}; + + + + + + + + + + + + + + + + + + + {if:userMemberID} +

    + Logged in: {memberName} (Logout) + +

    + {end:} + + +
    + + {if:userMemberID} + + {else:} + + {end:} + {if:option.tickets} + + + + + +
    + + + +
    + {end:} + {if:option.events} + +
    + {end:} + + + + + +
    + + +
    + +
    + +
    + +{if:userMemberID} + {userMemberVenueName} {term.ticket.cap} Management System
    + {if:checkPermission(#10#)} + For assistance with this system please call {owner.name} at {owner.phone} + {else:} + + {end:} +{else:} + + Gaslight Media - Event Management and Ticketing System +{end:} +
    + + {startScript:h} + + $(function() { + + if (startWithClaims) { + f_loadAction('Sold_claim', 'Main_container', "tabList="); + $('#claimStatusTab').addClass('emTabSelected'); + } + + }); + + // Link to front-end ticket ordering + $('#placeOrder').click( function() { + window.open('{frontEndOrderLink}?adminUserCheck={adminUserFrontLinkCheck}','_blank'); + }); + + + + + + + + + diff --git a/views/front/FoundationStandAlone/Debug/index.html b/views/front/FoundationStandAlone/Debug/index.html new file mode 100755 index 0000000..6af2dc9 --- /dev/null +++ b/views/front/FoundationStandAlone/Debug/index.html @@ -0,0 +1,44 @@ + + + + + + +
    Startup: {debugStartupTime}
    +
    Event Management Front-End Debug
    +
    +
    + Updated: {debugUpdateTime} +
    +
    + {debugData:h} +
    + + + + + {startScript:h} + + // Reload the current window with Action = Debug_update + function reloadDebugWindow() + { + window.location("{baseSCRIPT}&Action=Debug_update"); + } + + + \ No newline at end of file diff --git a/views/front/FoundationStandAlone/Debug/start.html b/views/front/FoundationStandAlone/Debug/start.html new file mode 100755 index 0000000..66c3023 --- /dev/null +++ b/views/front/FoundationStandAlone/Debug/start.html @@ -0,0 +1,27 @@ + + + + + + +
    Startup: {debugStartupTime}
    +
    Event Management Front-End Debug
    +
    +
    Debug Startup
    + + \ No newline at end of file diff --git a/views/front/FoundationStandAlone/Shop/PayPalApproved.html b/views/front/FoundationStandAlone/Shop/PayPalApproved.html new file mode 100755 index 0000000..323197a --- /dev/null +++ b/views/front/FoundationStandAlone/Shop/PayPalApproved.html @@ -0,0 +1,41 @@ + + + + + +
    + +

    Your PayPal payment has been approved.

    + + +
    + +

    + Your cart will now reflect that the payment has been made. +

    + +
    + +
    +
    Close This Window
    +
    + +
    + + + + diff --git a/views/front/FoundationStandAlone/Shop/PayPalFail.html b/views/front/FoundationStandAlone/Shop/PayPalFail.html new file mode 100755 index 0000000..18feaa0 --- /dev/null +++ b/views/front/FoundationStandAlone/Shop/PayPalFail.html @@ -0,0 +1,49 @@ + + + + + +
    + +

    Unable to process your payment!

    + + +
    + +

    +

    Sorry, there was a problem.
    +

    + +

    + We were unable to find your purchase information and are therefore + are unable to process your payment through PayPal. This could be + due to you not performing any action with your pending purchase + for too long. Please click the "Return to selected tickets" button + at the top of the checkout page to see if your selections are still listed. +

    + +
    + +
    +
    Close This Window
    +
    + +
    + + + + diff --git a/views/front/FoundationStandAlone/Shop/additionalInfo.html b/views/front/FoundationStandAlone/Shop/additionalInfo.html new file mode 100644 index 0000000..96dc231 --- /dev/null +++ b/views/front/FoundationStandAlone/Shop/additionalInfo.html @@ -0,0 +1,246 @@ + + + +
    + + + +
    +
    + + + {term.nav.show_selected} + {if:!option.ticket_shop.start_at_cart} + {term.nav.select_more} + {end:} + + +

    {cartText:h}

    + +
    +
    + +{if:reason} + + + +
    +
    +
    +

    We're sorry, we had a problem with your request:

    +
      + {foreach:reason,r}{Chuck} +
    • {r:h}
    • + {end:} +
    +
    +
    +
    +{end:} + + + +{foreach:cart,c} + + {if:option.show_location_blocks} +
    +
    +
    +
    +

    {c.name:h}

    +
    + {end:} + + + + + {if:c.needAssignemntOrDate} + {if:c.needAssignment} + +
    + {if:!c.haveAssignment} +
    {text.cart.select_assignment_location}
    + {else:} +
    {text.cart.select_assignment_location}
    + {end:} + {foreach:c.assignmentMembers,a} + {if:a.entrances} + {foreach:a.entrances,e} +
    + {if:option.cart_images} + {if:e.image} +
    + {end:} + {end:} +
    + {if:e.selected} + {a.name} - {e.name}
    + {else:} + {a.name} - {e.name}
    + {end:} +
    +
    {e.addr1}{if:e.addr2}, {e.addr2}{end:}, {e.city}
    +
    {e.phone}
    + {if:e.descr} +
    {e.descr:h}
    + {end:} +
    +
    + {end:} +
    + {else:} + {if:a.selected} + {a.name}
    + {else:} + {a.name}
    + {end:} + {end:} + {end:} +  
    + {end:} + + {if:option.ask_for_likely_date} + {if:c.needLikelyDate} +
    +

    + {if:!c.likelyDate} + + {else:} + + {end:} + {text.cart.select_likely_date}   + + mm/dd/yyyy + {if:text.cart.select_likely_date_explain} +
    {text.cart.select_likely_date_explain} + {end:} +

    +
    + {end:} + {end:} +
    +
    + {end:} + {if:!c.needAssignment} + + {if:option.cart_images}{if:c.image} +
    + + +
    + {end:}{end:} + {end:} + +
    +
    +
    + +{end:} + + + +{if:cartHasContents} +
    +
    + {if:!blockCheckout} + {term.nav.checkout} + {else:} + Please complete the items in RED above. + {end:} +
    +
    +{else:} +
    +
    +

    Your cart is currently empty.

    +
    +
    +{end:} + + + + + + + + + diff --git a/views/front/FoundationStandAlone/Shop/cart.html b/views/front/FoundationStandAlone/Shop/cart.html new file mode 100755 index 0000000..31268cb --- /dev/null +++ b/views/front/FoundationStandAlone/Shop/cart.html @@ -0,0 +1,670 @@ + + + +
    + + + +
    +
    + + + {if:!option.ticket_selection.start_at_cart} + {term.nav.select_more} + {end:} + + +

    {cartText:h}

    + +
    +
    + +{if:reason} + + + +
    +
    +
    + We're sorry, we had a problem with your request: +
      + {foreach:reason,r} +
    • {r:h}
    • + {end:} +
    +
    +
    +
    +{end:} + +{if:havePromoCodes} + + + +
    +
    + If you have a {term.promo.norm}, please enter it here: + Enter {term.promo.cap} here: +
    +
    + +
    +
    + +{end:} + + + +{foreach:cart,c} + + {if:option.show_location_blocks} +
    +
    +
    +
    +
    {c.name:h}
    +
    + {end:} + + + + {foreach:c.performances,p} +
    +
    +
    + + + +
    +
    + {if:!option.ticket_shop.start_at_cart} + {term.nav.select_more_of_these} + {end:} + + {p.name:h} + +
    +
    + + + +
    +
    + {if:p.short_descr} + {p.short_descr:h} + {else:} + {if:p.descr} + {p.descr:h} + {end:} + {end:} +
    + {if:option.ticket_shop.cart.show_performance_image} + {if:p.image} + +
    + +
    + +
    + +
    + {end:} + {end:} +
    + + + + {foreach:p.dates,d} +
     
    +
    +
    +
    + {if:d.dateSpecific} + {d.fullDate} + {else:} + Use any date + {if:c.likelyDate} + - Likely Date {c.likelyDate} + {end:} + {end:} +
    +
    +
    + + + + {foreach:d.sections,s} +
    +
    Quant
    + {if:!p.oneSectionOnly} +
    {term.section.cap}
    +
    + {else:} +
    + {end:} + {term.ticket.cap} +
    +
    Price
    +
    Sub-Total
    +
    + + + + {foreach:s.tickets,i} + + + +
    +
    + +
    + {if:!p.oneSectionOnly} +
    {s.name:h}
    +
    + {else:} +
    + {end:} + {i.title} + {if:i.required_addon_not_supplied} +
    + At least one item below is required. + {end:} +
    +
    {if:i.show_price}{i.price}{end:}
    +
    {if:!i.show_addons}{if:i.show_price}{i.extended}{end:}{end:}
    +
    + + + +
    +
    +
    {i.title}
    +
    + {if:i.problem} +
    +
    +
    {i.problemText}
    +
    +
    + {end:} + {if:i.descr} + + +
    +
    +
    + {if:option.ticket_shop.cart.show_ticket_image} + {if:i.image} + + {end:} + {end:} + {i.descr:h} +
    +
    + {end:} + + {if:!p.oneSectionOnly} +
    +
    {term.section.cap}:
    +
    {s.name:h}
    +
    + {end:} +
    +
    Quant:
    +
     
    +
    + +
    +
    + {if:i.price_numb} +
    +
    Price:
    +
    {if:i.show_price}{i.price}{end:}
    +
    + {end:} + {if:!i.show_addons} +
    +
    Sub-Total:
    +
    {if:i.show_price}{i.extended}{end:}
    +
    + {end:} +
    + {if:option.packages} + {foreach:i.packageData,y} +
    +
     
    +
    + {y.quant} +
    +
    + {y.title} - {y.performance_name} +
    +
    + {end:} + {end:} + {if:i.descr} + + +
    +
    +
    + {if:option.ticket_shop.cart.show_ticket_image} + {if:i.image} + + {end:} + {end:} + {i.descr:h} +
    +
    + {end:} + + + + {if:i.show_addons} + {foreach:i.addons,a} + + + +
    +
     
    +
    + +
    +
    {a.name}
    +
    {a.unit_cost}/{a.unit_name:h}
    +
    +
    + + + +
    +
    +

    {a.name}

    +
    +
    +
    Quant:
    +
     
    +
    + +
    +
    +
    +
    Price:
    +
    {a.unit_cost}/{a.unit_name:h}
    +
    + +
    + + {end:} +
     
    +
    +
    Sub-Total:
    +
    {i.extended}
    +
    +
     
    + {end:} + + + {if:i.promo} +
    +
     
    +
    + {term.promo.cap}: {promoCode} +
    +
    +
    + {i.promo.credit} +
    +
    +
    +
    Promo:
    +
    {promoCode}:
    +
    {i.promo.credit}
    +
    + + {end:} + + {end:} + + {end:} + + {end:} + +
    +
    +
    + + {end:} + + + + {if:!option.ticket_shop.additionalInfo.use_page} + + {if:c.needAssignemntOrDate} + {if:c.needAssignment} + +
    + {if:!c.haveAssignment} +
    {text.cart.select_assignment_location}
    + {else:} +
    {text.cart.select_assignment_location}
    + {end:} + {foreach:c.assignmentMembers,a} + {if:a.entrances} + {foreach:a.entrances,e} +
    + {if:option.cart_images} + {if:e.image} +
    + {end:} + {end:} +
    + {if:e.selected} + {a.name} - {e.name}
    + {else:} + {a.name} - {e.name}
    + {end:} +
    +
    {e.addr1}{if:e.addr2}, {e.addr2}{end:}, {e.city}
    +
    {e.phone}
    + {if:e.descr} +
    {e.descr:h}
    + {end:} +
    +
    + {end:} +
    + {else:} + {if:a.selected} + {a.name}
    + {else:} + {a.name}
    + {end:} + {end:} + {end:} +  
    + {end:} + + {if:option.ask_for_likely_date} + {if:c.needLikelyDate} +
    + {if:!c.likelyDate} + + {else:} + + {end:} + {text.cart.select_likely_date}   + + mm/dd/yyyy +
    + {end:} + {end:} +
    +
    + {end:} + {if:!c.needAssignment} + + {if:option.cart_images}{if:c.image} +
    + + +
    + {end:}{end:} + {end:} + {end:} + +{if:c.no_payment} +
    +
    +

    + No payment is being processed for these {term.ticket.plur}.
    Payment for these items must be arranged directly with {owner.name}. +

    +
    +
    +{end:} + + {if:option.show_location_blocks} +
    +
    +
    + {end:} + +{end:} + + + +{if:cartHasContents} +
    +
    +

    + Grand Total {totals.grand_total_price} +

    +
    +
    +
    +
    + {if:blockCheckoutMixedPayment} + Please read the message at the top of this page. + {else:} + + {if:option.ticket_shop.additionalInfo.use_page} + {if:blockCheckoutNonAssignment} + Please complete the items in RED above. + {else:} + {if:doingAdditionalInfo} + {term.nav.additional_info} + {else:} + {term.nav.checkout} + {end:} + {end:} + {else:} + {if:!blockCheckout} + {term.nav.checkout} + {else:} + Please complete the items in RED above. + {end:} + {end:} + {end:} +
    +
    +{else:} +
    +
    +

    Your cart is currently empty.

    +
    +
    +{end:} + + + +{if:option.cart_promotions} + +
    +
    You may also be interested in ...
    +
    + +
    +
    +
    + {foreach:cartPromotions,p} +
    + + {if:p.image} +
    + +
    + {end:} +
    + {if:p.short_descr}{p.short_descr:h}{end:} +
    + {if:option.ticket_shop.cart.show_promotion_images} +
    + {if:p.image} + + {end:} +
    + {end:} +
    + {end:} +
    +
    +
    +{end:} + + + + + + + + + diff --git a/views/front/FoundationStandAlone/Shop/checkout.html b/views/front/FoundationStandAlone/Shop/checkout.html new file mode 100755 index 0000000..4ad59ec --- /dev/null +++ b/views/front/FoundationStandAlone/Shop/checkout.html @@ -0,0 +1,1159 @@ + + + +
    + + + + +
    +
    + + + {term.nav.show_selected} + {if:!option.ticket_selection.start_at_cart} + {term.nav.select_more} + {end:} + + +

    {checkoutText:h}

    + +
    +
    + +{if:reason} +
    +
    +
    + We're sorry, we had a problem with your request: +
      + {foreach:reason,r}{Chuck} +
    • {r:h}
    • + {end:} +
    +
    +
    +
    +{end:} + + +
    +
    +
    +
    +
    + Contact Information +
    +
    +
    +
    +
    +
    + {if:formData.contact.fname.required}
    +
    +
    +
    + {if:formData.contact.lname.required}
    +
    +
    +
    + {if:formData.contact.addr1.required}
    +
    +
    +
    + {if:formData.contact.addr2.required}
    +
    +
    +
    + {if:formData.contact.city.required}
    +
    +
    +
    + {if:formData.contact.state.required}
    +
    +
    +
    + {if:formData.contact.country.required}
    +
    +
    +
    + {if:formData.contact.zip.required}
    +
    +
    +
    +
    +
    + {if:formData.contact.phone.required}
    +
    +
    +
    + {if:formData.contact.email.required}
    +
    +
    +
    + {if:formData.contact.email2.required}
    +
    +
    +
    + +
    +
    +
    +
    + {if:formData.contact.email_ok} +
    + {else:} +
    + {end:} +
    +
    + {if:opt_field_1_name} +
    +
    + {if:formData.contact.opt_field_1.required}
    +
    + {end:} + {if:opt_field_2_name} +
    +
    + {if:formData.contact.opt_field_2.required}
    +
    + {end:} + {if:opt_field_3_name} +
    +
    + {if:formData.contact.opt_field_3.required}
    +
    + {end:} +
    +
    +
    +
    +
    + + + +{foreach:cart,c} + + {if:option.show_location_blocks} +
    +
    +
    +
    +
    + {c.name:h} +
    +
    + {end:} + + + + {foreach:c.performances,p} + +
    +
    +
    + + + +
    +
    +

    {p.name:h}

    +
    +
    + + + +
    +
    + {if:p.short_descr} + {p.short_descr:h} + {else:} + {if:p.descr} + {p.descr:h} + {end:} + {end:} +
    +
    + + + + {foreach:p.dates,d} +
     
    +
    +
    +
    + {if:d.dateSpecific} + {d.fullDate} + {else:} + Use any date + {if:c.likelyDate} + - Likely Date {c.likelyDate} + {end:} + {end:} +
    +
    +
    + + + + {foreach:d.sections,s} +
    +
    + Quant +
    + {if:!p.oneSectionOnly} +
    + {term.section.cap} +
    +
    + {else:} +
    + {end:} + {term.ticket.cap} +
    +
    + Price +
    +
    + Sub-Total +
    +
    + + + + {foreach:s.tickets,i} +
    +
    + {i.selected} +
    + {if:!p.oneSectionOnly} +
    + {s.name:h} +
    +
    + {else:} +
    + {end:} + {i.title} +
    +
    + {if:i.show_price}{i.price}{end:} +
    +
    + {if:!i.show_addons}{if:i.show_price}{i.extended}{end:}{end:} +
    +
    + {if:option.packages} +
    Includes:
    + {foreach:i.packageData,y} +
    +
     
    +
    + {y.quant} +
    +
    + {y.title} - {y.performance_name} +
    +
    + {end:} +
     
    + {end:} + + + + {if:i.descr} +
    +
    +
    + {i.descr:h} +
    +
    + {end:} + + + + {foreach:i.addons,a} +
    +
     
    +
    + {a.selected} +
    +
    + {a.name} +
    +
    + {a.unit_cost}/{a.unit_name:h} +
    +
    + +
    +
    + {end:} + + {if:i.show_addons} +
    +
     
    +
    +   +
    +
    + {i.extended} +
    +
    + {end:} + + + + {if:i.promo} +
    +
     
    +
    + {term.promo.cap}: {promoCode} +
    +
    +
    + {i.promo.credit} +
    +
    + {end:} + + {end:} + + {end:} + + {end:} + + {if:p.policy} +
    +
    +

     

    +
    Please read and agree to our policy for this {term.performance.norm}.
    +

    {p.policy:h}

    + +
    +
    + {end:} + +
    +
    +
    + + {end:} + + + + {foreach:c.performances,p} + +
    +
    +
    + + + +
    +
    +

    {p.name:h}

    +
    +
    + + + +
    +
    + {if:p.short_descr} + {p.short_descr:h} + {else:} + {if:p.descr} + {p.descr:h} + {end:} + {end:} +
    +
    + + + + {foreach:p.dates,d} +
     
    +
    +
    + {if:d.dateSpecific} + {d.fullDate} + {else:} + Use any date + {if:c.likelyDate} + - Likely Date {c.likelyDate} + {end:} + {end:} +
    +
    + + + + {foreach:d.sections,s} + {if:!p.oneSectionOnly} +
    +
    + {term.section.cap}: {s.name:h} +
    +
    + {end:} + + + + {foreach:s.tickets,i} +
    +
    +

    {i.title}

    +
    +
    + {if:i.descr} +
    +
    +
    + {i.descr:h} +
    +
    + {end:} + +
    +
    + Quant +
    +
    {i.selected}
    + {if:i.show_price} +
    + Price +
    +
    {i.price}
    +
    + Sub-Total +
    +
    {if:!i.show_addons}{i.extended}{end:}
    + {end:} +
    + + + + {foreach:i.addons,a} +
    +
    + {a.name} +
    +
    {a.selected}
    +
    +
    +
    + {a.unit_cost}/{a.unit_name:h} +
    +
    {a.money}
    +
    + {end:} + + + + {if:i.promo} +
    +
     
    +
    + {term.promo.cap}: {promoCode} +
    +
    +
    + {i.promo.credit} +
    +
    + {end:} + {if:i.show_addons} +
    +
    + Sub-Total +
    +
    {i.extended}
    +
    + {end:} + + {end:} + + {end:} + + {end:} + + {if:p.policy} +
    +
    +

     

    +
    Please read and agree to our policy for this {term.performance.norm}.
    +

    {p.policy:h}

    + +
    +
    + {end:} + +
    +
    +
    + + {end:} + + {if:c.ticket_spec_req.value} +
    +
    + +
    +
    + {end:} + +{if:cartRequiresPayment} + {if:!formData.centralPayment} + + +
    +
    +
    +
    +
    +
    Payment for {term.ticket.plur} at {c.name:h}
    +
    +
    +
    {c.totalPrice}
    +
    +
    +
    +
    +   +
    +
    + + {if:c.paymentResult} + {if:c.paymentResult.approved} +
    +
    + Card Payment Approved +
    +
    +
    +
    + Name on Card: +
    +
    + {c.paymentResult.ccname} +
    +
    +
    +
    + Card Type: +
    +
    + {c.paymentResult.cctype} +
    +
    +
    +
    + Card Number: +
    +
    + {c.paymentResult.ccnumb} +
    +
    +
    +
    + Expiration Date: +
    +
    + {c.paymentResult.ccexp} +
    +
    +
    +
    + Authorization Code: +
    +
    + {c.paymentResult.authCode} +
    +
    + + {else:} +
    +
    +
    Card Payment Not Complete
    +
    +
    +
    +
    +

    {c.paymentResult.description}

    +

    Please check the payment information below and try again or contact your credit card company for assistance.

    + {if:forceCheckoutPhase} + {term.nav.delete_from_cart} + {end:} +
    +
    + {end:} + + {else:} + + {if:c.havePaymentMethod} +
    +
    + {if:c.haveMultiplePaymentMethods} +  PayPal + {else:} + + {end:} +
    +
    + + {if:c.haveCreditCards} +
    +
    + {if:c.haveMultiplePaymentMethods} +  Credit Card + {else:} + + {end:} +
    +
    +
    +
    + {if:c.paymentForm.cctype.required}
    +
    +
    +
    +
    + {if:c.paymentForm.ccname.required}
    +
    +
    +
    + {if:c.paymentForm.ccnumb.required}
    +
    +
    +
    +
    +
    +
    + {if:c.paymentForm.ccexp.required}
    +
    + {if:c.paymentForm.ccexp.required}
    +
    + {if:c.paymentForm.ccexp.problem} + {c.paymentForm.ccexp.problem} + {end:} +
    +
    +
    +
    + {if:c.paymentForm.cccode.required}
    +
    +
    +
    +
    + The Security Code is the three or four digit number on the signature side of your credit card. +
    +
    + {end:} + + {if:c.havePayPal} +
    +
    + +
    +
    + {end:} + + {end:} + + {end:} + +
    +
    +
    + + {end:} +{end:} + {if:c.no_payment} + +
    +
    +

    + + No payment is being processed for these {term.ticket.plur} at this time.
    Payment for these items must be arranged directly with {owner.name}. +

    +
    +
    + + {end:} + + {if:option.show_location_blocks} +
    +
    +
    + {end:} +{end:} + +{if:cartRequiresPayment} +{if:formData.centralPayment} + + {if:formData.centralPayment.havePaymentMethod} + +
    +
    +
    + +
    +
    +

    + Total Charged {totals.price} +

    +
    +
    + +
    +
    + {if:formData.centralPayment.haveMultiplePaymentMethods} +  PayPal + {else:} + + {end:} +
    +
    + + {foreach:formData.centralPayment.paymentForm,p} + {if:formData.centralPayment.haveCreditCards} +
    +
    + {if:formData.centralPayment.haveMultiplePaymentMethods} +  Credit Card + {else:} + + {end:} +
    +
    +
    +
    + {if:p.ccname.required}
    +
    +
    +
    + {if:p.cctype.required}
    +
    +
    +
    +
    + {if:p.ccnumb.required}
    +
    +
    +
    +
    +
    +
    + {if:p.ccexp.required}
    +
    + {if:p.ccexp.required}
    +
    + {if:p.ccexp.problem} + {p.ccexp.problem} + {end:} +
    +
    +
    +
    + {if:p.cccode.required}
    +
    +
    +
    +
    + The Security Code is the three or four digit number on the signature side of your credit card. +
    +
    + {end:} + {end:} + + {if:formData.centralPayment.havePayPal} +
    +
    + +
    +
    + {end:} + + {else:} +
    +
    +

    + No payment is being processed at this time. Payment for these items must be arranged directly with {owner.name}. +

    +
    +
    + + {end:} + +
    +
    +
    + + +{else:} + +
    +
    + Total Charged {totals.price} + {if:!cartHasOneVenueOnly} +

    NOTE: There will be a separate credit card transaction for each {term.prop.norm}.

    + {end:} +
    +
    + +{end:} +{end:} + +
    +
    + {ssl_seal_head_script:h} + {ssl_seal_body_script:h} +
    +
    + {if:!blockCheckout} + {term.nav.purchase} + {else:} + Unable to checkout - please see above. + {end:} +
    +
    + + + + + + \ No newline at end of file diff --git a/views/front/FoundationStandAlone/Shop/checkoutSuccess.html b/views/front/FoundationStandAlone/Shop/checkoutSuccess.html new file mode 100755 index 0000000..820bf82 --- /dev/null +++ b/views/front/FoundationStandAlone/Shop/checkoutSuccess.html @@ -0,0 +1,638 @@ + + + +{if:checkoutSucccessText} +
    +
    + +

    {checkoutSuccessText:h}

    +
    +
    +{end:} + +
    +
    + Purchase Complete +
    +
    + + + +
    +
    +
    +
    +
    + {foreach:cart,c} + {if:c.paymentResult} + {if:c.paymentResult.approved} +

    + CLick Here to download and PRINT your order
    summary and VOUCHERS for {c.name}

    + CLick Here to download your non-printable
    order summary and MOBILE FRIENDLY VOUCHERS
    +

    + {end:} + {end:} + {end:} +
    +
    + {foreach:cart,c} + {if:c.paymentResult} + {if:c.paymentResult.approved} +

    + CLick Here to download your non-printable
    MOBILE FRIENDLY VOUCHERS
    for {c.name}
    + CLick Here to download and PRINT
    your order summary and VOUCHERS
    for {c.name}

    +

    + {end:} + {end:} + {end:} +
    +
    +
    +
    + Adobe Reader is required to view and print your {term.voucher.plur}. Adobe Reader is a free program available directly from Adobe. + If you do not already have Adobe Reader installed, click the "Get Adobe Reader" link now. +
    +
    + +
    +
    + + If you are unable to print your {term.voucher.plur}, please print this page or write down the order number(s) + below and bring that to the ticket office when you arrive. + +
    +
    + ORDER #: + {foreach:cart,c} + {if:c.paymentResult} + {if:c.paymentResult.approved} + {c.paymentResult.orderID}  + {end:} + {end:} + {end:} +
    +
    +
    +
    +
    + + + +
    +
    +
    +
    +
    + Contact Information +
    +
    +
    +
    + Name: +
    +
    + {formData.contact.fname.value} {formData.contact.lname.value} +
    +
    +
    +
    + {text.cart.checkout.address}: +
    +
    + {formData.contact.addr1.value}
    + {if:formData.contact.addr2.value} + {formData.contact.addr2.value}
    + {end:} + {formData.contact.city.value}, {formData.contact.state.name} {formData.contact.zip.value}
    + {formData.contact.country.name} +
    +
    +
    +
    + {text.cart.checkout.phone}: +
    +
    + {formData.contact.phone.value} +
    +
    +
    +
    + {text.cart.checkout.email}: +
    +
    + {formData.contact.email.value} +
    +
    +
    +
    + OK to Send E-Mail?: +
    +
    + {if:formData.contact.email_ok} + You have asked us to send information on activities and offers. + {else:} + You have asked us to NOT send information on activities and offers. + We will only contact you regarding this order. + {end:} +
    +
    + {if:opt_field_1_name} +
    +
    + {opt_field_1_name}: +
    +
    + {formData.contact.opt_field_1.value} +
    +
    + {end:} + {if:opt_field_2_name} +
    +
    + {opt_field_2_name}: +
    +
    + {formData.contact.opt_field_2.value} +
    +
    + {end:} + {if:opt_field_3_name} +
    +
    + {opt_field_3_name}: +
    +
    + {formData.contact.opt_field_3.value} +
    +
    + {end:} + +
    +
    +
    + + + +{foreach:cart,c} + {if:!c.centralPaymentOnly} + + {if:option.show_location_blocks} +
    +
    +
    +
    +
    + {c.name:h} +
    +
    + {end:} + + + + {foreach:c.performances,p} +
    +
    +
    + + + +
    +
    +

    {p.name:h}

    +
    +
    + + + +
    +
    + {if:p.short_descr} + {p.short_descr:h} + {else:} + {if:p.descr} + {p.descr:h} + {end:} + {end:} +
    +
    + + + + {foreach:p.dates,d} +
    +
    +
    + {if:d.dateSpecific} + {d.fullDate} + {else:} + Use any date + {if:c.likelyDate} + - Likely Date {c.likelyDate} + {end:} + {end:} +
    +
    +
    + + + + {foreach:d.sections,s} +
    +
    + Quant +
    + {if:!p.oneSectionOnly} +
    + {term.section.cap} +
    +
    + {term.ticket.cap} +
    + {else:} +
    + {term.ticket.cap} +
    + {end:} +
    + Price +
    +
    + Total +
    +
    + + + + {foreach:s.tickets,i} +
    +
    Quant
    +
    {i.selected}
    +
    {i.selected}
    + {if:!p.oneSectionOnly} +
    {term.section.cap}
    +
    {s.name:h}
    +
    {term.ticket.cap}
    +
    {i.name:h}
    + {else:} +
    {term.ticket.cap}
    +
    {i.name:h}
    + {end:} +
    Price
    +
    {i.price}
    +
    {i.price}
    +
    Total
    +
    {i.extended}
    +
    {i.extended}
    +
    + {if:option.packages} +
    Includes:
    + {foreach:i.packageData,y} +
    +
     
    +
    + {y.quant} +
    +
    + {y.title} - {y.performance_name} +
    +
    + {end:} +
     
    + {end:} + + + + {if:i.descr} +
    +
    +
    + {i.descr:h} +
    +
    + {end:} + + + + {foreach:i.addons,a} +
    +
     
    +
    Quant
    +
    {a.selected}
    +
    {a.selected}
    + +
    {term.ticket.cap}
    +
    {a.name:h}
    + +
    Price
    +
    {a.unit_cost}/{a.unit_name:h}
    +
    {a.unit_cost}/{a.unit_name:h}
    + +
    Total
    +
    {a.money}
    +
    {a.money}
    +
    + {end:} + + + + {if:i.promo} +
    +
     
    +
    + {term.promo.cap}: {promoCode} +
    +
    +
    + {i.promo.credit} +
    +
    + {end:} + + {end:} + + {end:} + + {end:} + + {if:p.policy} + + + +
    +
    +

    {p.policy:h}

    +
    +
    + {end:} + +
    +
    +
    + + {end:} + + {if:c.paymentForm.spec_req.value} + + + +
    +
    + {c.paymentForm.spec_req.value:h} +
    +
    + {end:} + + {if:!formData.centralPayment} + + +
    +
    +
    +
    +
    + Payment for {term.ticket.plur} at {c.name:h} +
    +
    +
    {c.totalPrice}
    +
    +
    + {if:c.paymentResult.cctype} +
    +
    +   +
    +
    +
    +
    + Card Payment Approved +
    +
    +
    +
    + Card Type: +
    +
    + {c.paymentResult.cctype} +
    +
    +
    +
    + Name on Card: +
    +
    + {c.paymentResult.ccname} +
    +
    +
    +
    + Card Number: +
    +
    + {c.paymentResult.ccnumb} +
    +
    +
    +
    + Expiration Date: +
    +
    + {c.paymentResult.ccexp} +
    +
    +
    +
    + Authorization Code: +
    +
    + {c.paymentResult.authCode} +
    +
    + {else:} +
    +
    +

    *** Payment Processed Manually ***

    +
    +
    + {end:} +
    +
    +
    + + {end:}) + + + {if:c.ticket_policy} +
    +
    + {c.ticket_policy:h} +
    +
    + {end:} + + {if:option.show_location_blocks} +
    +
    +
    + {end:} + + {end:} +{end:} + + +{if:formData.centralPayment} +
    +
    +
    + +
    +
    +

    + Grand Total {totals.price} +

    +
    +
    + + {foreach:cart,c} + {if:c.paymentResult.cctype} +
    +
    + Card Payment Approved +
    +
    +
    +
    + Card Type: +
    +
    + {c.paymentResult.cctype} +
    +
    +
    +
    + Name on Card: +
    +
    + {c.paymentResult.ccname} +
    +
    +
    +
    + Card Number: +
    +
    + {c.paymentResult.ccnumb} +
    +
    +
    +
    + Expiration Date: +
    +
    + {c.paymentResult.ccexp} +
    +
    +
    +
    + Authorization Code: +
    +
    + {c.paymentResult.authCode} +
    +
    + {else:} + {if:c.isCentralPaymentMember} +
    +
    +

    *** Payment Processed Manually ***

    +
    +
    + {end:} + {end:} + + {end:} + +
    +
    +
    + + +{else:} + + +
    +
    + Grand Total {totals.price}
    +{if:!cartHasOneVenueOnly} +

    NOTE: You will see a separate credit card transaction for each {term.prop.norm} above.

    +{end:} +
    +
    + +{end:} + + + + + + + + + + + + + + + + + +{trackingScript:h} + + + \ No newline at end of file diff --git a/views/front/FoundationStandAlone/Shop/paymentSummary.html b/views/front/FoundationStandAlone/Shop/paymentSummary.html new file mode 100755 index 0000000..1ba213f --- /dev/null +++ b/views/front/FoundationStandAlone/Shop/paymentSummary.html @@ -0,0 +1,103 @@ +

    + + Click here to reprint your {term.voucher.plur} + +

    + +

    + {term.ticket.plur_cap} Purchased at:
    + {cartEntry.name} +

    + + +{if:cartEntry.descr}

    {cartEntry.descr:h}

    {end:} + + + + + + + + + + + +{foreach:cartEntry.performances,p} + {foreach:p.dates,d} + {foreach:d.sections,s} + + + {foreach:s.tickets,i} + + + + + + + + {foreach:i.addons,a} + + + + + + + + {end:} + {if:i.promo} + + + + + + + {end:} + {end:} + + + {end:} + {end:} +{end:} + + + + + + + + +
    Quant{term.performance.cap}{term.ticket.cap}PriceTotal
    {i.selected}{p.name:h}{i.title:h}{if:i.show_price}{i.price}{end:}{if:i.show_price}{i.extended}{end:}
       +
    + {a.selected} {a.unit_name} +
    +
    {a.unit_cost}/{a.unit_name}{a.money}
      {term.promo.cap}: {promoCode}  + {i.promo.credit}
     {cartEntry.totalPrice}
    + + +{if:cartEntry.ticket_spec_req} +

    + Special requests: {cartEntry.paymentForm.spec_req.value:h} +

    +{end:} + + +{if:cartEntry.ticket_policy}

    {cartEntry.ticket_policy:h}

    {end:} + +

    + + + + + + + +
    Credit Card Payment Approved
    Card Type{cartEntry.paymentResult.cctype}
    Name on Card{cartEntry.paymentResult.ccname}
    Card Number{cartEntry.paymentResult.ccnumb}
    Expiration Date{cartEntry.paymentResult.ccexp}
    Authorization Code{cartEntry.paymentResult.authCode}
    +

    + + \ No newline at end of file diff --git a/views/front/FoundationStandAlone/Shop/sectionSelect.html b/views/front/FoundationStandAlone/Shop/sectionSelect.html new file mode 100755 index 0000000..4f5e1b3 --- /dev/null +++ b/views/front/FoundationStandAlone/Shop/sectionSelect.html @@ -0,0 +1,96 @@ + + + + + + +
    + + +
    {term.section.cap} Selection
    + + + + + +
    {sectionText:h}
    + +{if:reason} +
    +
    We're sorry, we had a problem with your request:
    +
      + {foreach:reason,r} +
    • {r:h}
    • + {end:} +
    +
    +{end:} + +

    You have selected

    +
    +
    +
    +
    {performanceDetail.member_name}

    +
    {performanceDetail.name}
    +
    +
    + + +
    +
    +
    + + +
    +

    Please select from the following

    +
    +{foreach:sectionList,x} +
    + +
    +

    {term.section.cap}: {x.member_name}

    +

    {x.descr:h}

    +
    +
    +{end:} + +
    + +
    + + + \ No newline at end of file diff --git a/views/front/FoundationStandAlone/Shop/start-COPY.html b/views/front/FoundationStandAlone/Shop/start-COPY.html new file mode 100644 index 0000000..feda2b4 --- /dev/null +++ b/views/front/FoundationStandAlone/Shop/start-COPY.html @@ -0,0 +1,162 @@ + + +
    +
    +
    +
    +
    {m.name}
    +
    +
    +
    Address: {m.addr1}{if:m.addr2}, {m.addr2}{end:}, {m.city}
    +
    Phone #: {m.phone}
    +
    {m.descr:h}
    +
    +
    +
    +
    (map loads here)
    +
    + + +
    +
    + +
    + {foreach:m.performances,p} +
    +
    +
    +
    + {if:showTickets} + {p.name} + {else:} + {p.name} + {end:} +
    +
    +
    +
    {term.prop.cap}: {p.member_name}
    +
    Dates: {p.start_date.date} through {p.end_date.date}
    +
    +
    + {if:!showTickets} + {term.nav.select} + {end:} + + + {foreach:p.sections,s} +

     

    +
    +
    +
    + {if:!p.oneSectionOnly} + {s.sectionDetail.name}
    + {end:} + +
    + +
    +
    + + + {foreach:s.ticketsData,x} +
    + {if:option.ticket_selection.include_options_in_ticket_list} +
    +
    +
    Price: 
    +
    +
    {x.price}
    +
    +
    +
    +
    Select date: 
    +
    +
    + + +
    +
    +
    +
    +
    Quant: 
    +
    +
    (select date)
    +
    +
    +
    + + {end:} + +
    + {if:option.ticket_selection.include_options_in_ticket_list} +
    {x.title}
    + {else:} +
    + {x.name} +
    + {term.nav.select} + {end:} +
    +
    + {if:x.descr} +

    {x.descr:h}

    + {end:} +
    + {if:!x.date_specific.value} + Use any date{if:x.start_date.timestamp} from {x.start_date.date} to {x.end_date.date}{end:}{if:!x.time_specific.value}, {end:} + {end:} + {if:!x.time_specific.value} + Use any time of day, + {else:} + Time: {x.ticket_time.time}, + {end:} + {if:x.unlimted_use.value} + Each {term.ticket.norm} may be used an unlimited number of times + {else:} + + {end:} +
    +
    +
    + {if:option.ticket_selection.include_options_in_ticket_list} +
    +
    +
    Price each: 
    +
    +
    {x.price}
    +
    +
    +
    +
    Select date: 
    +
    +
    + + +
    +
    +
    +
    +
    Quant: 
    +
    +
    (select date)
    +
    +
    +
    + + {end:} +
    + + + {end:} + +
    + + {end:} + + + +
    + {end:} +
    +
    + {end:} diff --git a/views/front/FoundationStandAlone/Shop/start.html b/views/front/FoundationStandAlone/Shop/start.html new file mode 100755 index 0000000..681bd15 --- /dev/null +++ b/views/front/FoundationStandAlone/Shop/start.html @@ -0,0 +1,882 @@ + + + +{if:showTickets} + +
    + + + + +{end:} + + + +
    +
    + + + {term.nav.show_selected} + {term.nav.add_to_cart} + + +

    {ticketText:h}

    + +
    +
    + +{if:reason} +
    +
    +
    + We're sorry, we had a problem with your request: +
      + {foreach:reason,r}{Chuck} +
    • {r:h}
    • + {end:} +
    +
    +
    +
    +{end:} + + + +{foreach:membersList,m} + + + + + + + + + + + + + + + {if:option.ticket_shop.start.show_performances} + + {foreach:m.performances,p} + +
    +
    + name == $liveMusic){ ?> + Family Fun Cruises + + name == $ferry || $p->name == $valet || $p->name == $guide || $p->name == $sunset || $p->name == $fireWorks) { ?> +
    + name == $liveMusic) { ?> +
    + +
    + + +
    +
    + {if:!option.ticket_shop.start.show_sections} + name != $ferry && $p->name != $valet && $p->name != $guide){ ?> + {term.nav.select} + + + {p.name:h} + + {else:} + {p.name:h} + {end:} +
    +
    + + + +
    +
    + + {foreach:p.sections,s} + + + + + {if:!p.oneSectionOnly} + {s.sectionDetail.name}
    + {end:} + + +

    {p.short_descr:h}

    + + + + + + + {foreach:s.ticketsData,x} + + + {if:x.show_on_start.value} + + {if:x.mayBuyNow} + +
    +
    +
    +
    +
    + + + +
    +
    + + {if:option.ticket_selection.include_options_in_ticket_list} + price != '$0.00'){ ?> +
    {x.title} - {x.price}
    + title == 'Child Under 5'){ ?> +
    {x.title} - Free
    + +
    {x.title}
    + + {else:} + {x.name} + {end:} +
    +
    +
    +
    + + {if:x.descr} + + {end:} + + +
    +
    + {if:option.packages} + {foreach:x.packageData,y} +
    +
     
    +
    + {y.quant} +
    +
    + {y.title} - {y.performance_name} +
    +
    + {end:} + {end:} +
    + + {if:option.ticket_selection.include_options_in_ticket_list} + +
    + + + {if:x.date_specific.value} + + {end:} + + + + + {foreach:x.addons,a} + + + + {end:} + +
    +
    + + {end:} + +
    + + {if:x.show_on_start.value} +
    + {end:} +
    +
    + {end:} + {end:} + {end:} + + + {end:} + + {if:option.ticket_shop.start.show_performance_descr_short} + + {else:} + {if:p.descr} + + {end:} + {end:} + {if:option.ticket_shop.start.show_performance_start_end_dates} +
    + + {end:} +
    + {if:option.ticket_shop.start.show_performance_image} + {if:p.image} + +
    + +
    + +
    + +
    + {end:} + {end:} +
    + name == $guide){ ?> + + Add to cart and proceed to checkout + + + + +
    +
    +
    + + + {end:} + + {end:} + + + + + + + +{end:} + + + + + + + + + + + + +{if:option.ticket_selection.include_options_in_ticket_list} + + + {startScript:h} + var tickets = {ticketsJSON:h}; + + + + + + + +{end:} + + diff --git a/views/front/FoundationStandAlone/Shop/ticketOpt.html b/views/front/FoundationStandAlone/Shop/ticketOpt.html new file mode 100755 index 0000000..f0b3bc6 --- /dev/null +++ b/views/front/FoundationStandAlone/Shop/ticketOpt.html @@ -0,0 +1,286 @@ + + + + + +
    + +
    +
    Ticket Selection
    + + +
    + +
    {ticketOptText:h}
    + {if:reason} +
    +
    We're sorry, we had a problem with your request:
    +
      + {foreach:reason,r} +
    • {r:h}
    • + {end:} +
    +
    + {end:} +

    You have selected

    + +
    +
    +
    +
    {performanceDetail.name}
    +
    +
    +
    {term.prop.cap}: {performanceDetail.member_name}
    + + +
    +
    +
    +
    +
    {sectionDetail.name}
    +
    +
    + +
    +
    +
    +
    +
    {ticketDetail.name}
    +
    +
    + {if:!ticketDetail.date_specific.value} +
    Use any date {if:ticketDetail.start_date.timestamp} from {ticketDetail.start_date.date} to {ticketDetail.end_date.date}{end:}
    + {end:} + {if:!ticketDetail.time_specific.value} +
    Use any time
    + {else:} +
    Time: {ticketDetail.ticket_time.time}
    + {end:} + {if:!ticketDetail.unlimted_use.value} + + {else:} +
    Each {term.ticket.norm} may be used an unlimited number of times
    + {end:} +
    {ticketDetail.descr:h}
    +
    +
    +
    + +

    Please select from the following

    +
    +
    +
    +
    +
    +
    +
    +
    Select desired date:
    +
    +
    (click in field to set date)
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    Select Quantity:
    +
    +
    (please select date first)
    +
    +
    +
    +
    + {if:reason}
    (disabled - please see above)
    {else:}
    {term.nav.add_to_cart}
    {end:} +
    + + + + + + \ No newline at end of file diff --git a/views/front/FoundationStandAlone/Shop/ticketSelect.html b/views/front/FoundationStandAlone/Shop/ticketSelect.html new file mode 100755 index 0000000..ed06255 --- /dev/null +++ b/views/front/FoundationStandAlone/Shop/ticketSelect.html @@ -0,0 +1,491 @@ + + + + + + + + + + + +
    +
    + + + {term.nav.show_selected} + {if:!option.ticket_shop.start_at_cart} + {term.nav.select_more} + {end:} + + +

    {ticketText:h}

    + +
    +
    + +{if:reason} +
    +
    +
    + We're sorry, we had a problem with your request: +
      + {foreach:reason,r}{Chuck} +
    • {r:h}
    • + {end:} +
    +
    +
    +
    +{end:} + + + + + + + + +{foreach:sections,s} + +
    +
    +
    + + + +
    +
    + {performanceDetail.member_name:h}
    +

    {performanceDetail.name:h}

    + + {if:!oneSectionOnly} +
    {s.sectionDetail.name}
    + {end:} + {if:performanceDetail.descr} + {performanceDetail.descr:h} + {end:} +
    + {if:performanceDetail.image} +
    +
    + + +
    +
    + {end:} +
    + +
    +
    +
    + + + + {foreach:s.ticketsData,x} + {if:x.mayBuyNow} + +
    +
    +
    +
    +
    + + + +
    +
    + + {if:option.ticket_selection.include_options_in_ticket_list} +
    {x.title}
    + {else:} + {x.name} + {end:} +
    +
    +
    +
    + + {if:x.descr} + {x.descr:h} + {end:} + +

    + {if:!x.date_specific.value} + Use any date{if:x.start_date.timestamp} from {x.start_date.date} to {x.end_date.date}{end:}
    + {end:} + + {if:!x.time_specific.value} + Use any time of day, + {else:} + Time: {x.ticket_time.time} + {end:} + + {if:x.unlimted_use.value} + Each {term.ticket.norm} may be used an unlimited number of times + {end:} +

    +
    +
    + {if:option.packages} + {foreach:x.packageData,y} +
    +
     
    +
    + {y.quant} +
    +
    + {y.title} - {y.performance_name} +
    +
    + {end:} + {end:} +
    + + {if:option.ticket_selection.include_options_in_ticket_list} + +
    + Price: + {x.price} + + {if:x.date_specific.value} + + {end:} + + + + + {foreach:x.addons,a} + + + + {end:} + +
    +
    + + {end:} + +
    +
    +
    + {end:} + {end:} + +{end:} + + + + + + + +{if:option.ticket_selection.include_options_in_ticket_list} + + + {startScript:h} + var tickets = {ticketsJSON:h}; + + + + + + + +{end:} + \ No newline at end of file diff --git a/views/front/FoundationStandAlone/foot.html b/views/front/FoundationStandAlone/foot.html new file mode 100755 index 0000000..253ba60 --- /dev/null +++ b/views/front/FoundationStandAlone/foot.html @@ -0,0 +1,27 @@ + + + {if:option.development} +
    +
    +
    +
    +
    +
    Running on Development Server:
    +
    + +
    +
    +
    +
    + {end:} + + + + + diff --git a/views/front/FoundationStandAlone/head.html b/views/front/FoundationStandAlone/head.html new file mode 100755 index 0000000..9f092df --- /dev/null +++ b/views/front/FoundationStandAlone/head.html @@ -0,0 +1,71 @@ + + + + + + {if:!jQueryLoaded} + + + + {end:} + + {if:!jQueryUiLoaded} + + + + + {end:} + + {if:!siteHasFoundation} + + + {end:} + + + + + + + {if:customCssFile} + + + + + {end:} + + {if:frontDebug} + + +
    + + + + + {end:} + + +
    +
    Updating your information
    Please wait ...
    +
    Updating
    Please wait ...
    +
    + + {if:adminUser} +

    Purchasing By Admin User

    + {end:} + \ No newline at end of file diff --git a/views/front/FoundationStandAlone/index.html b/views/front/FoundationStandAlone/index.html new file mode 100755 index 0000000..fca55f0 --- /dev/null +++ b/views/front/FoundationStandAlone/index.html @@ -0,0 +1,34 @@ + + + + + + + + + + +

    PLEASE NOTE:

    + +

    + There is no general access to this site. + All access to this site should be through an appropriate link. + If you arrived here by mistake (or exploring), nothing but this message will be displayed. + If you have any concerns about this site, please contact Gaslight Media. +

    + +

    + Gaslight Media
    + 120 East Lake Street
    + Petoskey, MI 49770
    +  
    + Phone: 231-487-0692
    + E-Mail: info@gaslightmedia.com
    + Web: http://www.gaslightmedia.com +

    + + + + + + diff --git a/views/front/Gaslight/Debug/index.html b/views/front/Gaslight/Debug/index.html new file mode 100755 index 0000000..a42397f --- /dev/null +++ b/views/front/Gaslight/Debug/index.html @@ -0,0 +1,42 @@ + + + + + + +
    Startup: {debugStartupTime}
    +
    Event Management Front-End Debug
    +
    +
    + Updated: {debugUpdateTime} +
    +
    + {debugData:h} +
    + + + {startScript:h} + + // Reload the current window with Action = Debug_update + function reloadDebugWindow() + { + window.location("{baseSCRIPT}&Action=Debug_update"); + } + + + \ No newline at end of file diff --git a/views/front/Gaslight/Debug/start.html b/views/front/Gaslight/Debug/start.html new file mode 100755 index 0000000..66c3023 --- /dev/null +++ b/views/front/Gaslight/Debug/start.html @@ -0,0 +1,27 @@ + + + + + + +
    Startup: {debugStartupTime}
    +
    Event Management Front-End Debug
    +
    +
    Debug Startup
    + + \ No newline at end of file diff --git a/views/front/Gaslight/Shop/PayPalApproved.html b/views/front/Gaslight/Shop/PayPalApproved.html new file mode 100755 index 0000000..3cfafba --- /dev/null +++ b/views/front/Gaslight/Shop/PayPalApproved.html @@ -0,0 +1,41 @@ + + + + + +
    + +

    Your PayPal payment has been approved.

    + + +
    + +

    + Your cart will now reflect that the payment has been made. +

    + +
    + +
    +
    Close This Window
    +
    + +
    + + + + diff --git a/views/front/Gaslight/Shop/PayPalFail.html b/views/front/Gaslight/Shop/PayPalFail.html new file mode 100755 index 0000000..1307098 --- /dev/null +++ b/views/front/Gaslight/Shop/PayPalFail.html @@ -0,0 +1,49 @@ + + + + + +
    + +

    Unable to process your payment!

    + + +
    + +

    +

    Sorry, there was a problem.
    +

    + +

    + We were unable to find your purchase information and are therefore + are unable to process your payment through PayPal. This could be + due to you not performing any action with your pending purchase + for too long. Please click the "Return to selected tickets" button + at the top of the checkout page to see if your selections are still listed. +

    + +
    + +
    +
    Close This Window
    +
    + +
    + + + + diff --git a/views/front/Gaslight/Shop/additionalInfo.html b/views/front/Gaslight/Shop/additionalInfo.html new file mode 100644 index 0000000..4fa4164 --- /dev/null +++ b/views/front/Gaslight/Shop/additionalInfo.html @@ -0,0 +1,246 @@ + + + +
    + + + +
    +
    + + + {term.nav.show_selected} + {if:!option.ticket_shop.start_at_cart} + {term.nav.select_more} + {end:} + + +

    {cartText:h}

    + +
    +
    + +{if:reason} + + + +
    +
    +
    +

    We're sorry, we had a problem with your request:

    +
      + {foreach:reason,r}{Chuck} +
    • {r:h}
    • + {end:} +
    +
    +
    +
    +{end:} + + + +{foreach:cart,c} + + {if:option.show_location_blocks} +
    +
    +
    +
    +

    {c.name:h}

    +
    + {end:} + + + + + {if:c.needAssignemntOrDate} + {if:c.needAssignment} + +
    + {if:!c.haveAssignment} +
    {text.cart.select_assignment_location}
    + {else:} +
    {text.cart.select_assignment_location}
    + {end:} + {foreach:c.assignmentMembers,a} + {if:a.entrances} + {foreach:a.entrances,e} +
    + {if:option.cart_images} + {if:e.image} +
    + {end:} + {end:} +
    + {if:e.selected} + {a.name} - {e.name}
    + {else:} + {a.name} - {e.name}
    + {end:} +
    +
    {e.addr1}{if:e.addr2}, {e.addr2}{end:}, {e.city}
    +
    {e.phone}
    + {if:e.descr} +
    {e.descr:h}
    + {end:} +
    +
    + {end:} +
    + {else:} + {if:a.selected} + {a.name}
    + {else:} + {a.name}
    + {end:} + {end:} + {end:} +  
    + {end:} + + {if:option.ask_for_likely_date} + {if:c.needLikelyDate} +
    +

    + {if:!c.likelyDate} + + {else:} + + {end:} + {text.cart.select_likely_date}   + + mm/dd/yyyy + {if:text.cart.select_likely_date_explain} +
    {text.cart.select_likely_date_explain} + {end:} +

    +
    + {end:} + {end:} +
    +
    + {end:} + {if:!c.needAssignment} + + {if:option.cart_images}{if:c.image} +
    + + +
    + {end:}{end:} + {end:} + +
    +
    +
    + +{end:} + + + +{if:cartHasContents} +
    +
    + {if:!blockCheckout} + {term.nav.checkout} + {else:} + Please complete the items in RED above. + {end:} +
    +
    +{else:} +
    +
    +

    Your cart is currently empty.

    +
    +
    +{end:} + + + + + + + + + diff --git a/views/front/Gaslight/Shop/cart.html b/views/front/Gaslight/Shop/cart.html new file mode 100755 index 0000000..e0e7db8 --- /dev/null +++ b/views/front/Gaslight/Shop/cart.html @@ -0,0 +1,422 @@ + + + +
    +
    + + +
    + + +
    + {if:!option.ticket_selection.start_at_cart} + {term.nav.select_more} + {end:} + +
    +
    + +
    {cartText:h}
    + {if:reason} +
    +
    We're sorry, we had a problem with your request:
    +
      + {foreach:reason,r}{Chuck} +
    • {r:h}
    • + {end:} +
    +
    + {end:} + {if:havePromoCodes} +
    +
    +
    If you have a {term.promo.norm}, please enter it here:
    +
    +
    + {end:} + {foreach:cart,c} +
    +
    {c.name}
    +
    + {foreach:c.performances,p} +
    +
    + {if:!option.ticket_selection.start_at_cart} + {term.nav.select_more_of_these} + {end:} +
    + +
    {p.name}
    +
    + {if:p.descr}
    {p.descr:h}
    {end:} + {if:p.short_descr}
    {p.short_descr:h}
    {end:} + {if:option.cart_images}{if:p.image} + + {end:}{end:} +
    +
    +
    +
    + {foreach:p.dates,d} +
    + {if:d.dateSpecific} + {d.fullDate} + {else:} + + {if:c.likelyDate} + - Likely Date {c.likelyDate} + {end:} + {end:} + {foreach:d.sections,s} + + + + {if:!p.oneSectionOnly} + + {end:} + + + + + {foreach:s.tickets,i} + + + {if:!p.oneSectionOnly} + + {end:} + + + + + {if:i.problem} + + + + {end:} + {if:i.descr} + + + {if:!p.oneSectionOnly} + + + {end:} + + {foreach:i.addons,a} + + + {if:!p.oneSectionOnly} + + {end:} + + + + + {end:} + + + {if:i.promo} + + + {if:!p.oneSectionOnly} + + {end:} + + + + {end:} + + {end:} +
    QuantSection{term.ticket.cap}PriceTotal
    + + {s.name} + {i.title} + {if:i.time_specific.value} + - {i.ticket_time.time} + {else:} + + {end:} + {if:i.show_price}{i.price}{end:}{if:i.show_price}{i.extended}{end:}
     {i.problemText}
      + {else:} + + {end:} + {if:option.cart_images}{if:i.image} +
    + {end:}{end:} +
    {i.descr:h}
    +
       +
    + +
    +
    {a.unit_cost}/{a.unit_name}{a.money}
      {term.promo.cap}: {promoCode}  + {i.promo.credit}
    + {end:} +
    + {end:} +
    +
    + {end:} +
    + {if:c.ticket_policy}
    {c.ticket_policy:h}
    {end:} + +{if:option.ask_for_assignment_and_likely_date} + {if:c.needAssignemntOrDate} + {if:c.needAssignment} + +
    + {if:!c.haveAssignment} +
    {text.cart.select_assignment_location}
    + {else:} +
    {text.cart.select_assignment_location}
    + {end:} + {foreach:c.assignmentMembers,a} + {if:a.entrances} + {foreach:a.entrances,e} +
    + {if:option.cart_images} + {if:e.image} +
    + {end:} + {end:} +
    + {if:e.selected} + {a.name} - {e.name}
    + {else:} + {a.name} - {e.name}
    + {end:} +
    +
    {e.addr1}{if:e.addr2}, {e.addr2}{end:}, {e.city}
    +
    {e.phone}
    + {if:e.descr} +
    {e.descr:h}
    + {end:} +
    +
    + {end:} +
    + {else:} + {if:a.selected} + {a.name}
    + {else:} + {a.name}
    + {end:} + {end:} + {end:} +  
    + {end:} + + {if:option.ask_for_likely_date} + {if:c.needLikelyDate} +
    + {if:!c.likelyDate} + + {else:} + + {end:} + {text.cart.select_likely_date}   + + mm/dd/yyyy +
    + {end:} + {end:} +
    +
    + {end:} + {if:!c.needAssignment} + + {if:option.cart_images}{if:c.image} +
    + + +
    + {end:}{end:} + {end:} +{end:} + + +
    + {end:} + + +
    + {if:cartHasContents} +
    + Grand Total   {totals.price} +
    +
    + {if:totals.tickets} + + {term.nav.checkout} + + {else:} + Your cart is currently empty. + {end:} +
    + {else:} +

    Your cart is currently empty.

    + {end:} +
    + + {if:option.cart_promotions} +
    + You may also be interested in ...
    + {foreach:cartPromotions,p} +
    + + {if:p.image} +
    + {end:} +
    + {if:p.start_date} +

    + Dates: {p.start_date.date} +

    + {end:} + + {if:p.short_descr}
    {p.short_descr:h}
    {end:} + {if:p.short_descr}
    {p.short_descr:h}
    {end:} +
    +
    + {end:} +
    + {end:} + + + +
    + +{startScript:h} + + $(document).ready(function(){ + + // Block direct form submission - Everything submits by jQuery action + $('#cartForm').submit(function( event ) { + return false; + }); + + // Convert input fields to select lists + $('.glmCartQuant').each(function() { + + var id = $(this).attr('id'); + var ticket = $(this).attr('data-ticket'); + var addon = $(this).attr('data-addon'); + var max = $(this).attr('data-max'); + var value = $(this).attr('value'); + var units = $(this).attr('data-units'); + var numbSel = ''; + + // Build a picklist for this input + for (var i = 0 ; i {lte:h} max ; i++) { + if (value == i) { + numbSel = numbSel.concat(''); + } else { + numbSel = numbSel.concat(''); + } + } + + $('#quant_' + id).html('' + units); + + }); + + // Get or set vertical scroll to return to same place when cart reloads + function getVertScroll() { + var vertScroll = window.pageYOffset; + if (vertScroll == 0) { + var vertScroll = document.documentElement.scrollTop; + } + if (vertScroll == 0) { + var vertScroll = document.body.scrollTop; + } + return vertScroll; + } + + // When a cart value changes, submit it as a cart update. + $('.glmCartSelect').change(function() { + vertScroll = getVertScroll(); + var ticket = $(this).attr('data-ticket'); + var addon = $(this).attr('data-addon'); + var value = $(this).val(); + + setBlocker(); + window.location = "{baseSCRIPT}&Action=Shop_cart&cart=update&ticket_inv=" + ticket + "&addon=" + addon + "&quant=" + value + "&vertScroll=" + vertScroll; + + }); + + // When there's a change in the promo code input, submit it. + $('#promoCodeInput').change(function() { + var value = $(this).val(); + setBlocker(); + window.location = "{baseSCRIPT}&Action=Shop_cart&cart=promo_code&promo_code=" + value; + }); + + // When a member selection for unassigned items changes, submit it so it's in the session + $('.glmAssignmentChange').change(function() { + vertScroll = getVertScroll(); + var member = $(this).attr('data-Member'); + var assignedTo = $(this).val(); + var assignedToEntrance = $(this).attr('data-entrance'); + setBlocker(); + window.location = "{baseSCRIPT}&Action=Shop_cart&cart=update_assignment&member_assigned=" + member + "&assigned_to=" + assignedTo + "&entrance_assigned=" + assignedToEntrance + "&vertScroll=" + vertScroll; + }); + + // When a likely departure date changes, submit it so it's in the session + $('.glmLikelyDateChange').change(function() { + vertScroll = getVertScroll(); + var member = $(this).attr('data-Member'); + var likelyDate = $(this).val(); + setBlocker(); + window.location = "{baseSCRIPT}&Action=Shop_cart&cart=update_likelyDate&member=" + member + "&likely_date=" + likelyDate + "&vertScroll=" + vertScroll; + + }); + + // Code to start datepicker for each date input + if($("#likelyDateInput").length > 0) { + $("#likelyDateInput").datepicker({ + dateFormat: "mm/dd/yy", + minDate: -1, + maxDate: 365 + }); + } + + // Checkout action + $('#GLMcheckoutBtn').click(function() { + setBlocker(); + window.location = "{baseSCRIPT}&Action=Shop_checkout"; + }); + + function setBlocker() { + $('#glmReloadBlocker').show(); + } + + $('#GLMnavSelectEvent').on('click', function() { // Return to Event Selection + setBlocker(); + window.location = '{startURL:h}'; + }); + +/* Not using right now + // Reprint order button + $('#reprintVoucher').on('keypress', function(event) { + if(event.which == '13'){ + var orderID = $(this).val(); + var voucherWindow = window.open('{appAdminURL}&Action=Order_printVoucher&OrderID=' + orderID, + "voucherPrint", + "height=750,width=600,menubar=yes,toolbar=yes,alwaysRaised=yes,menu" + ); + voucherWindow.focus(); + voucherWindow.print(); + return false; + } + }); +*/ + + if ({vertScroll}) { + window.scrollTo(0,{vertScroll}); + } + + }); + + + diff --git a/views/front/Gaslight/Shop/checkout.html b/views/front/Gaslight/Shop/checkout.html new file mode 100755 index 0000000..defa85c --- /dev/null +++ b/views/front/Gaslight/Shop/checkout.html @@ -0,0 +1,892 @@ + + + +
    + +
    +
    Selected {term.ticket.plur_cap}
    + +
    + {term.nav.show_selected} + {if:!option.ticket_selection.start_at_cart} + {term.nav.select_more} + {end:} +
    +
    + +
    {checkoutText:h}
    + {if:reason} +
    +
    We're sorry, we had a problem with your request:
    +
      + {foreach:reason,r} +
    • {r:h}
    • + {end:} +
    +

    See below for more information.

    +
    + {end:} +
    + + +
    +
    Contact Information
    + +
    +
    +
    {text.cart.checkout.first_name}:
    +
    {text.cart.checkout.first_name}:
    + {if:formData.contact.fname.problem} +
    +
    {formData.contact.fname.problem}
    + {else:} +
    + {end:} + +
    +
    +
    +
    {text.cart.checkout.last_name}:
    +
    {text.cart.checkout.last_name}:
    + {if:formData.contact.lname.problem} +
    +
    {formData.contact.lname.problem}
    + {else:} +
    + {end:} + +
    +
    +
    +
    {text.cart.checkout.address}:
    +
    {text.cart.checkout.address}:
    + {if:formData.contact.addr1.problem} +
    +
    {formData.contact.addr1.problem}
    + {else:} +
    + {end:} + +
    +
    +
    +
     
    +
     
    + {if:formData.contact.addr2.problem} +
    +
    {formData.contact.addr2.problem}
    + {else:} +
    + {end:} + +
    +
    +
    +
    {text.cart.checkout.city}:
    +
    {text.cart.checkout.city}:
    + {if:formData.contact.city.problem} +
    +
    {formData.contact.city.problem}
    + {else:} +
    + {end:} + +
    +
    +
    +
    {text.cart.checkout.state}:
    +
    {text.cart.checkout.state}:
    + {if:formData.contact.state.problem} +
    +
    {formData.contact.state.problem}
    + {else:} +
    + {end:} + +
    +
    +
    +
    {text.cart.checkout.country}:
    +
    {text.cart.checkout.country}:
    + {if:formData.contact.country.problem} +
    +
    {formData.contact.country.problem}
    + {else:} +
    + {end:} + +
    +
    +
    +
    {text.cart.checkout.zip}:
    +
    {text.cart.checkout.zip}:
    + {if:formData.contact.zip.problem} +
    +
    {formData.contact.zip.problem}
    + {else:} +
    + {end:} + +
    +
    +
    +
    {text.cart.checkout.phone}:
    +
    {text.cart.checkout.phone}:
    + {if:formData.contact.phone.problem} +
    +
    {formData.contact.phone.problem}
    + {else:} +
    + {end:} + +
    +
    +
    +
    {text.cart.checkout.email}:
    +
    {text.cart.checkout.email}:
    + {if:formData.contact.email.problem} +
    +
    {formData.contact.email.problem}
    + {else:} +
    + {end:} + +
    +
    +
    +
    {text.cart.checkout.email_again}:
    +
    {text.cart.checkout.email_again}:
    + {if:formData.contact.email2.problem} +
    +
    {formData.contact.email2.problem}
    + {else:} +
    + {end:} + +
    +
    +
    +
    OK to Send E-Mail?
    + {if:formData.contact.email_ok} +
    {text.cart.checkout.activities_offers}
    + {else:} +
    {text.cart.checkout.activities_offers}
    + {end:} +
    + + {if:opt_field_1_name} +
    +
    {opt_field_1_name}:
    +
    {opt_field_1_name}:
    + {if:formData.contact.opt_field_1.problem} +
    +
    {formData.contact.opt_field_1.problem}
    + {else:} +
    + {end:} + +
    +
    + {end:} + {if:opt_field_2_name} +
    +
    {opt_field_2_name}:
    +
    {opt_field_2_name}:
    + {if:formData.contact.opt_field_2.problem} +
    +
    {formData.contact.opt_field_2.problem}
    + {else:} +
    + {end:} + +
    +
    + {end:} + {if:opt_field_3_name} +
    +
    {opt_field_3_name}:
    +
    {opt_field_3_name}:
    + {if:formData.contact.opt_field_3.problem} +
    +
    {formData.contact.opt_field_3.problem}
    + {else:} +
    + {end:} + +
    +
    + {end:} + + +
    +
    + + {foreach:cart,c} + {if:c.performances} +
    +
    {term.prop.cap}: {c.name}
    + + +
    + + {foreach:c.performances,p} +
    +
    +
    +
    +
    {p.name}
    +
    + + {if:option.cart_images}{if:option.cart_images}{if:p.image}{end:}{end:}{end:} +
    +
    +
    +
    + {foreach:p.dates,d} +
    +
    + + {if:d.dateSpecific} + {d.fullDate} + {else:} + + {if:c.likelyDate} + - Likely Date {c.likelyDate} + {end:} + {end:} + +
    + + + {foreach:d.sections,s} + + + + {if:!p.oneSectionOnly} + + {end:} + + + + + {foreach:s.tickets,i} + + + {if:!p.oneSectionOnly} + + {end:} + + + + + {if:i.descr} + + + {if:!p.oneSectionOnly} + + + {end:} + + {foreach:i.addons,a} + + + {if:!p.oneSectionOnly} + + {end:} + + + + + {end:} + + {if:i.promo} + + + {if:!p.oneSectionOnly} + + {end:} + + + + {end:} + {end:} +
    QuantSection{term.ticket.cap}PriceTotal
    + {i.selected} + {s.name} + {i.title} + {if:i.time_specific.value} + - {i.ticket_time.time} + {else:} + + {end:} + {if:i.show_price}{i.price}{end:}{if:i.show_price}{i.extended}{end:}
      + {else:} + + {end:} + {if:option.cart_images} + {if:i.image} +
    + {end:} + {end:} +
    {i.descr:h}
    +
       +
    + {a.selected} {a.unit_name} +
    +
    {a.unit_cost}/{a.unit_name}{a.money}
      {term.promo.cap}: {promoCode}  + {i.promo.credit}
    + {end:} +
    + {end:} +
    +
    + {if:p.policy} +
    +
    + Please read and agree to our policy for this {term.performance.norm}. +
    +
    +

    {p.policy:h}

    +
    +
    +

    I agree to the policy stated above.

    +
    +
    + {end:} +
    + {end:} +
    + + {if:c.ticket_policy}
    {c.ticket_policy:h}
    {end:} + {if:c.ticket_policy}
    {c.ticket_policy:h}
    {end:} + +
    + + {if:c.ticket_spec_req.value} +
    +
    Please enter any special requests:
    +
    +
    + {end:} + + + {if:!formData.centralPayment} +
    + + {if:c.paymentResult} + {if:c.paymentResult.approved} +
    Card Payment Approved
    +
    Card Type
    {c.paymentResult.cctype}
    +
    Name on Card
    {c.paymentResult.ccname}
    +
    Card Number
    {c.paymentResult.ccnumb}
    +
    Expiration Date
    {c.paymentResult.ccexp}
    +
    Authorization Code
    {c.paymentResult.authCode}
    +
    +
    {term.nav.print_vouchers}
    +
    + {else:} +
    Card Payment Not Complete
    +
    • {c.paymentResult.description}
    +

    Please check the payment information below and try again or contact your credit card company for assistance.

    + {if:forceCheckoutPhase} +
    +
    {term.nav.delete_from_cart}
    +
    + {end:} + {end:} + {end:} + {if:c.paymentResult.approved} +

    Payment Accepted

    + {else:} + {if:c.havePaymentMethod} + +
    + {if:c.havePayPal} + {if:c.haveMultiplePaymentMethods} +  PayPal + {else:} + + {end:} + {end:} + {if:c.haveCreditCards} + {if:c.havePayPal} +      + {end:} + {if:c.haveMultiplePaymentMethods} +  Credit Card + {else:} + + {end:} + {end:} +
    + + {if:c.haveCreditCards} + {if:c.haveMultiplePaymentMethods} + + {else:} + + {end:} +
    +
    Total Charged to this Card
    +
    {c.totalPrice}
    +
    +
    +
    Card Type
    +
    Card Type
    + {if:c.paymentForm.cctype.problem} +
    +
    {c.paymentForm.cctype.problem}
    + {else:} +
    + {end:} + +
    +
    +
    +
    Name on Card
    +
    Name on Card
    + {if:c.paymentForm.ccname.problem} +
    +
    {c.paymentForm.ccname.problem}
    + {else:} +
    + {end:} + +
    +
    +
    +
    Card Number
    +
    Card Number
    + {if:c.paymentForm.ccnumb.problem} +
    +
    {c.paymentForm.ccnumb.problem}
    + {else:} +
    + {end:} + +
    +
    +
    +
    Expiration Date
    +
    Expiration Date
    + {if:c.paymentForm.ccexp.problem} +
    +
    {c.paymentForm.ccexp.problem}
    + {else:} +
    + {end:} + Month + + Year + +
    +
    +
    +
    Security Code
    +
    Security Code
    + {if:c.paymentForm.cccode.problem} +
    +
    {c.paymentForm.cccode.problem}
    + {else:} +
    + {end:} + +
    +
    +
    +
    + The Security Code is the three or four digit number on the signature side of your credit card. +
    +
    + + {end:} + {if:c.havePayPal} + + {if:c.haveMultiplePaymentMethods} + + {else:} + + {end:} +
    + +
    +
    + {end:} + {if:c.haveMultiplePaymentMethods} + +
    Please select a Payment Method
    +
    + {end:} + {else:} + +
    + This {term.prop.norm} does not have a payment method configured. + Please call this {term.prop.norm} to purchase {term.ticket.plur}. +
    +
    + {end:} + {end:} + +
    +
    + + {end:} +
    +
    + {end:} + + {if:!cartRequiresPayment} + + {end:} + + {end:} + +{if:cartRequiresPayment} + {if:formData.centralPayment} + +
    + + {if:formData.centralPayment.havePaymentMethod} + + {foreach:formData.centralPayment.paymentForm,p} + + {if:p.cctype} + + + +
    +
    + {if:formData.centralPayment.haveMultiplePaymentMethods} +  Credit Card + {else:} + + {end:} +
    +
    +
    +
    Card Type
    +
    Card Type
    +
    + +
    +
    +
    +
    Name on Card
    +
    Name on Card
    + {if:p.ccname.problem} +
    +
    {p.ccname.problem}
    + {else:} +
    + {end:} + +
    +
    +
    +
    Card Number
    +
    Card Number
    + {if:p.ccnumb.problem} +
    +
    {p.ccnumb.problem}
    + {else:} +
    + {end:} + +
    +
    +
    +
    Expiration Date
    +
    Expiration Date
    + {if:p.ccexp.problem} +
    +
    {p.ccexp.problem}
    + {else:} +
    + {end:} + Month + + Year + +
    +
    +
    +
    Security Code
    +
    Security Code
    + {if:p.cccode.problem} +
    +
    {p.cccode.problem}
    + {else:} +
    + {end:} + +
    +
    +
    +
    + The Security Code is the three or four digit number on the signature side of your credit card. +
    +
    + + {if:p.haveMultiplePaymentMethods} + +
    Please select a Payment Method
    +
    + {end:} + + {end:} + {end:} + +
    + + {else:} + +
    + This {term.prop.norm} does not have a payment method configured. + Please call this {term.prop.norm} to purchase {term.ticket.plur}. +
    +
    + + {end:} + + {end:} + +{end:} + + + +
    + {if:cartRequiresPayment} +
    +
    Complete Purchase
    + +

    + {ssl_seal_head_script:h} + {ssl_seal_body_script:h} +

    +
    + {else:} +
    +
    No Payment Required
    +
    + {end:} +
    +
    + {if:cartRequiresPayment} + +
    + +
    Grand Total
    +
    +
    + +
    {totals.price}
    +
    + {end:} +
    + {if:!cartHasOneVenueOnly} + + {end:} + + {if:adminUser} +
    + No payment info required for Admin User. +
    + {end:} + +
    + {if:!blockCheckout} + {term.nav.purchase} + {else:} + Unable to checkout - please see above. + {end:} +
    +
    +
    + +
    + + + + + + diff --git a/views/front/Gaslight/Shop/checkoutSuccess.html b/views/front/Gaslight/Shop/checkoutSuccess.html new file mode 100755 index 0000000..e7ef18e --- /dev/null +++ b/views/front/Gaslight/Shop/checkoutSuccess.html @@ -0,0 +1,374 @@ + + + + + +
    + + +
    Purchase Complete
    + + + + + {foreach:cart,c} + {if:c.paymentResult} + {if:c.paymentResult.approved} +

    +

    *** {term.nav.print_vouchers} for {c.name} ***
    +

    + {end:} + {end:} + {end:} + + + +
    +
    + +
    +
    + +

    + Adobe Reader is required to view and print your {term.voucher.plur}. Adobe Reader is a free program available directly from Adobe. + If you do not already have Adobe Reader installed, click the "Get Adobe Reader" link now. +

    +
    +
    +
    + +

    + If you are unable to print your {term.voucher.plur}, please print this page or write down the order number(s) + below and bring that to the ticket office when you arrive. +

    + ORDER #: + {foreach:cart,c} + {if:c.paymentResult} + {if:c.paymentResult.approved} + {c.paymentResult.orderID}  + {end:} + {end:} + {end:} +
    +
    +
    + + +
    {successText:h}
    + +
    +
    Contact Information
    +
    +
    First Name:
    {formData.contact.fname.value}
    +
    Last Name:
    {formData.contact.lname.value}
    +
    Address:
    {formData.contact.addr1.value}
    +
     
    {formData.contact.addr2.value}
    +
    City:
    {formData.contact.city.value}
    +
    State:
    {formData.contact.state.value}
    +
    Country:
    {formData.contact.country.value}
    +
    ZIP/Postal Code:
    {formData.contact.zip.value}
    +
    Phone:
    {formData.contact.phone.value}
    +
    E-Mail address:
    {formData.contact.email.value}
    + {if:opt_field_1_name}
    {opt_field_1_name}:
    {formData.contact.opt_field_1.value:h}
    {end:} + {if:opt_field_2_name}
    {opt_field_2_name}:
    {formData.contact.opt_field_2.value:h}
    {end:} + {if:opt_field_3_name}
    {opt_field_3_name}:
    {formData.contact.opt_field_3.value:h}
    {end:} +
     
    + {if:formData.contact.email_ok} + You have asked us to send information on activities and offers. + {else:} + You have asked us to NOT send information on activities and offers.
    + We will only contact you regarding this order. + {end:} +
    + +
    + +
    + + + {foreach:cart,c} +
    + +
    {term.ticket.plur_cap} at: {c.name}
    + + +
    + {if:c.descr}
    {c.descr:h}
    {end:} + {if:option.cart_images}{if:c.image}{end:}{end:} + +
    + +
    + + {foreach:c.performances,p} + +
    + +
    +
    +
    + {term.performance.cap}: {p.name} +
    +
    + + {if:option.cart_images}{if:option.cart_images}{if:p.image}{end:}{end:}{end:} +
    +
    +
    + +
    + {foreach:p.dates,d} + +
    + {term.ticket.cap} date: + + {if:d.dateSpecific} + {d.fullDate} + {else:} + Use any date + {if:c.likelyDate} + - Likely Date {c.likelyDate} + {end:} + {end:} + +
    + + + {foreach:d.sections,s} + + + + {if:!p.oneSectionOnly} + + {end:} + + + + + {foreach:s.tickets,i} + + + {if:!p.oneSectionOnly} + + {end:} + + + + + {if:i.descr} + + + {if:!p.oneSectionOnly} + + + {end:} + + {foreach:i.addons,a} + + + {if:!p.oneSectionOnly} + + {end:} + + + + + {end:} + + {if:i.promo} + + + {if:!p.oneSectionOnly} + + {end:} + + + + {end:} + {end:} +
    QuantSection{term.ticket.cap}PriceTotal
    + {i.selected} + {s.name} + {i.title} + {if:i.time_specific.value} + - {i.ticket_time.time} + {else:} + + {end:} + {if:i.show_price}{i.price}{end:}{if:i.show_price}{i.extended}{end:}
      + {else:} + + {end:} + {if:option.cart_images} + {if:i.image} +
    + {end:} + {end:} +
    {i.descr:h}
    +
       +
    + {a.selected} {a.unit_name} +
    +
    {a.unit_cost}/{a.unit_name}{a.money}
      {term.promo.cap}: {promoCode}  + {i.promo.credit}
    + {end:} + + + {end:} + +
    + +
    + + {if:p.policy} +
    +
    +
    + Our policy for this {term.performance.norm}. +
    +

    {p.policy:h}

    +
    +
    + {end:} + + {end:} + +
    + + + + {if:!cartHasOneVenueOnly} + +
    +
    +
    +
    Sub Total
    +
    +
    +
    {c.totalPrice}
    +
    +
    +
    + {end:} + + {if:c.ticket_policy}
    {c.ticket_policy:h}
    {end:} + + + {if:c.ticket_policy}
    {c.ticket_policy:h}
    {end:} + + +
    + + + {if:c.ticket_spec_req.value} +
    +
    Special requests:
    +
    {c.paymentForm.spec_req.value:h}
    +
    + {end:} + + + {if:c.paymentResult} +
    + {if:c.paymentResult.approved} +
    Card Payment Approved
    + +
    Card Type
    {c.paymentResult.cctype}
    +
    Name on Card
    {c.paymentResult.ccname}
    +
    Card Number
    {c.paymentResult.ccnumb}
    +
    Expiration Date
    {c.paymentResult.ccexp}
    +
    Authorization Code
    {c.paymentResult.authCode}
    +
    +
    {term.nav.print_vouchers}
    +
    + {else:} +
    Card Payment Not Complete
    +
    • {c.paymentResult.description}
    +

    Please check the payment information below and try again or contact your credit card company for assistance.

    + {if:forceCheckoutPhase} +
    +
    {term.nav.delete_from_cart}
    +
    + {end:} + + {end:} + +
    + {end:} + +
    + +
    + + {end:} + +
    + {if:cartHasContents} +
    +
    Cart Totals
    +
    +
    +
    Grand Total
    +
    +
    +
    {totals.price}
    +
    +
    +
    + {else:} +

    Your cart is currently empty.

    + {end:} +
    + +
    + +{trackingScript:h} + + + + + diff --git a/views/front/Gaslight/Shop/paymentSummary.html b/views/front/Gaslight/Shop/paymentSummary.html new file mode 100755 index 0000000..c42a21c --- /dev/null +++ b/views/front/Gaslight/Shop/paymentSummary.html @@ -0,0 +1,125 @@ +

    + + Click here to reprint your {term.voucher.plur} + +

    + +

    + + {cartEntry.name} +

    + + + + + + + + + + + + + + +{foreach:cartForSummaryCentral,c} +{foreach:c.performances,p} + {foreach:p.dates,d} + {foreach:d.sections,s} + + + {foreach:s.tickets,i} + + + + + + + + {foreach:i.addons,a} + + + + + + + + {end:} + {if:i.promo} + + + + + + + {end:} + {end:} + + + {end:} + {end:} +{end:} + + + + + + + + +
    Quant{term.performance.cap}{term.ticket.cap}PriceTotal
    {i.selected}{p.name:h} + {i.title:h} + {if:i.time_specific.value} + - {i.ticket_time.time} + {else:} + + {end:} + {if:i.show_price}{i.price}{end:}{if:i.show_price}{i.extended}{end:}
       +
    + {a.selected} {a.unit_name} +
    +
    {a.unit_cost}/{a.unit_name}{a.money}
      {term.promo.cap}: {promoCode}  + {i.promo.credit}
     {c.totalPrice}
    + + +{if:c.ticket_spec_req} +

    + {c.paymentForm.spec_req.value:h} +

    +{end:} + +{end:} + +{if:cartEntry.ticket_policy}

    {cartEntry.ticket_policy:h}

    {end:} + + + + + + + + + + + + +
    First Name:{formData.contact.fname.value}
    Last Name:{formData.contact.lname.value}
    Address:{formData.contact.addr1.value}
     {formData.contact.addr2.value}
    City:{formData.contact.city.value}
    State:{formData.contact.state.value}
    Country:{formData.contact.country.value}
    ZIP/Postal Code:{formData.contact.zip.value}
    Phone:{formData.contact.phone.value}
    E-Mail address:{formData.contact.email.value}
    + +

    + + + + + + + +
    Credit Card Payment Approved
    Card Type{cartEntry.paymentResult.cctype}
    Name on Card{cartEntry.paymentResult.ccname}
    Card Number{cartEntry.paymentResult.ccnumb}
    Expiration Date{cartEntry.paymentResult.ccexp}
    Authorization Code{cartEntry.paymentResult.authCode}
    +

    + + diff --git a/views/front/Gaslight/Shop/sectionSelect.html b/views/front/Gaslight/Shop/sectionSelect.html new file mode 100755 index 0000000..2767f00 --- /dev/null +++ b/views/front/Gaslight/Shop/sectionSelect.html @@ -0,0 +1,96 @@ + + + + + + +
    + + +
    {term.section.cap} Selection
    + + + + + +
    {sectionText:h}
    + +{if:reason} +
    +
    We're sorry, we had a problem with your request:
    +
      + {foreach:reason,r} +
    • {r:h}
    • + {end:} +
    +
    +{end:} + +

    You have selected

    +
    +
    +
    +
    {performanceDetail.member_name}

    +
    {performanceDetail.name}
    +
    +
    + + +
    +
    +
    + + +
    +

    Please select from the following

    +
    +{foreach:sectionList,x} +
    + +
    +

    {term.section.cap}: {x.member_name}

    +

    {x.descr:h}

    +
    +
    +{end:} + +
    + +
    + + {startScript:h} + + $(document).ready(function(){ + + // Code to kick off the geolocation-display feature + $("#locationMap").geolocate({ + lat: "#lat", + lng: "#lon", + mapOptions: { + disableDefaultUI: false, + mapTypeControl: true, + mapTypeId: "roadmap", + zoom: 12 + }, + markerOptions: { + draggable: false, + title: "This is your selected location" + } + }); + + }); + + + diff --git a/views/front/Gaslight/Shop/start-COPY.html b/views/front/Gaslight/Shop/start-COPY.html new file mode 100644 index 0000000..feda2b4 --- /dev/null +++ b/views/front/Gaslight/Shop/start-COPY.html @@ -0,0 +1,162 @@ + + +
    +
    +
    +
    +
    {m.name}
    +
    +
    +
    Address: {m.addr1}{if:m.addr2}, {m.addr2}{end:}, {m.city}
    +
    Phone #: {m.phone}
    +
    {m.descr:h}
    +
    +
    +
    +
    (map loads here)
    +
    + + +
    +
    + +
    + {foreach:m.performances,p} +
    +
    +
    +
    + {if:showTickets} + {p.name} + {else:} + {p.name} + {end:} +
    +
    +
    +
    {term.prop.cap}: {p.member_name}
    +
    Dates: {p.start_date.date} through {p.end_date.date}
    +
    +
    + {if:!showTickets} + {term.nav.select} + {end:} + + + {foreach:p.sections,s} +

     

    +
    +
    +
    + {if:!p.oneSectionOnly} + {s.sectionDetail.name}
    + {end:} + +
    + +
    +
    + + + {foreach:s.ticketsData,x} +
    + {if:option.ticket_selection.include_options_in_ticket_list} +
    +
    +
    Price: 
    +
    +
    {x.price}
    +
    +
    +
    +
    Select date: 
    +
    +
    + + +
    +
    +
    +
    +
    Quant: 
    +
    +
    (select date)
    +
    +
    +
    + + {end:} + +
    + {if:option.ticket_selection.include_options_in_ticket_list} +
    {x.title}
    + {else:} +
    + {x.name} +
    + {term.nav.select} + {end:} +
    +
    + {if:x.descr} +

    {x.descr:h}

    + {end:} +
    + {if:!x.date_specific.value} + Use any date{if:x.start_date.timestamp} from {x.start_date.date} to {x.end_date.date}{end:}{if:!x.time_specific.value}, {end:} + {end:} + {if:!x.time_specific.value} + Use any time of day, + {else:} + Time: {x.ticket_time.time}, + {end:} + {if:x.unlimted_use.value} + Each {term.ticket.norm} may be used an unlimited number of times + {else:} + + {end:} +
    +
    +
    + {if:option.ticket_selection.include_options_in_ticket_list} +
    +
    +
    Price each: 
    +
    +
    {x.price}
    +
    +
    +
    +
    Select date: 
    +
    +
    + + +
    +
    +
    +
    +
    Quant: 
    +
    +
    (select date)
    +
    +
    +
    + + {end:} +
    + + + {end:} + +
    + + {end:} + + + +
    + {end:} +
    +
    + {end:} diff --git a/views/front/Gaslight/Shop/start.html b/views/front/Gaslight/Shop/start.html new file mode 100755 index 0000000..b4e2fca --- /dev/null +++ b/views/front/Gaslight/Shop/start.html @@ -0,0 +1,398 @@ + + + +
    + +
    +
    {term.event.cap} Selection
    + + +
    + +
    {introText:h}
    + {if:reason} +
    +
    We're sorry, we had a problem with your request:
    +
      + {foreach:reason,r} +
    • {r:h}
    • + {end:} +
    +
    + {end:} +

    Please select from the following

    +{if:showTickets} +
    + + + + +{end:} + + {foreach:membersList,m} +
    +
    +
    +
    +
    {m.name}
    +
    +
    +
    Address: {m.addr1}{if:m.addr2}, {m.addr2}{end:}, {m.city}
    +
    Phone #: {m.phone}
    +
    {m.descr:h}
    +
    +
    + {if:option.select_images} + {if:m.image} +
    + {end:} + {end:} + +
    + {foreach:m.performances,p} +
    +
    +
    +
    + {if:showTickets} + {p.name} + {else:} + {p.name} + {end:} +
    +
    +
    + + {if:p.start_date.timestamp}
    Dates: {p.start_date.date}{if:p.end_date.timestamp} - {p.end_date.date} {end:}
    {end:} +
    {p.short_descr:h}
    +
    +
    + {if:option.select_images} + {if:p.image} +
    + {end:} + {end:} + {if:!showTickets} + + {end:} + + + + {foreach:p.sections,s} +

     

    +
    +
    +
    + {if:!p.oneSectionOnly} + {s.sectionDetail.name}
    + {end:} + +
    + +
    +
    + + + {foreach:s.ticketsData,x} +
    + {if:option.ticket_selection.include_options_in_ticket_list} +
    +
    +
    Price: 
    +
    +
    {x.price}
    +
    +
    +
    +
    Select date: 
    +
    +
    + + +
    +
    +
    +
    +
    Quant: 
    +
    +
    (select date)
    +
    +
    +
    + + {end:} + +
    + {if:option.ticket_selection.include_options_in_ticket_list} +
    {x.title}
    + {else:} +
    + {x.name} +
    + {term.nav.select} + {end:} +
    +
    + {if:x.descr} +

    {x.descr:h}

    + {end:} +
    + {if:!x.date_specific.value} + Use any date{if:x.start_date.timestamp} from {x.start_date.date} to {x.end_date.date}{end:}{if:!x.time_specific.value} {end:} + {end:} + {if:!x.time_specific.value} + Use any time of day, + {else:} + Time: {x.ticket_time.time}, + {end:} + {if:x.unlimted_use.value} + Each {term.ticket.norm} may be used an unlimited number of times + {else:} + + {end:} +
    +
    +
    + {if:option.ticket_selection.include_options_in_ticket_list} +
    +
    +
    Price each: 
    +
    +
    {x.price}
    +
    +
    +
    +
    Select date: 
    +
    +
    + + +
    +
    +
    +
    +
    Quant: 
    +
    +
    (select date)
    +
    +
    +
    + + {end:} +
    + + + {end:} + +
    + + {end:} + + + +
    + {end:} +
    +
    + {end:} +{if:showTickets} + +
    +{end:} +
    + +{startScript:h} + + var addButtonPushed = false; + + // Dates for inventory data + var tickets = {ticketsJSON:h}; + + var ticketQuantSelection = '\ + \ + '; + + var ticketTooLate = '\ +

    \ + Sorry, too late to select these {term.ticket.plur} on-line.\ +

    \ + '; + + + + $(document).ready(function(){ + + // Code to kick off the geolocation-display feature + function doLocationMap(id) { + $("#locationMap_" + id).geolocate({ + lat: "#lat_" + id, + lng: "#lon_" + id, + mapOptions: { + disableDefaultUI: false, + mapTypeControl: true, + mapTypeId: "roadmap", + zoom: 12 + }, + markerOptions: { + draggable: false, + title: "This is your selected location" + } + }); + } + {foreach:membersList,m} + doLocationMap({m.id}); + {end:} + + // DatePicker action + function avail(date) { + m = (date.getMonth()+1); + if (m < 10) { + m = '0' + m; + } + d = date.getDate(); + if (d < 10) { + d = '0' + d; + } + y = date.getFullYear(); + mdy = m + '/' + d + '/' + y; + if (dates[mdy]) { + return [true,"","Available"]; + } else { + return [false,"","Not Available"]; + } + } + + // for each ticket + $.each(tickets, function(index, ticket) { + + var inventory = ticket.inventory; + + // Build date data array and count dates for this ticket + var dateCount = 0; + var dateData = false + $.each(inventory, function(index, date) { + + // Count the number of dates + dateCount++; + + // If this is the first one, store it in case it's the only one + dateData = date; + + }); // each date + + // if there's no date specific tickets + if (!ticket.dateSpecific) { + + // Populate date input field + $('#GLMeventDateSelect_' + ticket.id).html(''); + doQuantSelection(ticket.id, dateData.id, dateData.available, dateData.tooLate); + + // if there's only one date, then display that and move on. + } else if (!ticket.dateSpecific || dateCount == 1) { + + // populate date input field + $('#GLMeventDate_' + ticket.id).html('
    Date:
    ' + dateData['date'] + '
    '); + doQuantSelection(ticket.id, dateData.id, dateData.available, dateData.tooLate); + + } else { + + // DatePicker action + function avail(date) { + m = (date.getMonth()+1); + if (m < 10) { + m = '0' + m; + } + d = date.getDate(); + if (d < 10) { + d = '0' + d; + } + y = date.getFullYear(); + mdy = m + '/' + d + '/' + y; + if (inventory[mdy]) { + return [true,"","Available"]; + } else { + return [false,"","Not Available"]; + } + } + + // Use the date picker to select a date + $('#GLMeventDateInput_' + ticket.id).datepicker({ + beforeShowDay: avail, + dateFormat: "mm/dd/yy", +// *** NEED TO FIX REFERENCE TO "performanceDetail" since that's not available on this page + minDate: "{performanceDetail.start_date.date}", + maxDate: "{performanceDetail.end_date.date}", + onSelect: function(selectedDate, inst) { + // Get data for the selected date + dateData = inventory[selectedDate]; + $('#GLMeventInvID_' + ticket.id).val(dateData.id); + doQuantSelection(ticket.id, dateData.id, dateData.available, dateData.tooLate); + } // Date Selection + + }); // Date Picker + + + } + + }); // each ticket + + function doQuantSelection(id, invId, available, tooLate) { + + // Build the ticket quant options + var ticketQuants = ''; + var selectMax = available; + if (selectMax > 50) { + selectMax = 50; + } + + if (tooLate) { + $('#GLMticketQuantContainer_' + id).html(ticketTooLate); + } else { + + // note that the braced lte below is needed to inject a less-than-or-equal-to operator without having flexy chew on it. + for (var i = 1; i {lte:h} (selectMax*1); i++) { + ticketQuants = ticketQuants.concat(''); + } + + // Populate the ticket quantity container + tmpQuantSel = ticketQuantSelection.replace(/\[id\]/g, id); + $('#GLMticketQuantContainer_' + id).html(tmpQuantSel.replace(/\[ticket-quants\]/g, ticketQuants)); + } + + } + + $('#GLMselectButton').click(function() { + + // Check for a selected ticket + var ticketSelected = false; + $('.glmTicketQuant').each(function( index ) { + if ($(this).val() != '') { + ticketSelected = true; + } + }); + + if (ticketSelected) { + selectButtonPressed = true; + setBlocker(); + $('#GLMselectForm').submit(); + } else { + alert('Please select a {term.ticket.norm} quantity.') + return false; + } + + }); + + function setBlocker() { + $('#glmReloadBlocker').show(); + } + + }); + + + diff --git a/views/front/Gaslight/Shop/svn-commit.tmp b/views/front/Gaslight/Shop/svn-commit.tmp new file mode 100644 index 0000000..8c664dd --- /dev/null +++ b/views/front/Gaslight/Shop/svn-commit.tmp @@ -0,0 +1,4 @@ +Anthony changes for "use any date" or whatever +--This line, and those below, will be ignored-- + +M checkout.html diff --git a/views/front/Gaslight/Shop/ticketOpt.html b/views/front/Gaslight/Shop/ticketOpt.html new file mode 100755 index 0000000..7b959f2 --- /dev/null +++ b/views/front/Gaslight/Shop/ticketOpt.html @@ -0,0 +1,273 @@ + + + + + +
    + +
    +
    Ticket Selection
    + + +
    + +
    {ticketOptText:h}
    + {if:reason} +
    +
    We're sorry, we had a problem with your request:
    +
      + {foreach:reason,r} +
    • {r:h}
    • + {end:} +
    +
    + {end:} +

    You have selected

    + +
    +
    +
    +
    {performanceDetail.name}
    +
    +
    +
    {term.prop.cap}: {performanceDetail.member_name}
    + + +
    +
    +
    +
    +
    {sectionDetail.name}
    +
    +
    + +
    +
    +
    +
    +
    {ticketDetail.name}
    +
    +
    + {if:!ticketDetail.date_specific.value} +
    Use any date {if:ticketDetail.start_date.timestamp} from {ticketDetail.start_date.date} to {ticketDetail.end_date.date}{end:}
    + {end:} + {if:!ticketDetail.time_specific.value} +
    Use any time
    + {else:} +
    Time: {ticketDetail.ticket_time.time}
    + {end:} + {if:!ticketDetail.unlimted_use.value} + + {else:} +
    Each {term.ticket.norm} may be used an unlimited number of times
    + {end:} +
    {ticketDetail.descr:h}
    +
    +
    +
    + +

    Please select from the following

    +
    +
    +
    +
    +
    +
    +
    +
    Select desired date:
    +
    +
    (click in field to set date)
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    Select Quantity:
    +
    +
    (please select date first)
    +
    +
    +
    +
    + {if:reason}
    (disabled - please see above)
    {else:}
    {term.nav.add_to_cart}
    {end:} +
    + +{startScript:h} + + // Whether ticket has date specific inventory + var dateSpecific = {ticketDetail.date_specific.value} + 0; + + // Dates for inventory data + var dates = {inventoryJSON:h}; + + $(document).ready(function(){ + + // DatePicker action + function avail(date) { + m = (date.getMonth()+1); + if (m < 10) { + m = '0' + m; + } + d = date.getDate(); + if (d < 10) { + d = '0' + d; + } + y = date.getFullYear(); + mdy = m + '/' + d + '/' + y; + if (dates[mdy]) { + return [true,"","Available"]; + } else { + return [false,"","Not Available"]; + } + } + var dateData = false; + + var ticketQuantSelection = '\ + \ + '; + var ticketTooLate = '\ +

    \ + Sorry, too late to select these {term.ticket.plur} on-line.\ + {term.ticket.plur_cap} must be purchased at least {detail.performance.purch_leadtime} hours prior to the {term.performance.norm}.\ + Please select another date or time.\ +

    \ + '; + var selectedInv; + var ticketQuants; + var addButtonPushed = false; + + // Start by counting the number of dates to see if we have only 1 + var dateCount = 0; +// if (dateSpecific) { + $.each(dates, function(index, date) { + dateCount = dateCount + 1; + dateData = date; + }); +// } + // if there's no date specific tickets + if (!dateSpecific) { + // Populate date input field + $('#GLMeventDateSelectBlock').html(''); + doQuantSelection(); + // if there's only one date, then display that and move on. + } else if (!dateSpecific || dateCount == 1) { + // populate date input field + $('#GLMeventDate').val(dateData['date']); + $('#GLMtickets').html('
    Date:
    ' + dateData['date'] + '
    '); + + doQuantSelection(); + } else { + // Use the date picker to select a date + dateData = false; + $("#GLMeventDate").datepicker({ + beforeShowDay: avail, + dateFormat: "mm/dd/yy", + minDate: "{performanceDetail.start_date.date}", + maxDate: "{performanceDetail.end_date.date}", + onSelect: function(selectedDate, inst) { + // Update input message + $('#GLMdateMessage').html('
    '); + + // Get data for the selected date + dateData = dates[selectedDate]; + doQuantSelection(); + } // Date Selection + + }); // Date Picker + + } + + function doQuantSelection() { + // Build the ticket quant options + ticketQuants = ''; + var selectMax = dateData['available']; + if (selectMax > 50) { + selectMax = 50; + } + var tooLate = dateData['tooLate']; + if (tooLate) { + $('#GLMticketQuantContainer').html(ticketTooLate); + } else { + // note that the braced lte below is needed to inject a less-than-or-equal-to operator without having flexy chew on it. + for (var i = 1; i {lte:h} (selectMax*1); i++) { + ticketQuants = ticketQuants.concat(''); + } + + // Populate the ticket quantity container + $('#GLMticketQuantContainer').html(ticketQuantSelection.replace(/\[ticket-quants\]/g, ticketQuants)); + } +// doAddToCartSetup(); + } + +// function doAddToCartSetup() { + // Add to cart action + $('#GLMaddToCart').click(function() { + if (addButtonPushed) { + return; + } + var reason = ''; + // Check date + if (dateData) { + selectedInv = dateData.id; + } else { + reason = reason.concat('* You need to select a date first.\n'); + } + // Check quantity + var selectedQuant = (parseInt($('#glmQuantSelector').val()) + 0); + if (selectedQuant == 0) { + reason = reason.concat('* You need to select a quantity first.\n'); + } + // Check if there's a reason we can't add this to the cart yet + if (reason != '') { + alert(reason); + return; + } + // Adding to cart + addButtonPushed = true; + $("#GLMeventDate").datepicker('disable'); + $('#glmQuantSelector').prop('disabled', 'disabled'); + setBlocker(); + // Submit to cart + window.location = "{baseSCRIPT}&Action=Shop_cart&cart=add&PerformanceID={performanceDetail.id}&SectionID={sectionDetail.id}&TicketID={ticketDetail.id}&ticket_inv=" + selectedInv + "&quant=" + selectedQuant; + + }); +// } + // Code to kick off the geolocation-display feature + $("#locationMap").geolocate({ + lat: "#lat", + lng: "#lon", + mapOptions: { + disableDefaultUI: false, + mapTypeControl: true, + mapTypeId: "roadmap", + zoom: 12 + }, + markerOptions: { + draggable: false, + title: "This is your selected location" + } + }); + // Navigation buttons + $('#GLMnavCart').click(function() { // Add to Cart + window.location = '{baseSCRIPT}&Action=Shop_cart'; + }); + $('#GLMnavSelectEvent').on('click', function() { // Return to Event Selection + window.location = '{startURL:h}'; + }); + + function setBlocker() { + $('#glmReloadBlocker').show(); + } + + }); + + diff --git a/views/front/Gaslight/Shop/ticketSelect.html b/views/front/Gaslight/Shop/ticketSelect.html new file mode 100755 index 0000000..06586eb --- /dev/null +++ b/views/front/Gaslight/Shop/ticketSelect.html @@ -0,0 +1,314 @@ + + + +
    + +
    +
    {term.ticket.cap} Selection
    + +
    + {term.nav.show_selected} + {if:!option.ticket_selection.start_at_cart} + {term.nav.select_more} + {end:} +
    +
    + +
    {ticketText:h}
    +{if:reason} +
    +
    We're sorry, we had a problem with your request:
    +
      + {foreach:reason,r} +
    • {r:h}
    • + {end:} +
    +
    +{end:} +

    You have selected

    + + + +{foreach:sections,s} +
    +
    + + +
    + {if:performanceDetail.image} +
    + {end:} +
    + +
    +
    {performanceDetail.member_name:h}

    +
    {performanceDetail.name:h}
    +
    +
    +
    + {if:!oneSectionOnly} + {s.sectionDetail.name}
    + {end:} + +
    + + {if:performanceDetail.descr} + {performanceDetail.descr:h} + {end:} +
    +
    +
    +
    +
    + +

    Please select from the following

    +
    +
    + + + + + {foreach:s.ticketsData,x} +
    + {if:option.ticket_selection.include_options_in_ticket_list} +
    +
    +
    Price: 
    +
    +
    {x.price}
    +
    +
    +
    +
    Select date: 
    +
    +
    + + +
    +
    +
    +
    +
    Quant: 
    +
    +
    (select date)
    +
    +
    +
    + {end:} +
    + {if:option.ticket_selection.include_options_in_ticket_list} +
    {x.title}
    + {else:} +
    + {x.name} +
    + {end:} +
    +
    + {if:x.descr} +

    {x.short_descr:h}

    + {end:} +

    + {if:!x.date_specific.value} + {if:x.start_date.timestamp} Date: {x.start_date.date}{end:}{if:!x.start_end_dates_same} to {x.end_date.date}{end:}{if:!x.time_specific.value} {end:} + {end:} + {if:!x.time_specific.value} + + {else:} + Time: {x.ticket_time.time} + {end:} + {if:x.unlimted_use.value} + Each {term.ticket.norm} may be used an unlimited number of times + {else:} + + {end:} +

    +
    +
    +
    +
    + {end:} + +
    +
    + +{end:} + +
    + +{if:option.ticket_selection.include_options_in_ticket_list} + + {startScript:h} + + var addButtonPushed = false; + + // Dates for inventory data + var tickets = {ticketsJSON:h}; + + var ticketQuantSelection = '\ + \ + '; + + var ticketTooLate = '\ +

    \ + Sorry, too late to select these {term.ticket.plur} on-line.\ + {term.ticket.plur_cap} must be purchased at least [hours] hours prior to the {term.performance.norm}.\ + Please select another date or time.\ +

    \ + '; + + + $(document).ready(function(){ + + // for each ticket + $.each(tickets, function(index, ticket) { + + var inventory = ticket.inventory; + + // Build date data array and count dates for this ticket + var dateCount = 0; + var dateData = false + $.each(inventory, function(index, date) { + + // Count the number of dates + dateCount++; + + // If this is the first one, store it in case it's the only one + dateData = date; + + }); // each date + + // if there's no date specific tickets + if (!ticket.dateSpecific) { + + // Populate date input field + $('#GLMeventDateSelect_' + ticket.id).html(''); + doQuantSelection(ticket.id, dateData.id, dateData.available, ticket.tooLate); + + // if there's only one date, then display that and move on. + } else if (!ticket.dateSpecific || dateCount == 1) { + + // populate date input field + $('#GLMeventDateSelect_' + ticket.id).html(' \ +
    Date Available: 
    \ +
    \ +
    \ + ' + dateData.ticket_date.date + ' \ + \ +
    \ +
    '); + + doQuantSelection(ticket.id, dateData.id, dateData.available, ticket.tooLate); + + } else { + + // DatePicker action + function avail(date) { + m = (date.getMonth()+1); + if (m < 10) { + m = '0' + m; + } + d = date.getDate(); + if (d < 10) { + d = '0' + d; + } + y = date.getFullYear(); + mdy = m + '/' + d + '/' + y; + if (inventory[mdy]) { + return [true,"","Available"]; + } else { + return [false,"","Not Available"]; + } + } + + // Use the date picker to select a date + if($('#GLMeventDateInput_' + ticket.id).length > 0) { + $('#GLMeventDateInput_' + ticket.id).datepicker({ + beforeShowDay: avail, + dateFormat: "mm/dd/yy", + minDate: ticket.startDate, + maxDate: ticket.endDate, + onSelect: function(selectedDate, inst) { + // Get data for the selected date + dateData = inventory[selectedDate]; + $('#GLMeventInvID_' + ticket.id).val(dateData.id); + doQuantSelection(ticket.id, dateData.id, dateData.available, ticket.tooLate); + } // Date Selection + + }); // Date Picker + } + + } + + }); // each ticket + + function doQuantSelection(id, invId, available, tooLate) { + + // Build the ticket quant options + var ticketQuants = ''; + var selectMax = available; + if (selectMax > 50) { + selectMax = 50; + } + + if (tooLate) { + $('#GLMticketQuantContainer_' + id).html(ticketTooLate.replace(/\[hours\]/g, {performanceDetail.purch_leadtime})); + } else { + // note that the braced lte below is needed to inject a less-than-or-equal-to operator without having flexy chew on it. + for (var i = 1; i {lte:h} (selectMax*1); i++) { + ticketQuants = ticketQuants.concat(''); + } + + // Populate the ticket quantity container + tmpQuantSel = ticketQuantSelection.replace(/\[id\]/g, id); + $('#GLMticketQuantContainer_' + id).html(tmpQuantSel.replace(/\[ticket-quants\]/g, ticketQuants)); + } + + } + + var selectButtonPressed = false; + + $('#GLMselectButton').click(function() { + + // Prevent multiple submissions + if (selectButtonPressed == true) { + return; + } + + // Check for a selected ticket + var ticketSelected = false; + $('.glmTicketQuant').each(function( index ) { + if ($(this).val() != '') { + ticketSelected = true; + } + }); + + if (ticketSelected) { + selectButtonPressed = true; + setBlocker(); + $('#GLMselectForm').submit(); + } else { + alert('Please select a {term.ticket.norm} quantity.') + return false; + } + + }); + + function setBlocker() { + $('#glmReloadBlocker').show(); + } + if( $(window).width() < 768 ){ + $('.glmBlock').not(":first").each(function() { + var left = $(this).find( $('.glmBlockContentLeft') ); + left.prependTo( $(this) ).find( $('glmBlockContentRight') ); + }); + } + }); + +{end:} + diff --git a/views/front/Gaslight/foot.html b/views/front/Gaslight/foot.html new file mode 100755 index 0000000..36eb69f --- /dev/null +++ b/views/front/Gaslight/foot.html @@ -0,0 +1,9 @@ + +{if:option.development} +

    + Running on Development Server: + + Reset Session + +

    +{end:} \ No newline at end of file diff --git a/views/front/Gaslight/head.html b/views/front/Gaslight/head.html new file mode 100755 index 0000000..2b09b3e --- /dev/null +++ b/views/front/Gaslight/head.html @@ -0,0 +1,38 @@ + +{startScript:h} + // Pass some reference parameters to JAVAScript + var baseSiteURL = '{baseURL}'; + var baseAppURL = '{baseAppURL}'; + +{if:!jQueryLoaded} + +{end:} +{if:!jQueryUiLoaded} + + +{end:} + + + +{if:customCssFile} + + +{end:} +{if:frontDebug} + +
    +{end:} +{startScript:h} + var disp_setting="toolbar=no,location=no,directories=no,menubar=no,scrollbars=yes,width=1000, height=700, left=100, top=25"; + {if:frontDebug} + debugWindowFront = window.open("{baseURL}index.php?Action=Debug_update","emDebugWindowFront",disp_setting); + {end:} + + +
    +
    Updating your information
    Please wait ...
    +
    + + {if:adminUser} +

    Purchasing By Admin User

    + {end:} diff --git a/views/front/Gaslight/index.html b/views/front/Gaslight/index.html new file mode 100755 index 0000000..fca55f0 --- /dev/null +++ b/views/front/Gaslight/index.html @@ -0,0 +1,34 @@ + + + + + + + + + + +

    PLEASE NOTE:

    + +

    + There is no general access to this site. + All access to this site should be through an appropriate link. + If you arrived here by mistake (or exploring), nothing but this message will be displayed. + If you have any concerns about this site, please contact Gaslight Media. +

    + +

    + Gaslight Media
    + 120 East Lake Street
    + Petoskey, MI 49770
    +  
    + Phone: 231-487-0692
    + E-Mail: info@gaslightmedia.com
    + Web: http://www.gaslightmedia.com +

    + + + + + + diff --git a/views/front/MMM/Debug/index.html b/views/front/MMM/Debug/index.html new file mode 100755 index 0000000..a42397f --- /dev/null +++ b/views/front/MMM/Debug/index.html @@ -0,0 +1,42 @@ + + + + + + +
    Startup: {debugStartupTime}
    +
    Event Management Front-End Debug
    +
    +
    + Updated: {debugUpdateTime} +
    +
    + {debugData:h} +
    + + + {startScript:h} + + // Reload the current window with Action = Debug_update + function reloadDebugWindow() + { + window.location("{baseSCRIPT}&Action=Debug_update"); + } + + + \ No newline at end of file diff --git a/views/front/MMM/Debug/start.html b/views/front/MMM/Debug/start.html new file mode 100755 index 0000000..66c3023 --- /dev/null +++ b/views/front/MMM/Debug/start.html @@ -0,0 +1,27 @@ + + + + + + +
    Startup: {debugStartupTime}
    +
    Event Management Front-End Debug
    +
    +
    Debug Startup
    + + \ No newline at end of file diff --git a/views/front/MMM/Shop/PayPalApproved.html b/views/front/MMM/Shop/PayPalApproved.html new file mode 100755 index 0000000..4dff5eb --- /dev/null +++ b/views/front/MMM/Shop/PayPalApproved.html @@ -0,0 +1,41 @@ + + + + + +
    + +

    Your PayPal payment has been approved.

    + + +
    + +

    + Your cart will now reflect that the payment has been made. +

    + +
    + +
    +
    Close This Window
    +
    + +
    + + + + diff --git a/views/front/MMM/Shop/PayPalFail.html b/views/front/MMM/Shop/PayPalFail.html new file mode 100755 index 0000000..bb62666 --- /dev/null +++ b/views/front/MMM/Shop/PayPalFail.html @@ -0,0 +1,49 @@ + + + + + +
    + +

    Unable to process your payment!

    + + +
    + +

    +

    Sorry, there was a problem.
    +

    + +

    + We were unable to find your purchase information and are therefore + are unable to process your payment through PayPal. This could be + due to you not performing any action with your pending purchase + for too long. Please click the "Return to selected tickets" button + at the top of the checkout page to see if your selections are still listed. +

    + +
    + +
    +
    Close This Window
    +
    + +
    + + + + diff --git a/views/front/MMM/Shop/additionalInfo.html b/views/front/MMM/Shop/additionalInfo.html new file mode 100644 index 0000000..b490910 --- /dev/null +++ b/views/front/MMM/Shop/additionalInfo.html @@ -0,0 +1,246 @@ + + + +
    + + + +
    +
    + + + {term.nav.show_selected} + {if:!option.ticket_shop.start_at_cart} + {term.nav.select_more} + {end:} + + +

    {cartText:h}

    + +
    +
    + +{if:reason} + + + +
    +
    +
    +

    We're sorry, we had a problem with your request:

    +
      + {foreach:reason,r}{Chuck} +
    • {r:h}
    • + {end:} +
    +
    +
    +
    +{end:} + + + +{foreach:cart,c} + + {if:option.show_location_blocks} +
    +
    +
    +
    +

    {c.name:h}

    +
    + {end:} + + + + + {if:c.needAssignemntOrDate} + {if:c.needAssignment} + +
    + {if:!c.haveAssignment} +
    {text.cart.select_assignment_location}
    + {else:} +
    {text.cart.select_assignment_location}
    + {end:} + {foreach:c.assignmentMembers,a} + {if:a.entrances} + {foreach:a.entrances,e} +
    + {if:option.cart_images} + {if:e.image} +
    + {end:} + {end:} +
    + {if:e.selected} + {a.name} - {e.name}
    + {else:} + {a.name} - {e.name}
    + {end:} +
    +
    {e.addr1}{if:e.addr2}, {e.addr2}{end:}, {e.city}
    +
    {e.phone}
    + {if:e.descr} +
    {e.descr:h}
    + {end:} +
    +
    + {end:} +
    + {else:} + {if:a.selected} + {a.name}
    + {else:} + {a.name}
    + {end:} + {end:} + {end:} +  
    + {end:} + + {if:option.ask_for_likely_date} + {if:c.needLikelyDate} +
    +

    + {if:!c.likelyDate} + + {else:} + + {end:} + {text.cart.select_likely_date}   + + mm/dd/yyyy + {if:text.cart.select_likely_date_explain} +
    {text.cart.select_likely_date_explain} + {end:} +

    +
    + {end:} + {end:} +
    +
    + {end:} + {if:!c.needAssignment} + + {if:option.cart_images}{if:c.image} +
    + + +
    + {end:}{end:} + {end:} + +
    +
    +
    + +{end:} + + + +{if:cartHasContents} +
    +
    + {if:!blockCheckout} + {term.nav.checkout} + {else:} + Please complete the items in RED above. + {end:} +
    +
    +{else:} +
    +
    +

    Your cart is currently empty.

    +
    +
    +{end:} + + + + + + + + + diff --git a/views/front/MMM/Shop/cart.html b/views/front/MMM/Shop/cart.html new file mode 100755 index 0000000..ac03b9b --- /dev/null +++ b/views/front/MMM/Shop/cart.html @@ -0,0 +1,429 @@ + + + +
    +
    + + +
    + + +
    + {if:!option.ticket_selection.start_at_cart} + {term.nav.select_more} + {end:} + +
    +
    + +
    {cartText:h}
    + {if:reason} +
    +
    We're sorry, we had a problem with your request:
    +
      + {foreach:reason,r}{Chuck} +
    • {r:h}
    • + {end:} +
    +
    + {end:} + {if:havePromoCodes} +
    +
    +
    If you have a {term.promo.norm}, please enter it here:
    +
    +
    + {end:} + {foreach:cart,c} +
    +
    {c.name}
    +
    + {foreach:c.performances,p} +
    +
    + {if:!option.ticket_selection.start_at_cart} + {term.nav.select_more_of_these} + {end:} +
    + +
    {p.name}
    +
    + {if:p.descr}
    {p.descr:h}
    {end:} + {if:p.short_descr}
    {p.short_descr:h}
    {end:} + {if:option.cart_images}{if:p.image} + + {end:}{end:} +
    +
    +
    +
    + {foreach:p.dates,d} +
    + {if:d.dateSpecific} + {d.fullDate} + {else:} + + {if:c.likelyDate} + - Likely Date {c.likelyDate} + {end:} + {end:} + {foreach:d.sections,s} + + + + {if:!p.oneSectionOnly} + + {end:} + + + + + {foreach:s.tickets,i} + + + {if:!p.oneSectionOnly} + + {end:} + + + + + {if:i.problem} + + + + {end:} + {if:i.descr} + + + {if:!p.oneSectionOnly} + + + {end:} + + {foreach:i.addons,a} + + + {if:!p.oneSectionOnly} + + {end:} + + + + + {end:} + + + {if:i.promo} + + + {if:!p.oneSectionOnly} + + {end:} + + + + {end:} + + {end:} +
    QuantSection{term.ticket.cap}PriceTotal
    + + {s.name} + {i.title} + {if:false} + {if:i.date_specific.value} + - {i.start_date.date} + {if:i.time_specific.value} + {i.ticket_time.time} + {end:} + {else:} + {if:i.time_specific.value} + - {i.ticket_time.time} + {end:} + {end:} + {end:} + {if:i.show_price}{i.price}{end:}{if:i.show_price}{i.extended}{end:}
     {i.problemText}
      + {else:} + + {end:} + {if:option.cart_images}{if:i.image} +
    + {end:}{end:} +
    {i.descr:h}
    +
       +
    + +
    +
    {a.unit_cost}/{a.unit_name}{a.money}
      {term.promo.cap}: {promoCode}  + {i.promo.credit}
    + {end:} +
    + {end:} +
    +
    + {end:} +
    + {if:c.ticket_policy}
    {c.ticket_policy:h}
    {end:} + +{if:option.ask_for_assignment_and_likely_date} + {if:c.needAssignemntOrDate} + {if:c.needAssignment} + +
    + {if:!c.haveAssignment} +
    {text.cart.select_assignment_location}
    + {else:} +
    {text.cart.select_assignment_location}
    + {end:} + {foreach:c.assignmentMembers,a} + {if:a.entrances} + {foreach:a.entrances,e} +
    + {if:option.cart_images} + {if:e.image} +
    + {end:} + {end:} +
    + {if:e.selected} + {a.name} - {e.name}
    + {else:} + {a.name} - {e.name}
    + {end:} +
    +
    {e.addr1}{if:e.addr2}, {e.addr2}{end:}, {e.city}
    +
    {e.phone}
    + {if:e.descr} +
    {e.descr:h}
    + {end:} +
    +
    + {end:} +
    + {else:} + {if:a.selected} + {a.name}
    + {else:} + {a.name}
    + {end:} + {end:} + {end:} +  
    + {end:} + + {if:option.ask_for_likely_date} + {if:c.needLikelyDate} +
    + {if:!c.likelyDate} + + {else:} + + {end:} + {text.cart.select_likely_date}   + + mm/dd/yyyy +
    + {end:} + {end:} +
    +
    + {end:} + {if:!c.needAssignment} + + {if:option.cart_images}{if:c.image} +
    + + +
    + {end:}{end:} + {end:} +{end:} + + +
    + {end:} + + +
    + {if:cartHasContents} +
    + Grand Total   {totals.price} +
    +
    + {if:totals.tickets} + + {term.nav.checkout} + + {else:} + Your cart is currently empty. + {end:} +
    + {else:} +

    Your cart is currently empty.

    + {end:} +
    + + {if:option.cart_promotions} +
    + You may also be interested in ...
    + {foreach:cartPromotions,p} +
    + + {if:p.image} +
    + {end:} +
    + {if:p.start_date} +

    + Dates: {p.start_date.date} +

    + {end:} + + {if:p.short_descr}
    {p.short_descr:h}
    {end:} + {if:p.short_descr}
    {p.short_descr:h}
    {end:} +
    +
    + {end:} +
    + {end:} + + + +
    + +{startScript:h} + + $(document).ready(function(){ + + // Block direct form submission - Everything submits by jQuery action + $('#cartForm').submit(function( event ) { + return false; + }); + + // Convert input fields to select lists + $('.glmCartQuant').each(function() { + + var id = $(this).attr('id'); + var ticket = $(this).attr('data-ticket'); + var addon = $(this).attr('data-addon'); + var max = $(this).attr('data-max'); + var value = $(this).attr('value'); + var units = $(this).attr('data-units'); + var numbSel = ''; + + // Build a picklist for this input + for (var i = 0 ; i {lte:h} max ; i++) { + if (value == i) { + numbSel = numbSel.concat(''); + } else { + numbSel = numbSel.concat(''); + } + } + + $('#quant_' + id).html('' + units); + + }); + + // Get or set vertical scroll to return to same place when cart reloads + function getVertScroll() { + var vertScroll = window.pageYOffset; + if (vertScroll == 0) { + var vertScroll = document.documentElement.scrollTop; + } + if (vertScroll == 0) { + var vertScroll = document.body.scrollTop; + } + return vertScroll; + } + + // When a cart value changes, submit it as a cart update. + $('.glmCartSelect').change(function() { + vertScroll = getVertScroll(); + var ticket = $(this).attr('data-ticket'); + var addon = $(this).attr('data-addon'); + var value = $(this).val(); + + setBlocker(); + window.location = "{baseSCRIPT}&Action=Shop_cart&cart=update&ticket_inv=" + ticket + "&addon=" + addon + "&quant=" + value + "&vertScroll=" + vertScroll; + + }); + + // When there's a change in the promo code input, submit it. + $('#promoCodeInput').change(function() { + var value = $(this).val(); + setBlocker(); + window.location = "{baseSCRIPT}&Action=Shop_cart&cart=promo_code&promo_code=" + value; + }); + + // When a member selection for unassigned items changes, submit it so it's in the session + $('.glmAssignmentChange').change(function() { + vertScroll = getVertScroll(); + var member = $(this).attr('data-Member'); + var assignedTo = $(this).val(); + var assignedToEntrance = $(this).attr('data-entrance'); + setBlocker(); + window.location = "{baseSCRIPT}&Action=Shop_cart&cart=update_assignment&member_assigned=" + member + "&assigned_to=" + assignedTo + "&entrance_assigned=" + assignedToEntrance + "&vertScroll=" + vertScroll; + }); + + // When a likely departure date changes, submit it so it's in the session + $('.glmLikelyDateChange').change(function() { + vertScroll = getVertScroll(); + var member = $(this).attr('data-Member'); + var likelyDate = $(this).val(); + setBlocker(); + window.location = "{baseSCRIPT}&Action=Shop_cart&cart=update_likelyDate&member=" + member + "&likely_date=" + likelyDate + "&vertScroll=" + vertScroll; + + }); + + // Code to start datepicker for each date input + if($("#likelyDateInput").length > 0) { + $("#likelyDateInput").datepicker({ + dateFormat: "mm/dd/yy", + minDate: -1, + maxDate: 365 + }); + } + + // Checkout action + $('#GLMcheckoutBtn').click(function() { + setBlocker(); + window.location = "{baseSCRIPT}&Action=Shop_checkout"; + }); + + function setBlocker() { + $('#glmReloadBlocker').show(); + } + + $('#GLMnavSelectEvent').on('click', function() { // Return to Event Selection + setBlocker(); + window.location = '{startURL:h}'; + }); + +/* Not using right now + // Reprint order button + $('#reprintVoucher').on('keypress', function(event) { + if(event.which == '13'){ + var orderID = $(this).val(); + var voucherWindow = window.open('{appAdminURL}&Action=Order_printVoucher&OrderID=' + orderID, + "voucherPrint", + "height=750,width=600,menubar=yes,toolbar=yes,alwaysRaised=yes,menu" + ); + voucherWindow.focus(); + voucherWindow.print(); + return false; + } + }); +*/ + + if ({vertScroll}) { + window.scrollTo(0,{vertScroll}); + } + + }); + + + diff --git a/views/front/MMM/Shop/checkout.html b/views/front/MMM/Shop/checkout.html new file mode 100755 index 0000000..ca99ef7 --- /dev/null +++ b/views/front/MMM/Shop/checkout.html @@ -0,0 +1,926 @@ + + + +
    + +
    +
    Selected {term.ticket.plur_cap}
    + +
    + {term.nav.show_selected} + {if:!option.ticket_selection.start_at_cart} + {term.nav.select_more} + {end:} +
    +
    + +
    {checkoutText:h}
    + {if:reason} +
    +
    We're sorry, we had a problem with your request:
    +
      + {foreach:reason,r} +
    • {r:h}
    • + {end:} +
    +

    See below for more information.

    +
    + {end:} +
    + + +
    +
    Contact Information
    + +
    +
    +
    {text.cart.checkout.first_name}:
    +
    {text.cart.checkout.first_name}:
    + {if:formData.contact.fname.problem} +
    +
    {formData.contact.fname.problem}
    + {else:} +
    + {end:} + +
    +
    +
    +
    {text.cart.checkout.last_name}:
    +
    {text.cart.checkout.last_name}:
    + {if:formData.contact.lname.problem} +
    +
    {formData.contact.lname.problem}
    + {else:} +
    + {end:} + +
    +
    +
    +
    {text.cart.checkout.address}:
    +
    {text.cart.checkout.address}:
    + {if:formData.contact.addr1.problem} +
    +
    {formData.contact.addr1.problem}
    + {else:} +
    + {end:} + +
    +
    +
    +
     
    +
     
    + {if:formData.contact.addr2.problem} +
    +
    {formData.contact.addr2.problem}
    + {else:} +
    + {end:} + +
    +
    +
    +
    {text.cart.checkout.city}:
    +
    {text.cart.checkout.city}:
    + {if:formData.contact.city.problem} +
    +
    {formData.contact.city.problem}
    + {else:} +
    + {end:} + +
    +
    +
    +
    {text.cart.checkout.state}:
    +
    {text.cart.checkout.state}:
    + {if:formData.contact.state.problem} +
    +
    {formData.contact.state.problem}
    + {else:} +
    + {end:} + +
    +
    +
    +
    {text.cart.checkout.country}:
    +
    {text.cart.checkout.country}:
    + {if:formData.contact.country.problem} +
    +
    {formData.contact.country.problem}
    + {else:} +
    + {end:} + +
    +
    +
    +
    {text.cart.checkout.zip}:
    +
    {text.cart.checkout.zip}:
    + {if:formData.contact.zip.problem} +
    +
    {formData.contact.zip.problem}
    + {else:} +
    + {end:} + +
    +
    +
    +
    {text.cart.checkout.phone}:
    +
    {text.cart.checkout.phone}:
    + {if:formData.contact.phone.problem} +
    +
    {formData.contact.phone.problem}
    + {else:} +
    + {end:} + +
    +
    +
    +
    {text.cart.checkout.email}:
    +
    {text.cart.checkout.email}:
    + {if:formData.contact.email.problem} +
    +
    {formData.contact.email.problem}
    + {else:} +
    + {end:} + +
    +
    +
    +
    {text.cart.checkout.email_again}:
    +
    {text.cart.checkout.email_again}:
    + {if:formData.contact.email2.problem} +
    +
    {formData.contact.email2.problem}
    + {else:} +
    + {end:} + +
    +
    +
    +
    Receive E-Newsletter?
    + {if:formData.contact.email_ok} +
    + {else:} +
    + {end:} + Please sign me up to receive "The Ship's Bell" e-newsletter. +
    +
    + + {if:opt_field_1_name} +
    +
    {opt_field_1_name}:
    +
    {opt_field_1_name}:
    + {if:formData.contact.opt_field_1.problem} +
    +
    {formData.contact.opt_field_1.problem}
    + {else:} +
    + {end:} + +
    +
    + {end:} + {if:opt_field_2_name} +
    +
    {opt_field_2_name}:
    +
    {opt_field_2_name}:
    + {if:formData.contact.opt_field_2.problem} +
    +
    {formData.contact.opt_field_2.problem}
    + {else:} +
    + {end:} + +
    +
    + {end:} + {if:opt_field_3_name} +
    +
    {opt_field_3_name}:
    +
    {opt_field_3_name}:
    + {if:formData.contact.opt_field_3.problem} +
    +
    {formData.contact.opt_field_3.problem}
    + {else:} +
    + {end:} + +
    +
    + {end:} + + +
    +
    + + {foreach:cart,c} + {if:c.performances} +
    +
    {term.prop.cap}: {c.name}
    + + +
    + + {foreach:c.performances,p} +
    +
    +
    +
    +
    {p.name}
    +
    + {if:p.descr}
    {p.descr:h}
    {end:} + {if:option.cart_images}{if:option.cart_images}{if:p.image}{end:}{end:}{end:} +
    +
    +
    +
    + {foreach:p.dates,d} +
    +
    + + {if:d.dateSpecific} + {d.fullDate} + {else:} + + {if:c.likelyDate} + - Likely Date {c.likelyDate} + {end:} + {end:} + +
    + + + {foreach:d.sections,s} + + + + {if:!p.oneSectionOnly} + + {end:} + + + + + {foreach:s.tickets,i} + + + {if:!p.oneSectionOnly} + + {end:} + + + + + {if:i.descr} + + + {if:!p.oneSectionOnly} + + + {end:} + + {foreach:i.addons,a} + + + {if:!p.oneSectionOnly} + + {end:} + + + + + {end:} + + {if:i.promo} + + + {if:!p.oneSectionOnly} + + {end:} + + + + {end:} + {end:} +
    QuantSection{term.ticket.cap}PriceTotal
    + {i.selected} + {s.name} + {i.title} + {if:i.time_specific.value} + - {i.ticket_time.time} + {else:} + + {end:} + {if:i.show_price}{i.price}{end:}{if:i.show_price}{i.extended}{end:}
      + {else:} + + {end:} + {if:option.cart_images} + {if:i.image} +
    + {end:} + {end:} +
    {i.descr:h}
    +
       +
    + {a.selected} {a.unit_name} +
    +
    {a.unit_cost}/{a.unit_name}{a.money}
      {term.promo.cap}: {promoCode}  + {i.promo.credit}
    + {end:} +
    + {end:} +
    +
    + {if:p.policy} +
    +
    + Please read and agree to our policy for this {term.performance.norm}. +
    +
    +

    {p.policy:h}

    +
    +
    +

    I agree to the policy stated above.

    +
    +
    + {end:} +
    + {end:} +
    + + {if:c.ticket_policy}
    {c.ticket_policy:h}
    {end:} + {if:c.ticket_policy}
    {c.ticket_policy:h}
    {end:} + +
    + + {if:c.ticket_spec_req.value} +
    +
    Please enter any special requests:
    +
    +
    + {end:} + + + {if:!formData.centralPayment} +
    + + {if:c.paymentResult} + {if:c.paymentResult.approved} +
    Card Payment Approved
    +
    Card Type
    {c.paymentResult.cctype}
    +
    Name on Card
    {c.paymentResult.ccname}
    +
    Card Number
    {c.paymentResult.ccnumb}
    +
    Expiration Date
    {c.paymentResult.ccexp}
    +
    Authorization Code
    {c.paymentResult.authCode}
    +
    +
    {term.nav.print_vouchers}
    +
    + {else:} +
    Card Payment Not Complete
    +
    • {c.paymentResult.description}
    +

    Please check the payment information below and try again or contact your credit card company for assistance.

    + {if:forceCheckoutPhase} +
    +
    {term.nav.delete_from_cart}
    +
    + {end:} + {end:} + {end:} + {if:c.paymentResult.approved} +

    Payment Accepted

    + {else:} + {if:c.havePaymentMethod} + +
    + {if:c.havePayPal} + {if:c.haveMultiplePaymentMethods} +  PayPal + {else:} + + {end:} + {end:} + {if:c.haveCreditCards} + {if:c.havePayPal} +      + {end:} + {if:c.haveMultiplePaymentMethods} +  Credit Card + {else:} + + {end:} + {end:} +
    + + {if:c.haveCreditCards} + {if:c.haveMultiplePaymentMethods} + + {else:} + + {end:} +
    +
    Total Charged to this Card
    +
    {c.totalPrice}
    +
    +
    +
    Card Type
    +
    Card Type
    + {if:c.paymentForm.cctype.problem} +
    +
    {c.paymentForm.cctype.problem}
    + {else:} +
    + {end:} + +
    +
    +
    +
    Name on Card
    +
    Name on Card
    + {if:c.paymentForm.ccname.problem} +
    +
    {c.paymentForm.ccname.problem}
    + {else:} +
    + {end:} + +
    +
    +
    +
    Card Number
    +
    Card Number
    + {if:c.paymentForm.ccnumb.problem} +
    +
    {c.paymentForm.ccnumb.problem}
    + {else:} +
    + {end:} + +
    +
    +
    +
    Expiration Date
    +
    Expiration Date
    + {if:c.paymentForm.ccexp.problem} +
    +
    {c.paymentForm.ccexp.problem}
    + {else:} +
    + {end:} + Month + + Year + +
    +
    +
    +
    Security Code
    +
    Security Code
    + {if:c.paymentForm.cccode.problem} +
    +
    {c.paymentForm.cccode.problem}
    + {else:} +
    + {end:} + +
    +
    +
    +
    + The Security Code is the three or four digit number on the signature side of your credit card. +
    +
    + + {end:} + {if:c.havePayPal} + + {if:c.haveMultiplePaymentMethods} + + {else:} + + {end:} +
    + +
    +
    + {end:} + {if:c.haveMultiplePaymentMethods} + +
    Please select a Payment Method
    +
    + {end:} + {else:} + +
    + This {term.prop.norm} does not have a payment method configured. + Please call this {term.prop.norm} to purchase {term.ticket.plur}. +
    +
    + {end:} + {end:} + +
    +
    + + {end:} +
    +
    + {end:} + + {if:!cartRequiresPayment} + + {end:} + + {end:} + +{if:cartRequiresPayment} + {if:formData.centralPayment} + +
    + + {if:formData.centralPayment.havePaymentMethod} + + {foreach:formData.centralPayment.paymentForm,p} + + {if:p.cctype} + + + +
    +
    + {if:formData.centralPayment.haveMultiplePaymentMethods} +  Credit Card + {else:} + + {end:} +
    +
    +
    +
    Card Type
    +
    Card Type
    +
    + +
    +
    +
    +
    Name on Card
    +
    Name on Card
    + {if:p.ccname.problem} +
    +
    {p.ccname.problem}
    + {else:} +
    + {end:} + +
    +
    +
    +
    Card Number
    +
    Card Number
    + {if:p.ccnumb.problem} +
    +
    {p.ccnumb.problem}
    + {else:} +
    + {end:} + +
    +
    +
    +
    Expiration Date
    +
    Expiration Date
    + {if:p.ccexp.problem} +
    +
    {p.ccexp.problem}
    + {else:} +
    + {end:} + Month + + Year + +
    +
    +
    +
    Security Code
    +
    Security Code
    + {if:p.cccode.problem} +
    +
    {p.cccode.problem}
    + {else:} +
    + {end:} + +
    +
    +
    +
    + The Security Code is the three or four digit number on the signature side of your credit card. +
    +
    + + {if:p.haveMultiplePaymentMethods} + +
    Please select a Payment Method
    +
    + {end:} + + {end:} + {end:} + +
    + + {else:} + +
    + This {term.prop.norm} does not have a payment method configured. + Please call this {term.prop.norm} to purchase {term.ticket.plur}. +
    +
    + + {end:} + + {end:} + +{end:} + + + +
    + {if:cartRequiresPayment} +
    +
    Complete Purchase
    + +

    + {ssl_seal_head_script:h} + {ssl_seal_body_script:h} +

    +
    + {else:} +
    +
    No Payment Required
    +
    + {end:} +
    +
    + {if:cartRequiresPayment} + +
    +
    + Grand Total   {totals.price} +
    + + + + + + + +
    + {end:} +
    + {if:!cartHasOneVenueOnly} + + {end:} + + {if:adminUser} +
    + No payment info required for Admin User. +
    + {if:noPaymentReasons} +
    + Reason for no payment information required:
    + +
    + {end:} + {end:} + +
    + {if:!blockCheckout} + {term.nav.purchase} + {else:} + Unable to checkout - please see above. + {end:} +
    +
    +
    + +
    + + + + + + diff --git a/views/front/MMM/Shop/checkoutSuccess.html b/views/front/MMM/Shop/checkoutSuccess.html new file mode 100755 index 0000000..d7f1570 --- /dev/null +++ b/views/front/MMM/Shop/checkoutSuccess.html @@ -0,0 +1,380 @@ + + + + + +
    + + +
    Purchase Complete
    + + + + + {foreach:cart,c} + {if:c.paymentResult} + {if:c.paymentResult.approved} +

    +

    *** {term.nav.print_vouchers} for {c.name} ***
    +

    + {end:} + {end:} + {end:} + + + +
    +
    + +
    +
    + +

    + Adobe Reader is required to view and print your {term.voucher.plur}. Adobe Reader is a free program available directly from Adobe. + If you do not already have Adobe Reader installed, click the "Get Adobe Reader" link now. +

    +
    +
    +
    + +

    + If you are unable to print your {term.voucher.plur}, please print this page or write down the order number(s) + below and bring that to the ticket office when you arrive. +

    + ORDER #: + {foreach:cart,c} + {if:c.paymentResult} + {if:c.paymentResult.approved} + {c.paymentResult.orderID}  + {end:} + {end:} + {end:} +
    +
    +
    + + +
    {successText:h}
    + +
    +
    Contact Information
    +
    +
    First Name:
    {formData.contact.fname.value}
    +
    Last Name:
    {formData.contact.lname.value}
    +
    Address:
    {formData.contact.addr1.value}
    +
     
    {formData.contact.addr2.value}
    +
    City:
    {formData.contact.city.value}
    +
    State:
    {formData.contact.state.value}
    +
    Country:
    {formData.contact.country.value}
    +
    ZIP/Postal Code:
    {formData.contact.zip.value}
    +
    Phone:
    {formData.contact.phone.value}
    +
    E-Mail address:
    {formData.contact.email.value}
    + {if:opt_field_1_name}
    {opt_field_1_name}:
    {formData.contact.opt_field_1.value:h}
    {end:} + {if:opt_field_2_name}
    {opt_field_2_name}:
    {formData.contact.opt_field_2.value:h}
    {end:} + {if:opt_field_3_name}
    {opt_field_3_name}:
    {formData.contact.opt_field_3.value:h}
    {end:} +
     
    + {if:formData.contact.email_ok} + You have asked us to send information on activities and offers. + {else:} + You have asked us to NOT send information on activities and offers.
    + We will only contact you regarding this order. + {end:} +
    + +
    + +
    + + + {foreach:cart,c} +
    + +
    {term.ticket.plur_cap} at: {c.name}
    + + +
    + {if:c.descr}
    {c.descr:h}
    {end:} + {if:option.cart_images}{if:c.image}{end:}{end:} + +
    + +
    + + {foreach:c.performances,p} + +
    + +
    +
    +
    + {term.performance.cap}: {p.name} +
    +
    + + {if:option.cart_images}{if:option.cart_images}{if:p.image}{end:}{end:}{end:} +
    +
    +
    + +
    + {foreach:p.dates,d} + +
    + {term.ticket.cap} date: + + {if:d.dateSpecific} + {d.fullDate} + {else:} + Use any date + {if:c.likelyDate} + - Likely Date {c.likelyDate} + {end:} + {end:} + +
    + + + {foreach:d.sections,s} + + + + {if:!p.oneSectionOnly} + + {end:} + + + + + {foreach:s.tickets,i} + + + {if:!p.oneSectionOnly} + + {end:} + + + + + {if:i.descr} + + + {if:!p.oneSectionOnly} + + + {end:} + + {foreach:i.addons,a} + + + {if:!p.oneSectionOnly} + + {end:} + + + + + {end:} + + {if:i.promo} + + + {if:!p.oneSectionOnly} + + {end:} + + + + {end:} + {end:} +
    QuantSection{term.ticket.cap}PriceTotal
    + {i.selected} + {s.name} + {i.title} + + {if:i.date_specific.value} + - {i.start_date.date} + {if:i.time_specific.value} + {i.ticket_time.time} + {end:} + {else:} + {if:i.time_specific.value} + - {i.ticket_time.time} + {end:} + {end:} + {if:i.show_price}{i.price}{end:}{if:i.show_price}{i.extended}{end:}
      + {else:} + + {end:} + {if:option.cart_images} + {if:i.image} +
    + {end:} + {end:} +
    {i.descr:h}
    +
       +
    + {a.selected} {a.unit_name} +
    +
    {a.unit_cost}/{a.unit_name}{a.money}
      {term.promo.cap}: {promoCode}  + {i.promo.credit}
    + {end:} + + + {end:} + +
    + +
    + + {if:p.policy} +
    +
    +
    + Our policy for this {term.performance.norm}. +
    +

    {p.policy:h}

    +
    +
    + {end:} + + {end:} + +
    + + + + {if:!cartHasOneVenueOnly} + +
    +
    +
    +
    Sub Total
    +
    +
    +
    {c.totalPrice}
    +
    +
    +
    + {end:} + + {if:c.ticket_policy}
    {c.ticket_policy:h}
    {end:} + + + {if:c.ticket_policy}
    {c.ticket_policy:h}
    {end:} + + +
    + + + {if:c.ticket_spec_req.value} +
    +
    Special requests:
    +
    {c.paymentForm.spec_req.value:h}
    +
    + {end:} + + + {if:c.paymentResult} +
    + {if:c.paymentResult.approved} +
    Card Payment Approved
    + +
    Card Type
    {c.paymentResult.cctype}
    +
    Name on Card
    {c.paymentResult.ccname}
    +
    Card Number
    {c.paymentResult.ccnumb}
    +
    Expiration Date
    {c.paymentResult.ccexp}
    +
    Authorization Code
    {c.paymentResult.authCode}
    +
    +
    {term.nav.print_vouchers}
    +
    + {else:} +
    Card Payment Not Complete
    +
    • {c.paymentResult.description}
    +

    Please check the payment information below and try again or contact your credit card company for assistance.

    + {if:forceCheckoutPhase} +
    +
    {term.nav.delete_from_cart}
    +
    + {end:} + + {end:} + +
    + {end:} + +
    + +
    + + {end:} + +
    + {if:cartHasContents} +
    +
    Cart Totals
    +
    +
    +
    Grand Total
    +
    +
    +
    {totals.price}
    +
    +
    +
    + {else:} +

    Your cart is currently empty.

    + {end:} +
    + +
    + +{trackingScript:h} + + + + + diff --git a/views/front/MMM/Shop/paymentSummary.html b/views/front/MMM/Shop/paymentSummary.html new file mode 100755 index 0000000..8ac4b97 --- /dev/null +++ b/views/front/MMM/Shop/paymentSummary.html @@ -0,0 +1,131 @@ +

    + + Click here to reprint your {term.voucher.plur} + +

    + +

    + + {cartEntry.name} +

    + + + + + + + + + + + + + + +{foreach:cartForSummaryCentral,c} +{foreach:c.performances,p} + {foreach:p.dates,d} + {foreach:d.sections,s} + + + {foreach:s.tickets,i} + + + + + + + + {foreach:i.addons,a} + + + + + + + + {end:} + {if:i.promo} + + + + + + + {end:} + {end:} + + + {end:} + {end:} +{end:} + + + + + + + + +
    Quant{term.performance.cap}{term.ticket.cap}PriceTotal
    {i.selected}{p.name:h} + {i.title:h} + {if:i.date_specific.value} + - {i.ticket_date.date} + {if:i.time_specific.value} + {i.ticket_time.time} + {end:} + {else:} + {if:i.time_specific.value} + - {i.ticket_time.time} + {end:} + {end:} + + {if:i.show_price}{i.price}{end:}{if:i.show_price}{i.extended}{end:}
       +
    + {a.selected} {a.unit_name} +
    +
    {a.unit_cost}/{a.unit_name}{a.money}
      {term.promo.cap}: {promoCode}  + {i.promo.credit}
     {c.totalPrice}
    + + +{if:c.ticket_spec_req} +

    + {c.paymentForm.spec_req.value:h} +

    +{end:} + +{end:} + +{if:cartEntry.ticket_policy}

    {cartEntry.ticket_policy:h}

    {end:} + + + + + + + + + + + + +
    First Name:{formData.contact.fname.value}
    Last Name:{formData.contact.lname.value}
    Address:{formData.contact.addr1.value}
     {formData.contact.addr2.value}
    City:{formData.contact.city.value}
    State:{formData.contact.state.value}
    Country:{formData.contact.country.value}
    ZIP/Postal Code:{formData.contact.zip.value}
    Phone:{formData.contact.phone.value}
    E-Mail address:{formData.contact.email.value}
    + +

    + + + + + + + +
    Credit Card Payment Approved
    Card Type{cartEntry.paymentResult.cctype}
    Name on Card{cartEntry.paymentResult.ccname}
    Card Number{cartEntry.paymentResult.ccnumb}
    Expiration Date{cartEntry.paymentResult.ccexp}
    Authorization Code{cartEntry.paymentResult.authCode}
    +

    + + diff --git a/views/front/MMM/Shop/sectionSelect.html b/views/front/MMM/Shop/sectionSelect.html new file mode 100755 index 0000000..db08efa --- /dev/null +++ b/views/front/MMM/Shop/sectionSelect.html @@ -0,0 +1,96 @@ + + + + + + +
    + + +
    {term.section.cap} Selection
    + + + + + +
    {sectionText:h}
    + +{if:reason} +
    +
    We're sorry, we had a problem with your request:
    +
      + {foreach:reason,r} +
    • {r:h}
    • + {end:} +
    +
    +{end:} + +

    You have selected

    +
    +
    +
    +
    {performanceDetail.member_name}

    +
    {performanceDetail.name}
    +
    +
    + + +
    +
    +
    + + +
    +

    Please select from the following

    +
    +{foreach:sectionList,x} +
    + +
    +

    {term.section.cap}: {x.member_name}

    +

    {x.descr:h}

    +
    +
    +{end:} + +
    + +
    + + {startScript:h} + + $(document).ready(function(){ + + // Code to kick off the geolocation-display feature + $("#locationMap").geolocate({ + lat: "#lat", + lng: "#lon", + mapOptions: { + disableDefaultUI: false, + mapTypeControl: true, + mapTypeId: "roadmap", + zoom: 12 + }, + markerOptions: { + draggable: false, + title: "This is your selected location" + } + }); + + }); + + + diff --git a/views/front/MMM/Shop/start-COPY.html b/views/front/MMM/Shop/start-COPY.html new file mode 100644 index 0000000..feda2b4 --- /dev/null +++ b/views/front/MMM/Shop/start-COPY.html @@ -0,0 +1,162 @@ + + +
    +
    +
    +
    +
    {m.name}
    +
    +
    +
    Address: {m.addr1}{if:m.addr2}, {m.addr2}{end:}, {m.city}
    +
    Phone #: {m.phone}
    +
    {m.descr:h}
    +
    +
    +
    +
    (map loads here)
    +
    + + +
    +
    + +
    + {foreach:m.performances,p} +
    +
    +
    +
    + {if:showTickets} + {p.name} + {else:} + {p.name} + {end:} +
    +
    +
    +
    {term.prop.cap}: {p.member_name}
    +
    Dates: {p.start_date.date} through {p.end_date.date}
    +
    +
    + {if:!showTickets} + {term.nav.select} + {end:} + + + {foreach:p.sections,s} +

     

    +
    +
    +
    + {if:!p.oneSectionOnly} + {s.sectionDetail.name}
    + {end:} + +
    + +
    +
    + + + {foreach:s.ticketsData,x} +
    + {if:option.ticket_selection.include_options_in_ticket_list} +
    +
    +
    Price: 
    +
    +
    {x.price}
    +
    +
    +
    +
    Select date: 
    +
    +
    + + +
    +
    +
    +
    +
    Quant: 
    +
    +
    (select date)
    +
    +
    +
    + + {end:} + +
    + {if:option.ticket_selection.include_options_in_ticket_list} +
    {x.title}
    + {else:} +
    + {x.name} +
    + {term.nav.select} + {end:} +
    +
    + {if:x.descr} +

    {x.descr:h}

    + {end:} +
    + {if:!x.date_specific.value} + Use any date{if:x.start_date.timestamp} from {x.start_date.date} to {x.end_date.date}{end:}{if:!x.time_specific.value}, {end:} + {end:} + {if:!x.time_specific.value} + Use any time of day, + {else:} + Time: {x.ticket_time.time}, + {end:} + {if:x.unlimted_use.value} + Each {term.ticket.norm} may be used an unlimited number of times + {else:} + + {end:} +
    +
    +
    + {if:option.ticket_selection.include_options_in_ticket_list} +
    +
    +
    Price each: 
    +
    +
    {x.price}
    +
    +
    +
    +
    Select date: 
    +
    +
    + + +
    +
    +
    +
    +
    Quant: 
    +
    +
    (select date)
    +
    +
    +
    + + {end:} +
    + + + {end:} + +
    + + {end:} + + + +
    + {end:} +
    +
    + {end:} diff --git a/views/front/MMM/Shop/start.html b/views/front/MMM/Shop/start.html new file mode 100755 index 0000000..a278490 --- /dev/null +++ b/views/front/MMM/Shop/start.html @@ -0,0 +1,406 @@ + + + +
    + +
    +
    {term.event.cap} Selection
    + + +
    + +
    {introText:h}
    + {if:reason} +
    +
    We're sorry, we had a problem with your request:
    +
      + {foreach:reason,r} +
    • {r:h}
    • + {end:} +
    +
    + {end:} +

    Please select from the following

    +{if:showTickets} +
    + + + + +{end:} + + {foreach:membersList,m} +
    +
    +
    +
    +
    {m.name}
    +
    +
    +
    Address: {m.addr1}{if:m.addr2}, {m.addr2}{end:}, {m.city}
    +
    Phone #: {m.phone}
    +
    {m.descr:h}
    +
    +
    + {if:option.select_images} + {if:m.image} +
    + {end:} + {end:} + +
    + {foreach:m.performances,p} +
    + {if:option.select_images} + {if:p.image} +
    + {else:} +
    + {end:} + {else:} +
    + {end:} +
    +
    + {if:showTickets} + {p.name} + {else:} + {p.name} + {end:} +
    +
    +
    + + {if:p.start_date.timestamp}
    Dates: {p.start_date.date}{if:p.end_date.timestamp} - {p.end_date.date} {end:}
    {end:} +
    {p.short_descr:h}
    +
    +
    + {if:option.select_images} + {if:p.image} +
    + {end:} + {end:} + {if:!showTickets} + + {end:} + + + + {foreach:p.sections,s} +

     

    +
    +
    +
    + {if:!p.oneSectionOnly} + {s.sectionDetail.name}
    + {end:} + +
    + +
    +
    + + + {foreach:s.ticketsData,x} +
    + {if:option.ticket_selection.include_options_in_ticket_list} +
    +
    +
    Price: 
    +
    +
    {x.price}
    +
    +
    +
    +
    Select date: 
    +
    +
    + + +
    +
    +
    +
    +
    Quant: 
    +
    +
    (select date)
    +
    +
    +
    + + {end:} + +
    + {if:option.ticket_selection.include_options_in_ticket_list} +
    {x.title}
    + {else:} +
    + {x.name} +
    + {term.nav.select} + {end:} +
    +
    + {if:x.descr} +

    {x.descr:h}

    + {end:} +
    + {if:!x.date_specific.value} + Use any date{if:x.start_date.timestamp} from {x.start_date.date} to {x.end_date.date}{end:}{if:!x.time_specific.value} {end:} + {end:} + {if:!x.time_specific.value} + Use any time of day, + {else:} + Time: {x.ticket_time.time}, + {end:} + {if:x.unlimted_use.value} + Each {term.ticket.norm} may be used an unlimited number of times + {else:} + + {end:} +
    +
    +
    + {if:option.ticket_selection.include_options_in_ticket_list} +
    +
    +
    Price each: 
    +
    +
    {x.price}
    +
    +
    +
    +
    Select date: 
    +
    +
    + + +
    +
    +
    +
    +
    Quant: 
    +
    +
    (select date)
    +
    +
    +
    + + {end:} +
    + + + {end:} + +
    + + {end:} + + + +
    + {end:} +
    +
    + {end:} +{if:showTickets} + + +{end:} +
    + +{startScript:h} + + var addButtonPushed = false; + + // Dates for inventory data + var tickets = {ticketsJSON:h}; + + var ticketQuantSelection = '\ + \ + '; + + var ticketTooLate = '\ +

    \ + Sorry, too late to select these {term.ticket.plur} on-line.\ +

    \ + '; + + + + $(document).ready(function(){ + + // Code to kick off the geolocation-display feature + function doLocationMap(id) { + $("#locationMap_" + id).geolocate({ + lat: "#lat_" + id, + lng: "#lon_" + id, + mapOptions: { + disableDefaultUI: false, + mapTypeControl: true, + mapTypeId: "roadmap", + zoom: 12 + }, + markerOptions: { + draggable: false, + title: "This is your selected location" + } + }); + } + {foreach:membersList,m} + doLocationMap({m.id}); + {end:} + + // DatePicker action + function avail(date) { + m = (date.getMonth()+1); + if (m < 10) { + m = '0' + m; + } + d = date.getDate(); + if (d < 10) { + d = '0' + d; + } + y = date.getFullYear(); + mdy = m + '/' + d + '/' + y; + if (dates[mdy]) { + return [true,"","Available"]; + } else { + return [false,"","Not Available"]; + } + } + + // for each ticket + $.each(tickets, function(index, ticket) { + + var inventory = ticket.inventory; + + // Build date data array and count dates for this ticket + var dateCount = 0; + var dateData = false + $.each(inventory, function(index, date) { + + // Count the number of dates + dateCount++; + + // If this is the first one, store it in case it's the only one + dateData = date; + + }); // each date + + // if there's no date specific tickets + if (!ticket.dateSpecific) { + + // Populate date input field + $('#GLMeventDateSelect_' + ticket.id).html(''); + doQuantSelection(ticket.id, dateData.id, dateData.available, dateData.tooLate); + + // if there's only one date, then display that and move on. + } else if (!ticket.dateSpecific || dateCount == 1) { + + // populate date input field + $('#GLMeventDate_' + ticket.id).html('
    Date:
    ' + dateData['date'] + '
    '); + doQuantSelection(ticket.id, dateData.id, dateData.available, dateData.tooLate); + + } else { + + // DatePicker action + function avail(date) { + m = (date.getMonth()+1); + if (m < 10) { + m = '0' + m; + } + d = date.getDate(); + if (d < 10) { + d = '0' + d; + } + y = date.getFullYear(); + mdy = m + '/' + d + '/' + y; + if (inventory[mdy]) { + return [true,"","Available"]; + } else { + return [false,"","Not Available"]; + } + } + + // Use the date picker to select a date + $('#GLMeventDateInput_' + ticket.id).datepicker({ + beforeShowDay: avail, + dateFormat: "mm/dd/yy", +// *** NEED TO FIX REFERENCE TO "performanceDetail" since that's not available on this page + minDate: "{performanceDetail.start_date.date}", + maxDate: "{performanceDetail.end_date.date}", + onSelect: function(selectedDate, inst) { + // Get data for the selected date + dateData = inventory[selectedDate]; + $('#GLMeventInvID_' + ticket.id).val(dateData.id); + doQuantSelection(ticket.id, dateData.id, dateData.available, dateData.tooLate); + } // Date Selection + + }); // Date Picker + + + } + + }); // each ticket + + function doQuantSelection(id, invId, available, tooLate) { + + // Build the ticket quant options + var ticketQuants = ''; + var selectMax = available; + if (selectMax > 50) { + selectMax = 50; + } + + if (tooLate) { + $('#GLMticketQuantContainer_' + id).html(ticketTooLate); + } else { + + // note that the braced lte below is needed to inject a less-than-or-equal-to operator without having flexy chew on it. + for (var i = 1; i {lte:h} (selectMax*1); i++) { + ticketQuants = ticketQuants.concat(''); + } + + // Populate the ticket quantity container + tmpQuantSel = ticketQuantSelection.replace(/\[id\]/g, id); + $('#GLMticketQuantContainer_' + id).html(tmpQuantSel.replace(/\[ticket-quants\]/g, ticketQuants)); + } + + } + + $('#GLMselectButton').click(function() { + + // Check for a selected ticket + var ticketSelected = false; + $('.glmTicketQuant').each(function( index ) { + if ($(this).val() != '') { + ticketSelected = true; + } + }); + + if (ticketSelected) { + selectButtonPressed = true; + setBlocker(); + $('#GLMselectForm').submit(); + } else { + alert('Please select a {term.ticket.norm} quantity.') + return false; + } + + }); + + function setBlocker() { + $('#glmReloadBlocker').show(); + } + + }); + + + diff --git a/views/front/MMM/Shop/svn-commit.tmp b/views/front/MMM/Shop/svn-commit.tmp new file mode 100644 index 0000000..8c664dd --- /dev/null +++ b/views/front/MMM/Shop/svn-commit.tmp @@ -0,0 +1,4 @@ +Anthony changes for "use any date" or whatever +--This line, and those below, will be ignored-- + +M checkout.html diff --git a/views/front/MMM/Shop/ticketOpt.html b/views/front/MMM/Shop/ticketOpt.html new file mode 100755 index 0000000..1564c62 --- /dev/null +++ b/views/front/MMM/Shop/ticketOpt.html @@ -0,0 +1,273 @@ + + + + + +
    + +
    +
    Ticket Selection
    + + +
    + +
    {ticketOptText:h}
    + {if:reason} +
    +
    We're sorry, we had a problem with your request:
    +
      + {foreach:reason,r} +
    • {r:h}
    • + {end:} +
    +
    + {end:} +

    You have selected

    + +
    +
    +
    +
    {performanceDetail.name}
    +
    +
    +
    {term.prop.cap}: {performanceDetail.member_name}
    + + +
    +
    +
    +
    +
    {sectionDetail.name}
    +
    +
    + +
    +
    +
    +
    +
    {ticketDetail.name}
    +
    +
    + {if:!ticketDetail.date_specific.value} +
    Use any date {if:ticketDetail.start_date.timestamp} from {ticketDetail.start_date.date} to {ticketDetail.end_date.date}{end:}
    + {end:} + {if:!ticketDetail.time_specific.value} +
    Use any time
    + {else:} +
    Time: {ticketDetail.ticket_time.time}
    + {end:} + {if:!ticketDetail.unlimted_use.value} + + {else:} +
    Each {term.ticket.norm} may be used an unlimited number of times
    + {end:} +
    {ticketDetail.descr:h}
    +
    +
    +
    + +

    Please select from the following.

    +
    +
    +
    +
    +
    +
    +
    +
    Select desired date:
    +
    +
    (click in field to set date)
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    Select Quantity:
    +
    +
    (please select date first)
    +
    +
    +
    +
    + {if:reason}
    (disabled - please see above)
    {else:}
    {term.nav.add_to_cart}
    {end:} +
    + +{startScript:h} + + // Whether ticket has date specific inventory + var dateSpecific = {ticketDetail.date_specific.value} + 0; + + // Dates for inventory data + var dates = {inventoryJSON:h}; + + $(document).ready(function(){ + + // DatePicker action + function avail(date) { + m = (date.getMonth()+1); + if (m < 10) { + m = '0' + m; + } + d = date.getDate(); + if (d < 10) { + d = '0' + d; + } + y = date.getFullYear(); + mdy = m + '/' + d + '/' + y; + if (dates[mdy]) { + return [true,"","Available"]; + } else { + return [false,"","Not Available"]; + } + } + var dateData = false; + + var ticketQuantSelection = '\ + \ + '; + var ticketTooLate = '\ +

    \ + Sorry, too late to select these {term.ticket.plur} on-line.\ + {term.ticket.plur_cap} must be purchased at least {detail.performance.purch_leadtime} hours prior to the {term.performance.norm}.\ + Please select another date or time.\ +

    \ + '; + var selectedInv; + var ticketQuants; + var addButtonPushed = false; + + // Start by counting the number of dates to see if we have only 1 + var dateCount = 0; +// if (dateSpecific) { + $.each(dates, function(index, date) { + dateCount = dateCount + 1; + dateData = date; + }); +// } + // if there's no date specific tickets + if (!dateSpecific) { + // Populate date input field + $('#GLMeventDateSelectBlock').html(''); + doQuantSelection(); + // if there's only one date, then display that and move on. + } else if (!dateSpecific || dateCount == 1) { + // populate date input field + $('#GLMeventDate').val(dateData['date']); + $('#GLMtickets').html('
    Date:
    ' + dateData['date'] + '
    '); + + doQuantSelection(); + } else { + // Use the date picker to select a date + dateData = false; + $("#GLMeventDate").datepicker({ + beforeShowDay: avail, + dateFormat: "mm/dd/yy", + minDate: "{performanceDetail.start_date.date}", + maxDate: "{performanceDetail.end_date.date}", + onSelect: function(selectedDate, inst) { + // Update input message + $('#GLMdateMessage').html('
    '); + + // Get data for the selected date + dateData = dates[selectedDate]; + doQuantSelection(); + } // Date Selection + + }); // Date Picker + + } + + function doQuantSelection() { + // Build the ticket quant options + ticketQuants = ''; + var selectMax = dateData['available']; + if (selectMax > 50) { + selectMax = 50; + } + var tooLate = dateData['tooLate']; + if (tooLate) { + $('#GLMticketQuantContainer').html(ticketTooLate); + } else { + // note that the braced lte below is needed to inject a less-than-or-equal-to operator without having flexy chew on it. + for (var i = 1; i {lte:h} (selectMax*1); i++) { + ticketQuants = ticketQuants.concat(''); + } + + // Populate the ticket quantity container + $('#GLMticketQuantContainer').html(ticketQuantSelection.replace(/\[ticket-quants\]/g, ticketQuants)); + } +// doAddToCartSetup(); + } + +// function doAddToCartSetup() { + // Add to cart action + $('#GLMaddToCart').click(function() { + if (addButtonPushed) { + return; + } + var reason = ''; + // Check date + if (dateData) { + selectedInv = dateData.id; + } else { + reason = reason.concat('* You need to select a date first.\n'); + } + // Check quantity + var selectedQuant = (parseInt($('#glmQuantSelector').val()) + 0); + if (selectedQuant == 0) { + reason = reason.concat('* You need to select a quantity first.\n'); + } + // Check if there's a reason we can't add this to the cart yet + if (reason != '') { + alert(reason); + return; + } + // Adding to cart + addButtonPushed = true; + $("#GLMeventDate").datepicker('disable'); + $('#glmQuantSelector').prop('disabled', 'disabled'); + setBlocker(); + // Submit to cart + window.location = "{baseSCRIPT}&Action=Shop_cart&cart=add&PerformanceID={performanceDetail.id}&SectionID={sectionDetail.id}&TicketID={ticketDetail.id}&ticket_inv=" + selectedInv + "&quant=" + selectedQuant; + + }); +// } + // Code to kick off the geolocation-display feature + $("#locationMap").geolocate({ + lat: "#lat", + lng: "#lon", + mapOptions: { + disableDefaultUI: false, + mapTypeControl: true, + mapTypeId: "roadmap", + zoom: 12 + }, + markerOptions: { + draggable: false, + title: "This is your selected location" + } + }); + // Navigation buttons + $('#GLMnavCart').click(function() { // Add to Cart + window.location = '{baseSCRIPT}&Action=Shop_cart'; + }); + $('#GLMnavSelectEvent').on('click', function() { // Return to Event Selection + window.location = '{startURL:h}'; + }); + + function setBlocker() { + $('#glmReloadBlocker').show(); + } + + }); + + diff --git a/views/front/MMM/Shop/ticketSelect.html b/views/front/MMM/Shop/ticketSelect.html new file mode 100755 index 0000000..952a48c --- /dev/null +++ b/views/front/MMM/Shop/ticketSelect.html @@ -0,0 +1,326 @@ + + + +
    + +
    +
    {term.ticket.cap} Selection
    + +
    + {term.nav.show_selected} + {if:!option.ticket_selection.start_at_cart} + {term.nav.select_more} + {end:} +
    +
    + +
    {ticketText:h}
    +{if:reason} +
    +
    We're sorry, we had a problem with your request:
    +
      + {foreach:reason,r} +
    • {r:h}
    • + {end:} +
    +
    +{end:} +

    You have selected

    + + + +{foreach:sections,s} +
    +
    + + +
    + {if:performanceDetail.image} +
    +
    + {else:} +
    + {end:} + +
    +
    {performanceDetail.member_name:h}

    +
    {performanceDetail.name:h}
    +
    +
    +
    + {if:!oneSectionOnly} + {s.sectionDetail.name}
    + {end:} + +
    + + {if:performanceDetail.descr} + {performanceDetail.descr:h} + {end:} +
    +
    +
    +
    +
    + + +

    Please select from the following. If you do not see the number of tickets available that you require, please select a different date or time.

    +
    +
    + + + + + {foreach:s.ticketsData,x} + {if:!x.tooLateToBuy} +
    + {if:option.ticket_selection.include_options_in_ticket_list} +
    +
    +
    Price: 
    +
    +
    {x.price}
    +
    +
    +
    +
    Select date: 
    +
    +
    + + +
    +
    +
    +
    +
    Quant: 
    +
    +
    (select date)
    +
    +
    +
    + {end:} +
    + {if:option.ticket_selection.include_options_in_ticket_list} +
    {x.title}
    + {else:} +
    + {x.name} +
    + {end:} +
    +
    + {if:x.descr} +

    {x.short_descr:h}

    + {end:} +

    + {if:!x.date_specific.value} + {if:x.start_date.timestamp} Date: {x.start_date.date}{end:}{if:!x.start_end_dates_same} to {x.end_date.date}{end:}{if:!x.time_specific.value} {end:} + {end:} + {if:!x.time_specific.value} + + {else:} + Time: {x.ticket_time.time} + {end:} + {if:x.unlimted_use.value} + Each {term.ticket.norm} may be used an unlimited number of times + {else:} + + {end:} +

    +
    +
    +
    +
    + {end:} + {end:} + +
    +
    + +{end:} + +
    + +{if:option.ticket_selection.include_options_in_ticket_list} + + {startScript:h} + + var addButtonPushed = false; + + // Dates for inventory data + var tickets = {ticketsJSON:h}; + + var ticketQuantSelection = '\ + \ + '; + + var ticketTooLate = '\ + Sorry, too late to select these {term.ticket.plur} on-line.\ + {term.ticket.plur_cap} must be purchased at least [hours] hours prior to the {term.performance.norm}.\ + Please select another date or time.\ + '; + + + $(document).ready(function(){ + + // for each ticket + $.each(tickets, function(index, ticket) { + + if (ticket.haveFutureInventory) { + + var inventory = ticket.inventory; + + // Build date data array and count dates for this ticket + var dateCount = 0; + var dateData = false + $.each(inventory, function(index, date) { + + // Count the number of dates + dateCount++; + + // If this is the first one, store it in case it's the only one + dateData = date; + + }); // each date + + // if there's no date specific tickets + if (!ticket.dateSpecific) { + + // Populate date input field + $('#GLMeventDateSelect_' + ticket.id).html(''); + doQuantSelection(ticket.id, dateData.id, dateData.available, ticket.tooLate); + + // if there's only one date, then display that and move on. + } else if (!ticket.dateSpecific || dateCount == 1) { + + // populate date input field + $('#GLMeventDateSelect_' + ticket.id).html(' \ +
    Date Available: 
    \ +
    \ +
    \ + ' + dateData.ticket_date.date + ' \ + \ +
    \ +
    '); + + doQuantSelection(ticket.id, dateData.id, dateData.available, ticket.tooLate); + + } else { + + // DatePicker action + function avail(date) { + m = (date.getMonth()+1); + if (m < 10) { + m = '0' + m; + } + d = date.getDate(); + if (d < 10) { + d = '0' + d; + } + y = date.getFullYear(); + var mdy = m + '/' + d + '/' + y; + if (inventory[mdy]) { + if (inventory[mdy]['tooLate']) { + return [false,"","Not Available"]; + } else { + return [true,"","Available"]; + } + } else { + return [false,"","Not Available"]; + } + } + + // Use the date picker to select a date + if($('#GLMeventDateInput_' + ticket.id).length > 0) { + $('#GLMeventDateInput_' + ticket.id).datepicker({ + beforeShowDay: avail, + dateFormat: "mm/dd/yy", + minDate: ticket.startDate, + maxDate: ticket.endDate, + onSelect: function(selectedDate, inst) { + // Get data for the selected date + dateData = inventory[selectedDate]; + $('#GLMeventInvID_' + ticket.id).val(dateData.id); + doQuantSelection(ticket.id, dateData.id, dateData.available, dateData.tooLate); + } // Date Selection + + }); // Date Picker + } + + } + + } // if have future inventory + + }); // each ticket + + function doQuantSelection(id, invId, available, tooLate) { + + // Build the ticket quant options + var ticketQuants = ''; + var selectMax = available; + if (selectMax > 50) { + selectMax = 50; + } + + if (tooLate) { + $('#GLMticketQuantContainer_' + id).html(ticketTooLate.replace(/\[hours\]/g, {performanceDetail.purch_leadtime})); + } else { + // note that the braced lte below is needed to inject a less-than-or-equal-to operator without having flexy chew on it. + for (var i = 1; i {lte:h} (selectMax*1); i++) { + ticketQuants = ticketQuants.concat(''); + } + + // Populate the ticket quantity container + tmpQuantSel = ticketQuantSelection.replace(/\[id\]/g, id); + $('#GLMticketQuantContainer_' + id).html(tmpQuantSel.replace(/\[ticket-quants\]/g, ticketQuants)); + } + + } + + var selectButtonPressed = false; + + $('.GLMselectButton').click(function() { + // Prevent multiple submissions + if (selectButtonPressed == true) { + return; + } + + // Check for a selected ticket + var ticketSelected = false; + $('.glmTicketQuant').each(function( index ) { + if ($(this).val() != '') { + ticketSelected = true; + } + }); + + if (ticketSelected) { + selectButtonPressed = true; + setBlocker(); + $('#GLMselectForm').submit(); + } else { + alert('Please select a {term.ticket.norm} quantity.') + return false; + } + + }); + + function setBlocker() { + $('#glmReloadBlocker').show(); + } + if( $(window).width() < 768 ){ + $('.glmBlock').not(":first").each(function() { + var left = $(this).find( $('.glmBlockContentLeft') ); + left.prependTo( $(this) ).find( $('glmBlockContentRight') ); + }); + } + }); + +{end:} + diff --git a/views/front/MMM/foot.html b/views/front/MMM/foot.html new file mode 100755 index 0000000..36eb69f --- /dev/null +++ b/views/front/MMM/foot.html @@ -0,0 +1,9 @@ + +{if:option.development} +

    + Running on Development Server: + + Reset Session + +

    +{end:} \ No newline at end of file diff --git a/views/front/MMM/head.html b/views/front/MMM/head.html new file mode 100755 index 0000000..2b09b3e --- /dev/null +++ b/views/front/MMM/head.html @@ -0,0 +1,38 @@ + +{startScript:h} + // Pass some reference parameters to JAVAScript + var baseSiteURL = '{baseURL}'; + var baseAppURL = '{baseAppURL}'; + +{if:!jQueryLoaded} + +{end:} +{if:!jQueryUiLoaded} + + +{end:} + + + +{if:customCssFile} + + +{end:} +{if:frontDebug} + +
    +{end:} +{startScript:h} + var disp_setting="toolbar=no,location=no,directories=no,menubar=no,scrollbars=yes,width=1000, height=700, left=100, top=25"; + {if:frontDebug} + debugWindowFront = window.open("{baseURL}index.php?Action=Debug_update","emDebugWindowFront",disp_setting); + {end:} + + +
    +
    Updating your information
    Please wait ...
    +
    + + {if:adminUser} +

    Purchasing By Admin User

    + {end:} diff --git a/views/front/MMM/index.html b/views/front/MMM/index.html new file mode 100755 index 0000000..9f04bbb --- /dev/null +++ b/views/front/MMM/index.html @@ -0,0 +1,34 @@ + + + + + + + + + + +

    PLEASE NOTE:

    + +

    + There is no general access to this site. + All access to this site should be through an appropriate link. + If you arrived here by mistake (or exploring), nothing but this message will be displayed. + If you have any concerns about this site, please contact Gaslight Media. +

    + +

    + Gaslight Media
    + 120 East Lake Street
    + Petoskey, MI 49770
    +  
    + Phone: 231-487-0692
    + E-Mail: info@gaslightmedia.com
    + Web: http://www.gaslightmedia.com +

    + + + + + + diff --git a/views/front/PointerBoat/Debug/index.html b/views/front/PointerBoat/Debug/index.html new file mode 100755 index 0000000..a42397f --- /dev/null +++ b/views/front/PointerBoat/Debug/index.html @@ -0,0 +1,42 @@ + + + + + + +
    Startup: {debugStartupTime}
    +
    Event Management Front-End Debug
    +
    +
    + Updated: {debugUpdateTime} +
    +
    + {debugData:h} +
    + + + {startScript:h} + + // Reload the current window with Action = Debug_update + function reloadDebugWindow() + { + window.location("{baseSCRIPT}&Action=Debug_update"); + } + + + \ No newline at end of file diff --git a/views/front/PointerBoat/Debug/start.html b/views/front/PointerBoat/Debug/start.html new file mode 100755 index 0000000..66c3023 --- /dev/null +++ b/views/front/PointerBoat/Debug/start.html @@ -0,0 +1,27 @@ + + + + + + +
    Startup: {debugStartupTime}
    +
    Event Management Front-End Debug
    +
    +
    Debug Startup
    + + \ No newline at end of file diff --git a/views/front/PointerBoat/Shop/PayPalApproved.html b/views/front/PointerBoat/Shop/PayPalApproved.html new file mode 100755 index 0000000..4dff5eb --- /dev/null +++ b/views/front/PointerBoat/Shop/PayPalApproved.html @@ -0,0 +1,41 @@ + + + + + +
    + +

    Your PayPal payment has been approved.

    + + +
    + +

    + Your cart will now reflect that the payment has been made. +

    + +
    + +
    +
    Close This Window
    +
    + +
    + + + + diff --git a/views/front/PointerBoat/Shop/PayPalFail.html b/views/front/PointerBoat/Shop/PayPalFail.html new file mode 100755 index 0000000..bb62666 --- /dev/null +++ b/views/front/PointerBoat/Shop/PayPalFail.html @@ -0,0 +1,49 @@ + + + + + +
    + +

    Unable to process your payment!

    + + +
    + +

    +

    Sorry, there was a problem.
    +

    + +

    + We were unable to find your purchase information and are therefore + are unable to process your payment through PayPal. This could be + due to you not performing any action with your pending purchase + for too long. Please click the "Return to selected tickets" button + at the top of the checkout page to see if your selections are still listed. +

    + +
    + +
    +
    Close This Window
    +
    + +
    + + + + diff --git a/views/front/PointerBoat/Shop/additionalInfo.html b/views/front/PointerBoat/Shop/additionalInfo.html new file mode 100644 index 0000000..b490910 --- /dev/null +++ b/views/front/PointerBoat/Shop/additionalInfo.html @@ -0,0 +1,246 @@ + + + +
    + + + +
    +
    + + + {term.nav.show_selected} + {if:!option.ticket_shop.start_at_cart} + {term.nav.select_more} + {end:} + + +

    {cartText:h}

    + +
    +
    + +{if:reason} + + + +
    +
    +
    +

    We're sorry, we had a problem with your request:

    +
      + {foreach:reason,r}{Chuck} +
    • {r:h}
    • + {end:} +
    +
    +
    +
    +{end:} + + + +{foreach:cart,c} + + {if:option.show_location_blocks} +
    +
    +
    +
    +

    {c.name:h}

    +
    + {end:} + + + + + {if:c.needAssignemntOrDate} + {if:c.needAssignment} + +
    + {if:!c.haveAssignment} +
    {text.cart.select_assignment_location}
    + {else:} +
    {text.cart.select_assignment_location}
    + {end:} + {foreach:c.assignmentMembers,a} + {if:a.entrances} + {foreach:a.entrances,e} +
    + {if:option.cart_images} + {if:e.image} +
    + {end:} + {end:} +
    + {if:e.selected} + {a.name} - {e.name}
    + {else:} + {a.name} - {e.name}
    + {end:} +
    +
    {e.addr1}{if:e.addr2}, {e.addr2}{end:}, {e.city}
    +
    {e.phone}
    + {if:e.descr} +
    {e.descr:h}
    + {end:} +
    +
    + {end:} +
    + {else:} + {if:a.selected} + {a.name}
    + {else:} + {a.name}
    + {end:} + {end:} + {end:} +  
    + {end:} + + {if:option.ask_for_likely_date} + {if:c.needLikelyDate} +
    +

    + {if:!c.likelyDate} + + {else:} + + {end:} + {text.cart.select_likely_date}   + + mm/dd/yyyy + {if:text.cart.select_likely_date_explain} +
    {text.cart.select_likely_date_explain} + {end:} +

    +
    + {end:} + {end:} +
    +
    + {end:} + {if:!c.needAssignment} + + {if:option.cart_images}{if:c.image} +
    + + +
    + {end:}{end:} + {end:} + +
    +
    +
    + +{end:} + + + +{if:cartHasContents} +
    +
    + {if:!blockCheckout} + {term.nav.checkout} + {else:} + Please complete the items in RED above. + {end:} +
    +
    +{else:} +
    +
    +

    Your cart is currently empty.

    +
    +
    +{end:} + + + + + + + + + diff --git a/views/front/PointerBoat/Shop/cart.html b/views/front/PointerBoat/Shop/cart.html new file mode 100755 index 0000000..f92072f --- /dev/null +++ b/views/front/PointerBoat/Shop/cart.html @@ -0,0 +1,431 @@ + + + +
    +
    + + +
    + + +
    + {if:!option.ticket_selection.start_at_cart} + {term.nav.select_more} + {end:} + +
    +
    + +
    {cartText:h}
    + {if:reason} +
    +
    We're sorry, we had a problem with your request:
    +
      + {foreach:reason,r}{Chuck} +
    • {r:h}
    • + {end:} +
    +
    + {end:} + {if:havePromoCodes} +
    +
    +
    If you have a {term.promo.norm}, please enter it here:
    +
    +
    + {end:} + {foreach:cart,c} +
    +
    {c.name:h}
    +
    + {foreach:c.performances,p} +
    +
    + {if:!option.ticket_selection.start_at_cart} + {term.nav.select_more_of_these} + + {end:} +
    + +
    {c.name:h} - {p.name}
    +
    + {if:p.descr}
    {p.descr:h}
    {end:} + {if:p.short_descr}
    {p.short_descr:h}
    {end:} + {if:option.cart_images}{if:p.image} + + {end:}{end:} +
    +
    +
    +
    + {foreach:p.dates,d} +
    + {if:d.dateSpecific} + {d.fullDate} + {else:} + + {if:c.likelyDate} + - Likely Date {c.likelyDate} + {end:} + {end:} + {foreach:d.sections,s} + + + + {if:!p.oneSectionOnly} + + {end:} + + + + + {foreach:s.tickets,i} + + + {if:!p.oneSectionOnly} + + {end:} + + + + + {if:i.problem} + + + + {end:} + {if:i.descr} + + + {if:!p.oneSectionOnly} + + + {end:} + + {foreach:i.addons,a} + + + {if:!p.oneSectionOnly} + + {end:} + + + + + {end:} + + + {if:i.promo} + + + {if:!p.oneSectionOnly} + + {end:} + + + + {end:} + + {end:} +
    QuantSection{term.ticket.cap}PriceTotal
    + + {s.name} + {i.title} + {if:false} + {if:i.date_specific.value} + - {i.start_date.date} + {if:i.time_specific.value} + {i.ticket_time.time} + {end:} + {else:} + {if:i.time_specific.value} + - {i.ticket_time.time} + {end:} + {end:} + {end:} + {if:i.show_price}{i.price}{end:}{if:i.show_price}{i.extended}{end:}
     {i.problemText}
      + {else:} + + {end:} + {if:option.cart_images}{if:i.image} +
    + {end:}{end:} +
    {i.descr:h}
    +
       +
    + +
    +
    {a.descr:h}
    +
    {a.unit_cost}/{a.unit_name}{a.money}
      {term.promo.cap}: {promoCode}  + {i.promo.credit}
    + {end:} +
    + {end:} +
    +
    + {end:} +
    + {if:c.ticket_policy}
    {c.ticket_policy:h}
    {end:} + +{if:option.ask_for_assignment_and_likely_date} + {if:c.needAssignemntOrDate} + {if:c.needAssignment} + +
    + {if:!c.haveAssignment} +
    {text.cart.select_assignment_location}
    + {else:} +
    {text.cart.select_assignment_location}
    + {end:} + {foreach:c.assignmentMembers,a} + {if:a.entrances} + {foreach:a.entrances,e} +
    + {if:option.cart_images} + {if:e.image} +
    + {end:} + {end:} +
    + {if:e.selected} + {a.name} - {e.name}
    + {else:} + {a.name} - {e.name}
    + {end:} +
    +
    {e.addr1}{if:e.addr2}, {e.addr2}{end:}, {e.city}
    +
    {e.phone}
    + {if:e.descr} +
    {e.descr:h}
    + {end:} +
    +
    + {end:} +
    + {else:} + {if:a.selected} + {a.name}
    + {else:} + {a.name}
    + {end:} + {end:} + {end:} +  
    + {end:} + + {if:option.ask_for_likely_date} + {if:c.needLikelyDate} +
    + {if:!c.likelyDate} + + {else:} + + {end:} + {text.cart.select_likely_date}   + + mm/dd/yyyy +
    + {end:} + {end:} +
    +
    + {end:} + {if:!c.needAssignment} + + {if:option.cart_images}{if:c.image} +
    + + +
    + {end:}{end:} + {end:} +{end:} + + +
    + {end:} + + +
    + {if:cartHasContents} +
    + Grand Total   {totals.price} +
    +
    + {if:totals.tickets} + + {term.nav.checkout} + + {else:} + Your cart is currently empty. + {end:} +
    + {else:} +

    Your cart is currently empty.

    + {end:} +
    + + {if:option.cart_promotions} +
    + You may also be interested in ...
    + {foreach:cartPromotions,p} +
    + + {if:p.image} +
    + {end:} +
    + {if:p.start_date} +

    + Dates: {p.start_date.date} +

    + {end:} + + {if:p.short_descr}
    {p.short_descr:h}
    {end:} + {if:p.short_descr}
    {p.short_descr:h}
    {end:} +
    +
    + {end:} +
    + {end:} + + + +
    + +{startScript:h} + + $(document).ready(function(){ + + // Block direct form submission - Everything submits by jQuery action + $('#cartForm').submit(function( event ) { + return false; + }); + + // Convert input fields to select lists + $('.glmCartQuant').each(function() { + + var id = $(this).attr('id'); + var ticket = $(this).attr('data-ticket'); + var addon = $(this).attr('data-addon'); + var max = $(this).attr('data-max'); + var value = $(this).attr('value'); + var units = $(this).attr('data-units'); + var numbSel = ''; + + // Build a picklist for this input + for (var i = 0 ; i {lte:h} max ; i++) { + if (value == i) { + numbSel = numbSel.concat(''); + } else { + numbSel = numbSel.concat(''); + } + } + + $('#quant_' + id).html('' + units); + + }); + + // Get or set vertical scroll to return to same place when cart reloads + function getVertScroll() { + var vertScroll = window.pageYOffset; + if (vertScroll == 0) { + var vertScroll = document.documentElement.scrollTop; + } + if (vertScroll == 0) { + var vertScroll = document.body.scrollTop; + } + return vertScroll; + } + + // When a cart value changes, submit it as a cart update. + $('.glmCartSelect').change(function() { + vertScroll = getVertScroll(); + var ticket = $(this).attr('data-ticket'); + var addon = $(this).attr('data-addon'); + var value = $(this).val(); + + setBlocker(); + window.location = "{baseSCRIPT}&Action=Shop_cart&cart=update&ticket_inv=" + ticket + "&addon=" + addon + "&quant=" + value + "&vertScroll=" + vertScroll; + + }); + + // When there's a change in the promo code input, submit it. + $('#promoCodeInput').change(function() { + var value = $(this).val(); + setBlocker(); + window.location = "{baseSCRIPT}&Action=Shop_cart&cart=promo_code&promo_code=" + value; + }); + + // When a member selection for unassigned items changes, submit it so it's in the session + $('.glmAssignmentChange').change(function() { + vertScroll = getVertScroll(); + var member = $(this).attr('data-Member'); + var assignedTo = $(this).val(); + var assignedToEntrance = $(this).attr('data-entrance'); + setBlocker(); + window.location = "{baseSCRIPT}&Action=Shop_cart&cart=update_assignment&member_assigned=" + member + "&assigned_to=" + assignedTo + "&entrance_assigned=" + assignedToEntrance + "&vertScroll=" + vertScroll; + }); + + // When a likely departure date changes, submit it so it's in the session + $('.glmLikelyDateChange').change(function() { + vertScroll = getVertScroll(); + var member = $(this).attr('data-Member'); + var likelyDate = $(this).val(); + setBlocker(); + window.location = "{baseSCRIPT}&Action=Shop_cart&cart=update_likelyDate&member=" + member + "&likely_date=" + likelyDate + "&vertScroll=" + vertScroll; + + }); + + // Code to start datepicker for each date input + if($("#likelyDateInput").length > 0) { + $("#likelyDateInput").datepicker({ + dateFormat: "mm/dd/yy", + minDate: -1, + maxDate: 365 + }); + } + + // Checkout action + $('#GLMcheckoutBtn').click(function() { + setBlocker(); + window.location = "{baseSCRIPT}&Action=Shop_checkout"; + }); + + function setBlocker() { + $('#glmReloadBlocker').show(); + } + + $('#GLMnavSelectEvent').on('click', function() { // Return to Event Selection + setBlocker(); + window.location = '{startURL:h}'; + }); + +/* Not using right now + // Reprint order button + $('#reprintVoucher').on('keypress', function(event) { + if(event.which == '13'){ + var orderID = $(this).val(); + var voucherWindow = window.open('{appAdminURL}&Action=Order_printVoucher&OrderID=' + orderID, + "voucherPrint", + "height=750,width=600,menubar=yes,toolbar=yes,alwaysRaised=yes,menu" + ); + voucherWindow.focus(); + voucherWindow.print(); + return false; + } + }); +*/ + + if ({vertScroll}) { + window.scrollTo(0,{vertScroll}); + } + + }); + + + diff --git a/views/front/PointerBoat/Shop/checkout.html b/views/front/PointerBoat/Shop/checkout.html new file mode 100755 index 0000000..91673e2 --- /dev/null +++ b/views/front/PointerBoat/Shop/checkout.html @@ -0,0 +1,939 @@ + + + + +
    + +
    +
    Selected {term.ticket.plur_cap}
    + +
    + {term.nav.show_selected} + {if:!option.ticket_selection.start_at_cart} + {term.nav.select_more} + {end:} +
    +
    + +
    {checkoutText:h}
    + {if:reason} +
    +
    We're sorry, we had a problem with your request:
    +
      + {foreach:reason,r} +
    • {r:h}
    • + {end:} +
    +

    See below for more information.

    +
    + {end:} +
    + + +
    +
    Contact Information
    + +
    +
    +
    {text.cart.checkout.first_name}:
    +
    {text.cart.checkout.first_name}:
    + {if:formData.contact.fname.problem} +
    +
    {formData.contact.fname.problem}
    + {else:} +
    + {end:} + +
    +
    +
    +
    {text.cart.checkout.last_name}:
    +
    {text.cart.checkout.last_name}:
    + {if:formData.contact.lname.problem} +
    +
    {formData.contact.lname.problem}
    + {else:} +
    + {end:} + +
    +
    +
    +
    {text.cart.checkout.address}:
    +
    {text.cart.checkout.address}:
    + {if:formData.contact.addr1.problem} +
    +
    {formData.contact.addr1.problem}
    + {else:} +
    + {end:} + +
    +
    +
    +
     
    +
     
    + {if:formData.contact.addr2.problem} +
    +
    {formData.contact.addr2.problem}
    + {else:} +
    + {end:} + +
    +
    +
    +
    {text.cart.checkout.city}:
    +
    {text.cart.checkout.city}:
    + {if:formData.contact.city.problem} +
    +
    {formData.contact.city.problem}
    + {else:} +
    + {end:} + +
    +
    +
    +
    {text.cart.checkout.state}:
    +
    {text.cart.checkout.state}:
    + {if:formData.contact.state.problem} +
    +
    {formData.contact.state.problem}
    + {else:} +
    + {end:} + +
    +
    +
    +
    {text.cart.checkout.country}:
    +
    {text.cart.checkout.country}:
    + {if:formData.contact.country.problem} +
    +
    {formData.contact.country.problem}
    + {else:} +
    + {end:} + +
    +
    +
    +
    {text.cart.checkout.zip}:
    +
    {text.cart.checkout.zip}:
    + {if:formData.contact.zip.problem} +
    +
    {formData.contact.zip.problem}
    + {else:} +
    + {end:} + +
    +
    +
    +
    {text.cart.checkout.phone}:
    +
    {text.cart.checkout.phone}:
    + {if:formData.contact.phone.problem} +
    +
    {formData.contact.phone.problem}
    + {else:} +
    + {end:} + +
    +
    +
    +
    {text.cart.checkout.email}:
    +
    {text.cart.checkout.email}:
    + {if:formData.contact.email.problem} +
    +
    {formData.contact.email.problem}
    + {else:} +
    + {end:} + +
    +
    +
    +
    {text.cart.checkout.email_again}:
    +
    {text.cart.checkout.email_again}:
    + {if:formData.contact.email2.problem} +
    +
    {formData.contact.email2.problem}
    + {else:} +
    + {end:} + +
    +
    +
    +
    Receive E-Newsletter?
    + {if:formData.contact.email_ok} +
    + {else:} +
    + {end:} + Please sign me up to receive Stafford's Hospitality e-newsletter. +
    +
    + + {if:opt_field_1_name} +
    +
    {opt_field_1_name}:
    +
    {opt_field_1_name}:
    + {if:formData.contact.opt_field_1.problem} +
    +
    {formData.contact.opt_field_1.problem}
    + {else:} +
    + {end:} + +
    +
    + {end:} + {if:opt_field_2_name} +
    +
    {opt_field_2_name}:
    +
    {opt_field_2_name}:
    + {if:formData.contact.opt_field_2.problem} +
    +
    {formData.contact.opt_field_2.problem}
    + {else:} +
    + {end:} + +
    +
    + {end:} + {if:opt_field_3_name} +
    +
    {opt_field_3_name}:
    +
    {opt_field_3_name}:
    + {if:formData.contact.opt_field_3.problem} +
    +
    {formData.contact.opt_field_3.problem}
    + {else:} +
    + {end:} + +
    +
    + {end:} + + +
    +
    + + {foreach:cart,c} + {if:c.performances} +
    +
    {term.prop.cap}: {c.name:h}
    + + +
    + + {foreach:c.performances,p} +
    +
    +
    +
    +
    {p.name}
    +
    + + {if:option.cart_images}{if:option.cart_images}{if:p.image}{end:}{end:}{end:} +
    +
    +
    +
    + {foreach:p.dates,d} +
    +
    + + {if:d.dateSpecific} + {d.fullDate} + {else:} + + {if:c.likelyDate} + - Likely Date {c.likelyDate} + {end:} + {end:} + +
    + + + {foreach:d.sections,s} + + + + {if:!p.oneSectionOnly} + + {end:} + + + + + {foreach:s.tickets,i} + + + {if:!p.oneSectionOnly} + + {end:} + + + + + {if:i.descr} + + + {if:!p.oneSectionOnly} + + + {end:} + + {foreach:i.addons,a} + {if:a.selected} + + + {if:!p.oneSectionOnly} + + {end:} + + + + + {end:} + {end:} + + {if:i.promo} + + + {if:!p.oneSectionOnly} + + {end:} + + + + {end:} + {end:} +
    QuantSection{term.ticket.cap}PriceTotal
    + {i.selected} + {s.name} + {i.title} + {if:d.dateSpecific} + - {d.fullDate} + {end:} + {if:i.time_specific.value} + + {else:} + + {end:} + {if:i.show_price}{i.price}{end:}{if:i.show_price}{i.extended}{end:}
      + {else:} + + {end:} + {if:option.cart_images} + {if:i.image} +
    + {end:} + {end:} +
    {i.descr:h}
    +
       +
    + {a.selected} {a.unit_name} +
    +
    {a.unit_cost}/{a.unit_name}{a.money}
      {term.promo.cap}: {promoCode}  + {i.promo.credit}
    + {end:} +
    + {end:} +
    +
    + {if:p.policy} +
    +
    + Please read and agree to our policy for this {term.performance.norm}. +
    +
    +

    {p.policy:h}

    +
    +
    + {if:adminUser} + +

    (Agree to policy not required for admin users)

    + {else:} +

    I agree to the policy stated above.

    + {end:} +
    +
    + {end:} +
    + {end:} +
    + + {if:c.ticket_policy}
    {c.ticket_policy:h}
    {end:} + {if:c.ticket_policy}
    {c.ticket_policy:h}
    {end:} + +
    + + {if:c.ticket_spec_req.value} +
    +
    Please enter any special requests:
    +
    +
    + {end:} + + + {if:!formData.centralPayment} +
    + + {if:c.paymentResult} + {if:c.paymentResult.approved} +
    Card Payment Approved
    +
    Card Type
    {c.paymentResult.cctype}
    +
    Name on Card
    {c.paymentResult.ccname}
    +
    Card Number
    {c.paymentResult.ccnumb}
    +
    Expiration Date
    {c.paymentResult.ccexp}
    +
    Authorization Code
    {c.paymentResult.authCode}
    + + {else:} +
    Card Payment Not Complete
    +
    • {c.paymentResult.description}
    +

    Please check the payment information below and try again or contact your credit card company for assistance.

    + {if:forceCheckoutPhase} +
    +
    {term.nav.delete_from_cart}
    +
    + {end:} + {end:} + {end:} + {if:c.paymentResult.approved} +

    Payment Accepted

    + {else:} + {if:c.havePaymentMethod} + +
    + {if:c.havePayPal} + {if:c.haveMultiplePaymentMethods} +  PayPal + {else:} + + {end:} + {end:} + {if:c.haveCreditCards} + {if:c.havePayPal} +      + {end:} + {if:c.haveMultiplePaymentMethods} +  Credit Card + {else:} + + {end:} + {end:} +
    + + {if:c.haveCreditCards} + {if:c.haveMultiplePaymentMethods} + + {else:} + + {end:} +
    +
    Total Charged to this Card
    +
    {c.totalPrice}
    +
    +
    +
    Card Type
    +
    Card Type
    + {if:c.paymentForm.cctype.problem} +
    +
    {c.paymentForm.cctype.problem}
    + {else:} +
    + {end:} + +
    +
    +
    +
    Name on Card
    +
    Name on Card
    + {if:c.paymentForm.ccname.problem} +
    +
    {c.paymentForm.ccname.problem}
    + {else:} +
    + {end:} + +
    +
    +
    +
    Card Number
    +
    Card Number
    + {if:c.paymentForm.ccnumb.problem} +
    +
    {c.paymentForm.ccnumb.problem}
    + {else:} +
    + {end:} + +
    +
    +
    +
    Expiration Date
    +
    Expiration Date
    + {if:c.paymentForm.ccexp.problem} +
    +
    {c.paymentForm.ccexp.problem}
    + {else:} +
    + {end:} + Month + + Year + +
    +
    +
    +
    Security Code
    +
    Security Code
    + {if:c.paymentForm.cccode.problem} +
    +
    {c.paymentForm.cccode.problem}
    + {else:} +
    + {end:} + +
    +
    +
    +
    + The Security Code is the three or four digit number on the signature side of your credit card. +
    +
    + + {end:} + {if:c.havePayPal} + + {if:c.haveMultiplePaymentMethods} + + {else:} + + {end:} +
    + +
    +
    + {end:} + {if:c.haveMultiplePaymentMethods} + +
    Please select a Payment Method
    +
    + {end:} + {else:} + +
    + This {term.prop.norm} does not have a payment method configured. + Please call this {term.prop.norm} to purchase {term.ticket.plur}. +
    +
    + {end:} + {end:} + +
    +
    + + {end:} +
    +
    + {end:} + + {if:!cartRequiresPayment} + + {end:} + + {end:} + +{if:cartRequiresPayment} + {if:formData.centralPayment} + +
    + + {if:formData.centralPayment.havePaymentMethod} + + {foreach:formData.centralPayment.paymentForm,p} + + {if:p.cctype} + + + +
    +
    + {if:formData.centralPayment.haveMultiplePaymentMethods} +  Credit Card + {else:} + + {end:} +
    +
    +
    +
    Card Type
    +
    Card Type
    +
    + +
    +
    +
    +
    Name on Card
    +
    Name on Card
    + {if:p.ccname.problem} +
    +
    {p.ccname.problem}
    + {else:} +
    + {end:} + +
    +
    +
    +
    Card Number
    +
    Card Number
    + {if:p.ccnumb.problem} +
    +
    {p.ccnumb.problem}
    + {else:} +
    + {end:} + +
    +
    +
    +
    Expiration Date
    +
    Expiration Date
    + {if:p.ccexp.problem} +
    +
    {p.ccexp.problem}
    + {else:} +
    + {end:} + Month + + Year + +
    +
    +
    +
    Security Code
    +
    Security Code
    + {if:p.cccode.problem} +
    +
    {p.cccode.problem}
    + {else:} +
    + {end:} + +
    +
    +
    +
    + The Security Code is the three or four digit number on the signature side of your credit card. +
    +
    + + {if:p.haveMultiplePaymentMethods} + +
    Please select a Payment Method
    +
    + {end:} + + {end:} + {end:} + +
    + + {else:} + +
    + This {term.prop.norm} does not have a payment method configured. + Please call this {term.prop.norm} to purchase {term.ticket.plur}. +
    +
    + + {end:} + + {end:} + +{end:} + + + +
    + {if:cartRequiresPayment} +
    +
    Complete Purchase
    + +

    + {ssl_seal_head_script:h} + {ssl_seal_body_script:h} +

    +
    + {else:} +
    +
    No Payment Required
    +
    + {end:} +
    +
    + {if:cartRequiresPayment} + +
    +
    + Grand Total   {totals.price} +
    + + + + + + + +
    + {end:} +
    + {if:!cartHasOneVenueOnly} + + {end:} + + {if:adminUser} +
    + No payment info required for Admin User. +
    + {if:noPaymentReasons} +
    + Reason for no payment information required:
    + +
    + {end:} + {end:} + +
    + {if:!blockCheckout} + {term.nav.purchase} + {else:} + Unable to checkout - please see above. + {end:} +
    +
    +
    + +
    + + + + + + diff --git a/views/front/PointerBoat/Shop/checkoutSuccess.html b/views/front/PointerBoat/Shop/checkoutSuccess.html new file mode 100755 index 0000000..8c98e73 --- /dev/null +++ b/views/front/PointerBoat/Shop/checkoutSuccess.html @@ -0,0 +1,378 @@ + + + + + +
    + + +
    Purchase Complete
    + + + + + + + + +
    + +
    + +

    + Please print this page for reference. + +

    + ORDER #: + {foreach:cart,c} + {if:c.paymentResult} + {if:c.paymentResult.approved} + {c.paymentResult.orderID}  + {end:} + {end:} + {end:} +
    +
    +
    + + +
    {successText:h}
    + +
    +
    Contact Information
    +
    +
    First Name:
    {formData.contact.fname.value}
    +
    Last Name:
    {formData.contact.lname.value}
    +
    Address:
    {formData.contact.addr1.value}
    +
     
    {formData.contact.addr2.value}
    +
    City:
    {formData.contact.city.value}
    +
    State:
    {formData.contact.state.value}
    +
    Country:
    {formData.contact.country.value}
    +
    ZIP/Postal Code:
    {formData.contact.zip.value}
    +
    Phone:
    {formData.contact.phone.value}
    +
    E-Mail address:
    {formData.contact.email.value}
    + {if:opt_field_1_name}
    {opt_field_1_name}:
    {formData.contact.opt_field_1.value:h}
    {end:} + {if:opt_field_2_name}
    {opt_field_2_name}:
    {formData.contact.opt_field_2.value:h}
    {end:} + {if:opt_field_3_name}
    {opt_field_3_name}:
    {formData.contact.opt_field_3.value:h}
    {end:} +
     
    + {if:formData.contact.email_ok} + You have asked us to send information on activities and offers. + {else:} + You have asked us to NOT send information on activities and offers.
    + We will only contact you regarding this order. + {end:} +
    + +
    + +
    + + + {foreach:cart,c} +
    + +
    {term.ticket.plur_cap} at: {c.name:h}
    + + +
    + {if:c.descr}
    {c.descr:h}
    {end:} + {if:option.cart_images}{if:c.image}{end:}{end:} + +
    + +
    + + {foreach:c.performances,p} + +
    + +
    +
    +
    + {term.performance.cap}: {p.name:h} +
    +
    + + {if:option.cart_images}{if:option.cart_images}{if:p.image}{end:}{end:}{end:} +
    +
    +
    + +
    + {foreach:p.dates,d} + +
    + {term.ticket.cap} date: + + {if:d.dateSpecific} + {d.fullDate} + {else:} + Use any date + {if:c.likelyDate} + - Likely Date {c.likelyDate} + {end:} + {end:} + +
    + + + {foreach:d.sections,s} + + + + {if:!p.oneSectionOnly} + + {end:} + + + + + {foreach:s.tickets,i} + + + {if:!p.oneSectionOnly} + + {end:} + + + + + {if:i.descr} + + + {if:!p.oneSectionOnly} + + + {end:} + + {foreach:i.addons,a} + + + {if:!p.oneSectionOnly} + + {end:} + + + + + {end:} + + {if:i.promo} + + + {if:!p.oneSectionOnly} + + {end:} + + + + {end:} + {end:} +
    QuantSection{term.ticket.cap}PriceTotal
    + {i.selected} + {s.name:h} + {i.title} + + {if:i.date_specific.value} + - {i.start_date.date} + {if:i.time_specific.value} + {i.ticket_time.time} + {end:} + {else:} + {if:i.time_specific.value} + - {i.ticket_time.time} + {end:} + {end:} + {if:i.show_price}{i.price}{end:}{if:i.show_price}{i.extended}{end:}
      + {else:} + + {end:} + {if:option.cart_images} + {if:i.image} +
    + {end:} + {end:} +
    {i.descr:h}
    +
       +
    + {a.selected} {a.unit_name} +
    +
    {a.unit_cost}/{a.unit_name}{a.money}
      {term.promo.cap}: {promoCode}  + {i.promo.credit}
    + {end:} + + + {end:} + +
    + +
    + + {if:p.policy} +
    +
    +
    + Our policy for this {term.performance.norm}. +
    +

    {p.policy:h}

    +
    +
    + {end:} + + {end:} + +
    + + + + {if:!cartHasOneVenueOnly} + +
    +
    +
    +
    Sub Total
    +
    +
    +
    {c.totalPrice}
    +
    +
    +
    + {end:} + + {if:c.ticket_policy}
    {c.ticket_policy:h}
    {end:} + + + {if:c.ticket_policy}
    {c.ticket_policy:h}
    {end:} + + +
    + + + {if:c.ticket_spec_req.value} +
    +
    Special requests:
    +
    {c.paymentForm.spec_req.value:h}
    +
    + {end:} + + + {if:c.paymentResult} +
    + {if:c.paymentResult.approved} +
    Card Payment Approved
    + +
    Card Type
    {c.paymentResult.cctype}
    +
    Name on Card
    {c.paymentResult.ccname}
    +
    Card Number
    {c.paymentResult.ccnumb}
    +
    Expiration Date
    {c.paymentResult.ccexp}
    +
    Authorization Code
    {c.paymentResult.authCode}
    + + {else:} +
    Card Payment Not Complete
    +
    • {c.paymentResult.description}
    +

    Please check the payment information below and try again or contact your credit card company for assistance.

    + {if:forceCheckoutPhase} +
    +
    {term.nav.delete_from_cart}
    +
    + {end:} + + {end:} + +
    + {end:} + +
    + +
    + + {end:} + +
    + {if:cartHasContents} +
    +
    Cart Totals
    +
    +
    +
    Grand Total
    +
    +
    +
    {totals.price}
    +
    +
    +
    + {else:} +

    Your cart is currently empty.

    + {end:} +
    + +
    + +{trackingScript:h} + + + + + diff --git a/views/front/PointerBoat/Shop/paymentSummary.html b/views/front/PointerBoat/Shop/paymentSummary.html new file mode 100755 index 0000000..9b03e13 --- /dev/null +++ b/views/front/PointerBoat/Shop/paymentSummary.html @@ -0,0 +1,135 @@ + + +

    + + {cartEntry.name:h} +

    + + + + + + + + + + + + + + +{foreach:cartForSummaryCentral,c} +{foreach:c.performances,p} + {foreach:p.dates,d} + {foreach:d.sections,s} + + + {foreach:s.tickets,i} + + + + + + + + {foreach:i.addons,a} + {if:a.selected} + + + + + + + + {end:} + {end:} + {if:i.promo} + + + + + + + {end:} + {end:} + + + {end:} + {end:} +{end:} + + + + + + + + +
    Quant{term.performance.cap}{term.ticket.cap}PriceTotal
    {i.selected}{p.name:h} + {i.title:h} + {if:d.dateSpecific} + - {d.fullDate} + {if:i.time_specific.value} + at {i.ticket_time.time} + {end:} + {else:} + {if:i.time_specific.value} + - {i.ticket_time.time} + {end:} + {end:} + + {if:i.show_price}{i.price}{end:}{if:i.show_price}{i.extended}{end:}
       +
    + {a.selected} {a.unit_name} +
    +
    {a.unit_cost}/{a.unit_name}{a.money}
      {term.promo.cap}: {promoCode}  + {i.promo.credit}
     {c.totalPrice}
    + + +{if:c.ticket_spec_req} +

    + {c.paymentForm.spec_req.value:h} +

    +{end:} + +{end:} + +{if:cartEntry.ticket_policy}

    {cartEntry.ticket_policy:h}

    {end:} + + + + + + + + + + + + +
    First Name:{formData.contact.fname.value}
    Last Name:{formData.contact.lname.value}
    Address:{formData.contact.addr1.value}
     {formData.contact.addr2.value}
    City:{formData.contact.city.value}
    State:{formData.contact.state.value}
    Country:{formData.contact.country.value}
    ZIP/Postal Code:{formData.contact.zip.value}
    Phone:{formData.contact.phone.value}
    E-Mail address:{formData.contact.email.value}
    + +

    + + + + + + + +
    Credit Card Payment Approved
    Card Type{cartEntry.paymentResult.cctype}
    Name on Card{cartEntry.paymentResult.ccname}
    Card Number{cartEntry.paymentResult.ccnumb}
    Expiration Date{cartEntry.paymentResult.ccexp}
    Authorization Code{cartEntry.paymentResult.authCode}
    +

    + + diff --git a/views/front/PointerBoat/Shop/sectionSelect.html b/views/front/PointerBoat/Shop/sectionSelect.html new file mode 100755 index 0000000..db08efa --- /dev/null +++ b/views/front/PointerBoat/Shop/sectionSelect.html @@ -0,0 +1,96 @@ + + + + + + +
    + + +
    {term.section.cap} Selection
    + + + + + +
    {sectionText:h}
    + +{if:reason} +
    +
    We're sorry, we had a problem with your request:
    +
      + {foreach:reason,r} +
    • {r:h}
    • + {end:} +
    +
    +{end:} + +

    You have selected

    +
    +
    +
    +
    {performanceDetail.member_name}

    +
    {performanceDetail.name}
    +
    +
    + + +
    +
    +
    + + +
    +

    Please select from the following

    +
    +{foreach:sectionList,x} +
    + +
    +

    {term.section.cap}: {x.member_name}

    +

    {x.descr:h}

    +
    +
    +{end:} + +
    + +
    + + {startScript:h} + + $(document).ready(function(){ + + // Code to kick off the geolocation-display feature + $("#locationMap").geolocate({ + lat: "#lat", + lng: "#lon", + mapOptions: { + disableDefaultUI: false, + mapTypeControl: true, + mapTypeId: "roadmap", + zoom: 12 + }, + markerOptions: { + draggable: false, + title: "This is your selected location" + } + }); + + }); + + + diff --git a/views/front/PointerBoat/Shop/start-COPY.html b/views/front/PointerBoat/Shop/start-COPY.html new file mode 100644 index 0000000..feda2b4 --- /dev/null +++ b/views/front/PointerBoat/Shop/start-COPY.html @@ -0,0 +1,162 @@ + + +
    +
    +
    +
    +
    {m.name}
    +
    +
    +
    Address: {m.addr1}{if:m.addr2}, {m.addr2}{end:}, {m.city}
    +
    Phone #: {m.phone}
    +
    {m.descr:h}
    +
    +
    +
    +
    (map loads here)
    +
    + + +
    +
    + +
    + {foreach:m.performances,p} +
    +
    +
    +
    + {if:showTickets} + {p.name} + {else:} + {p.name} + {end:} +
    +
    +
    +
    {term.prop.cap}: {p.member_name}
    +
    Dates: {p.start_date.date} through {p.end_date.date}
    +
    +
    + {if:!showTickets} + {term.nav.select} + {end:} + + + {foreach:p.sections,s} +

     

    +
    +
    +
    + {if:!p.oneSectionOnly} + {s.sectionDetail.name}
    + {end:} + +
    + +
    +
    + + + {foreach:s.ticketsData,x} +
    + {if:option.ticket_selection.include_options_in_ticket_list} +
    +
    +
    Price: 
    +
    +
    {x.price}
    +
    +
    +
    +
    Select date: 
    +
    +
    + + +
    +
    +
    +
    +
    Quant: 
    +
    +
    (select date)
    +
    +
    +
    + + {end:} + +
    + {if:option.ticket_selection.include_options_in_ticket_list} +
    {x.title}
    + {else:} +
    + {x.name} +
    + {term.nav.select} + {end:} +
    +
    + {if:x.descr} +

    {x.descr:h}

    + {end:} +
    + {if:!x.date_specific.value} + Use any date{if:x.start_date.timestamp} from {x.start_date.date} to {x.end_date.date}{end:}{if:!x.time_specific.value}, {end:} + {end:} + {if:!x.time_specific.value} + Use any time of day, + {else:} + Time: {x.ticket_time.time}, + {end:} + {if:x.unlimted_use.value} + Each {term.ticket.norm} may be used an unlimited number of times + {else:} + + {end:} +
    +
    +
    + {if:option.ticket_selection.include_options_in_ticket_list} +
    +
    +
    Price each: 
    +
    +
    {x.price}
    +
    +
    +
    +
    Select date: 
    +
    +
    + + +
    +
    +
    +
    +
    Quant: 
    +
    +
    (select date)
    +
    +
    +
    + + {end:} +
    + + + {end:} + +
    + + {end:} + + + +
    + {end:} +
    +
    + {end:} diff --git a/views/front/PointerBoat/Shop/start.html b/views/front/PointerBoat/Shop/start.html new file mode 100755 index 0000000..112e49f --- /dev/null +++ b/views/front/PointerBoat/Shop/start.html @@ -0,0 +1,387 @@ + + + +
    + +
    +
    {term.event.cap} Selection
    + + +
    + +
    {introText:h}
    + {if:reason} +
    +
    We're sorry, we had a problem with your request:
    +
      + {foreach:reason,r} +
    • {r:h}
    • + {end:} +
    +
    + {end:} + +{if:showTickets} + +
    + + + + +{end:} + + {foreach:membersList,m} +
    +
    +
    + +
    + +
    {m.descr:h}
    +
    +
    + {if:option.select_images} + {if:m.image} +
    + {end:} + {end:} + +
    + {foreach:m.performances,p} +
    + {if:option.select_images} + {if:p.image} +
    + {else:} +
    + {end:} + {else:} +
    + {end:} +
    +
    + {if:showTickets} + {m.name:h} - {p.name} + {else:} + {p.name} + {end:} +
    +
    +
    + +
    {p.short_descr:h}
    + {if:p.start_date.timestamp}
    Event Available: {p.start_date.date}{if:p.end_date.timestamp}  -  {p.end_date.date} {end:}
    {end:} +
    +
    + {if:option.select_images} + {if:p.image} +
    + {end:} + {end:} + {if:!showTickets} + + {end:} + + + + {foreach:p.sections,s} +

     

    +
    +
    +
    + {if:!p.oneSectionOnly} + {s.sectionDetail.name}
    + {end:} + +
    + +
    +
    + + + {foreach:s.ticketsData,x} + {if:!x.tooLateToBuy} +
    + {if:option.ticket_selection.include_options_in_ticket_list} +
    +
    +
    Price: 
    +
    +
    {x.price}
    +
    +
    +
    +
    Select date: 
    +
    +
    + + +
    +
    +
    +
    +
    Quant: 
    +
    +
    (select date)
    +
    +
    +
    + {end:} +
    + {if:option.ticket_selection.include_options_in_ticket_list} +
    {x.title}
    + {else:} +
    + {x.name} +
    + {end:} +
    + {if:x.descr} +
    +
    + {if:x.descr} +

    {x.descr:h}

    + {end:} +

    + {if:!x.date_specific.value} + {if:x.start_date.timestamp} Date: {x.start_date.date}{end:}{if:!x.start_end_dates_same} to {x.end_date.date}{end:}{if:!x.time_specific.value} {end:} + {end:} + {if:!x.time_specific.value} + + {elif false:} + + Time: {x.ticket_time.time} + {end:} + {if:x.unlimted_use.value} + Each {term.ticket.norm} may be used an unlimited number of times + {else:} + + {end:} +

    +
    +
    + +
    +
    + {end:} +
    + {end:} + {end:} +
    + + {end:} + + + +
    + {end:} +
    +
    + {end:} +{if:showTickets} + + +{end:} +
    + +{startScript:h} + + var addButtonPushed = false; + + // Dates for inventory data + var tickets = {ticketsJSON:h}; + + var ticketQuantSelection = '\ + \ + '; + + var ticketTooLate = '\ +

    \ + Sorry, too late to select these {term.ticket.plur} on-line.\ +

    \ + '; + + + + $(document).ready(function(){ + + // Code to kick off the geolocation-display feature + function doLocationMap(id) { + $("#locationMap_" + id).geolocate({ + lat: "#lat_" + id, + lng: "#lon_" + id, + mapOptions: { + disableDefaultUI: false, + mapTypeControl: true, + mapTypeId: "roadmap", + zoom: 12 + }, + markerOptions: { + draggable: false, + title: "This is your selected location" + } + }); + } + {foreach:membersList,m} + doLocationMap({m.id}); + {end:} + + // DatePicker action + function avail(date) { + m = (date.getMonth()+1); + if (m < 10) { + m = '0' + m; + } + d = date.getDate(); + if (d < 10) { + d = '0' + d; + } + y = date.getFullYear(); + mdy = m + '/' + d + '/' + y; + if (dates[mdy]) { + return [true,"","Available"]; + } else { + return [false,"","Not Available"]; + } + } + + // for each ticket + $.each(tickets, function(index, ticket) { + + var inventory = ticket.inventory; + + // Build date data array and count dates for this ticket + var dateCount = 0; + var dateData = false + $.each(inventory, function(index, date) { + + // Count the number of dates + dateCount++; + + // If this is the first one, store it in case it's the only one + dateData = date; + + }); // each date + + // if there's no date specific tickets + if (!ticket.dateSpecific) { + + // Populate date input field + $('#GLMeventDateSelect_' + ticket.id).html(''); + doQuantSelection(ticket.id, dateData.id, dateData.available, dateData.tooLate); + + // if there's only one date, then display that and move on. + } else if (!ticket.dateSpecific || dateCount == 1) { + + // populate date input field + $('#GLMeventDate_' + ticket.id).html('
    Date:
    ' + dateData['date'] + '
    '); + doQuantSelection(ticket.id, dateData.id, dateData.available, dateData.tooLate); + + } else { + + // DatePicker action + function avail(date) { + m = (date.getMonth()+1); + if (m < 10) { + m = '0' + m; + } + d = date.getDate(); + if (d < 10) { + d = '0' + d; + } + y = date.getFullYear(); + mdy = m + '/' + d + '/' + y; + if (inventory[mdy]) { + return [true,"","Available"]; + } else { + return [false,"","Not Available"]; + } + } + + // Use the date picker to select a date + $('#GLMeventDateInput_' + ticket.id).datepicker({ + beforeShowDay: avail, + dateFormat: "mm/dd/yy", +// *** NEED TO FIX REFERENCE TO "performanceDetail" since that's not available on this page + minDate: "{performanceDetail.start_date.date}", + maxDate: "{performanceDetail.end_date.date}", + onSelect: function(selectedDate, inst) { + // Get data for the selected date + dateData = inventory[selectedDate]; + $('#GLMeventInvID_' + ticket.id).val(dateData.id); + doQuantSelection(ticket.id, dateData.id, dateData.available, dateData.tooLate); + } // Date Selection + + }); // Date Picker + + + } + + }); // each ticket + + function doQuantSelection(id, invId, available, tooLate) { + + // Build the ticket quant options + var ticketQuants = ''; + var selectMax = available; + if (selectMax > 50) { + selectMax = 50; + } + + if (tooLate) { + $('#GLMticketQuantContainer_' + id).html(ticketTooLate); + } else { + + // note that the braced lte below is needed to inject a less-than-or-equal-to operator without having flexy chew on it. + for (var i = 1; i {lte:h} (selectMax*1); i++) { + ticketQuants = ticketQuants.concat(''); + } + + // Populate the ticket quantity container + tmpQuantSel = ticketQuantSelection.replace(/\[id\]/g, id); + $('#GLMticketQuantContainer_' + id).html(tmpQuantSel.replace(/\[ticket-quants\]/g, ticketQuants)); + + } + + } + + $('.GLMselectButton').click(function() { + + // Check for a selected ticket + var ticketSelected = false; + $('.glmTicketQuant').each(function( index ) { + if ($(this).val() != '') { + ticketSelected = true; + } + }); + + if (ticketSelected) { + selectButtonPressed = true; + setBlocker(); + $('#GLMselectForm').submit(); + } else { + alert('Please select a {term.ticket.norm} quantity.') + return false; + } + + }); + + function setBlocker() { + $('#glmReloadBlocker').show(); + } + + }); + + + diff --git a/views/front/PointerBoat/Shop/svn-commit.tmp b/views/front/PointerBoat/Shop/svn-commit.tmp new file mode 100644 index 0000000..8c664dd --- /dev/null +++ b/views/front/PointerBoat/Shop/svn-commit.tmp @@ -0,0 +1,4 @@ +Anthony changes for "use any date" or whatever +--This line, and those below, will be ignored-- + +M checkout.html diff --git a/views/front/PointerBoat/Shop/ticketOpt.html b/views/front/PointerBoat/Shop/ticketOpt.html new file mode 100755 index 0000000..1564c62 --- /dev/null +++ b/views/front/PointerBoat/Shop/ticketOpt.html @@ -0,0 +1,273 @@ + + + + + +
    + +
    +
    Ticket Selection
    + + +
    + +
    {ticketOptText:h}
    + {if:reason} +
    +
    We're sorry, we had a problem with your request:
    +
      + {foreach:reason,r} +
    • {r:h}
    • + {end:} +
    +
    + {end:} +

    You have selected

    + +
    +
    +
    +
    {performanceDetail.name}
    +
    +
    +
    {term.prop.cap}: {performanceDetail.member_name}
    + + +
    +
    +
    +
    +
    {sectionDetail.name}
    +
    +
    + +
    +
    +
    +
    +
    {ticketDetail.name}
    +
    +
    + {if:!ticketDetail.date_specific.value} +
    Use any date {if:ticketDetail.start_date.timestamp} from {ticketDetail.start_date.date} to {ticketDetail.end_date.date}{end:}
    + {end:} + {if:!ticketDetail.time_specific.value} +
    Use any time
    + {else:} +
    Time: {ticketDetail.ticket_time.time}
    + {end:} + {if:!ticketDetail.unlimted_use.value} + + {else:} +
    Each {term.ticket.norm} may be used an unlimited number of times
    + {end:} +
    {ticketDetail.descr:h}
    +
    +
    +
    + +

    Please select from the following.

    +
    +
    +
    +
    +
    +
    +
    +
    Select desired date:
    +
    +
    (click in field to set date)
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    Select Quantity:
    +
    +
    (please select date first)
    +
    +
    +
    +
    + {if:reason}
    (disabled - please see above)
    {else:}
    {term.nav.add_to_cart}
    {end:} +
    + +{startScript:h} + + // Whether ticket has date specific inventory + var dateSpecific = {ticketDetail.date_specific.value} + 0; + + // Dates for inventory data + var dates = {inventoryJSON:h}; + + $(document).ready(function(){ + + // DatePicker action + function avail(date) { + m = (date.getMonth()+1); + if (m < 10) { + m = '0' + m; + } + d = date.getDate(); + if (d < 10) { + d = '0' + d; + } + y = date.getFullYear(); + mdy = m + '/' + d + '/' + y; + if (dates[mdy]) { + return [true,"","Available"]; + } else { + return [false,"","Not Available"]; + } + } + var dateData = false; + + var ticketQuantSelection = '\ + \ + '; + var ticketTooLate = '\ +

    \ + Sorry, too late to select these {term.ticket.plur} on-line.\ + {term.ticket.plur_cap} must be purchased at least {detail.performance.purch_leadtime} hours prior to the {term.performance.norm}.\ + Please select another date or time.\ +

    \ + '; + var selectedInv; + var ticketQuants; + var addButtonPushed = false; + + // Start by counting the number of dates to see if we have only 1 + var dateCount = 0; +// if (dateSpecific) { + $.each(dates, function(index, date) { + dateCount = dateCount + 1; + dateData = date; + }); +// } + // if there's no date specific tickets + if (!dateSpecific) { + // Populate date input field + $('#GLMeventDateSelectBlock').html(''); + doQuantSelection(); + // if there's only one date, then display that and move on. + } else if (!dateSpecific || dateCount == 1) { + // populate date input field + $('#GLMeventDate').val(dateData['date']); + $('#GLMtickets').html('
    Date:
    ' + dateData['date'] + '
    '); + + doQuantSelection(); + } else { + // Use the date picker to select a date + dateData = false; + $("#GLMeventDate").datepicker({ + beforeShowDay: avail, + dateFormat: "mm/dd/yy", + minDate: "{performanceDetail.start_date.date}", + maxDate: "{performanceDetail.end_date.date}", + onSelect: function(selectedDate, inst) { + // Update input message + $('#GLMdateMessage').html('
    '); + + // Get data for the selected date + dateData = dates[selectedDate]; + doQuantSelection(); + } // Date Selection + + }); // Date Picker + + } + + function doQuantSelection() { + // Build the ticket quant options + ticketQuants = ''; + var selectMax = dateData['available']; + if (selectMax > 50) { + selectMax = 50; + } + var tooLate = dateData['tooLate']; + if (tooLate) { + $('#GLMticketQuantContainer').html(ticketTooLate); + } else { + // note that the braced lte below is needed to inject a less-than-or-equal-to operator without having flexy chew on it. + for (var i = 1; i {lte:h} (selectMax*1); i++) { + ticketQuants = ticketQuants.concat(''); + } + + // Populate the ticket quantity container + $('#GLMticketQuantContainer').html(ticketQuantSelection.replace(/\[ticket-quants\]/g, ticketQuants)); + } +// doAddToCartSetup(); + } + +// function doAddToCartSetup() { + // Add to cart action + $('#GLMaddToCart').click(function() { + if (addButtonPushed) { + return; + } + var reason = ''; + // Check date + if (dateData) { + selectedInv = dateData.id; + } else { + reason = reason.concat('* You need to select a date first.\n'); + } + // Check quantity + var selectedQuant = (parseInt($('#glmQuantSelector').val()) + 0); + if (selectedQuant == 0) { + reason = reason.concat('* You need to select a quantity first.\n'); + } + // Check if there's a reason we can't add this to the cart yet + if (reason != '') { + alert(reason); + return; + } + // Adding to cart + addButtonPushed = true; + $("#GLMeventDate").datepicker('disable'); + $('#glmQuantSelector').prop('disabled', 'disabled'); + setBlocker(); + // Submit to cart + window.location = "{baseSCRIPT}&Action=Shop_cart&cart=add&PerformanceID={performanceDetail.id}&SectionID={sectionDetail.id}&TicketID={ticketDetail.id}&ticket_inv=" + selectedInv + "&quant=" + selectedQuant; + + }); +// } + // Code to kick off the geolocation-display feature + $("#locationMap").geolocate({ + lat: "#lat", + lng: "#lon", + mapOptions: { + disableDefaultUI: false, + mapTypeControl: true, + mapTypeId: "roadmap", + zoom: 12 + }, + markerOptions: { + draggable: false, + title: "This is your selected location" + } + }); + // Navigation buttons + $('#GLMnavCart').click(function() { // Add to Cart + window.location = '{baseSCRIPT}&Action=Shop_cart'; + }); + $('#GLMnavSelectEvent').on('click', function() { // Return to Event Selection + window.location = '{startURL:h}'; + }); + + function setBlocker() { + $('#glmReloadBlocker').show(); + } + + }); + + diff --git a/views/front/PointerBoat/Shop/ticketSelect.html b/views/front/PointerBoat/Shop/ticketSelect.html new file mode 100755 index 0000000..b5f3930 --- /dev/null +++ b/views/front/PointerBoat/Shop/ticketSelect.html @@ -0,0 +1,327 @@ + + + +
    + +
    +
    {term.ticket.cap} Selection
    + +
    + {term.nav.show_selected} + {if:!option.ticket_selection.start_at_cart} + {term.nav.select_more} + {end:} +
    +
    + +
    {ticketText:h}
    +{if:reason} +
    +
    We're sorry, we had a problem with your request:
    +
      + {foreach:reason,r} +
    • {r:h}
    • + {end:} +
    +
    +{end:} +

    You have selected

    + + + +{foreach:sections,s} +
    +
    + + +
    + {if:performanceDetail.image} +
    +
    + {else:} +
    + {end:} + +
    +
    {performanceDetail.member_name:h}

    +
    {performanceDetail.name:h}
    +
    +
    +
    + {if:!oneSectionOnly} + {s.sectionDetail.name}
    + {end:} + +
    + + {if:performanceDetail.descr} + {performanceDetail.descr:h} + {end:} +
    +
    +
    +
    +
    + + +

    Please select from the following. If you do not see the number of tickets available that you require, please select a different date or time.

    +
    +
    + + + + + {foreach:s.ticketsData,x} + {if:!x.tooLateToBuy} +
    + {if:option.ticket_selection.include_options_in_ticket_list} +
    +
    +
    Price: 
    +
    +
    {x.price}
    +
    +
    +
    +
    Select date: 
    +
    +
    + + +
    +
    +
    +
    +
    Quant: 
    +
    +
    (select date)
    +
    +
    +
    + {end:} +
    + {if:option.ticket_selection.include_options_in_ticket_list} +
    {x.title:h}
    + {else:} +
    + {x.name} +
    + {end:} +
    +
    + {if:x.descr} +

    {x.descr:h}

    + {end:} +

    + {if:!x.date_specific.value} + {if:x.start_date.timestamp} Date: {x.start_date.date}{end:}{if:!x.start_end_dates_same} to {x.end_date.date}{end:}{if:!x.time_specific.value} {end:} + {end:} + {if:!x.time_specific.value} + + {elif false:} + + Time: {x.ticket_time.time} + {end:} + {if:x.unlimted_use.value} + Each {term.ticket.norm} may be used an unlimited number of times + {else:} + + {end:} +

    +
    +
    +
    +
    + {end:} + {end:} + +
    +
    + +{end:} + +
    + +{if:option.ticket_selection.include_options_in_ticket_list} + + {startScript:h} + + var addButtonPushed = false; + + // Dates for inventory data + var tickets = {ticketsJSON:h}; + + var ticketQuantSelection = '\ + \ + '; + + var ticketTooLate = '\ + Sorry, too late to select these {term.ticket.plur} on-line.\ + {term.ticket.plur_cap} must be purchased at least [hours] hours prior to the {term.performance.norm}.\ + Please select another date or time.\ + '; + + + $(document).ready(function(){ + + // for each ticket + $.each(tickets, function(index, ticket) { + + if (ticket.haveFutureInventory) { + + var inventory = ticket.inventory; + + // Build date data array and count dates for this ticket + var dateCount = 0; + var dateData = false + $.each(inventory, function(index, date) { + + // Count the number of dates + dateCount++; + + // If this is the first one, store it in case it's the only one + dateData = date; + + }); // each date + + // if there's no date specific tickets + if (!ticket.dateSpecific) { + + // Populate date input field + $('#GLMeventDateSelect_' + ticket.id).html(''); + doQuantSelection(ticket.id, dateData.id, dateData.available, ticket.tooLate); + + // if there's only one date, then display that and move on. + } else if (!ticket.dateSpecific || dateCount == 1) { + + // populate date input field + $('#GLMeventDateSelect_' + ticket.id).html(' \ +
    Date Available: 
    \ +
    \ +
    \ + ' + dateData.ticket_date.date + ' \ + \ +
    \ +
    '); + + doQuantSelection(ticket.id, dateData.id, dateData.available, ticket.tooLate); + + } else { + + // DatePicker action + function avail(date) { + m = (date.getMonth()+1); + if (m < 10) { + m = '0' + m; + } + d = date.getDate(); + if (d < 10) { + d = '0' + d; + } + y = date.getFullYear(); + var mdy = m + '/' + d + '/' + y; + if (inventory[mdy]) { + if (inventory[mdy]['tooLate']) { + return [false,"","Not Available"]; + } else { + return [true,"","Available"]; + } + } else { + return [false,"","Not Available"]; + } + } + + // Use the date picker to select a date + if($('#GLMeventDateInput_' + ticket.id).length > 0) { + $('#GLMeventDateInput_' + ticket.id).datepicker({ + beforeShowDay: avail, + dateFormat: "mm/dd/yy", + minDate: ticket.startDate, + maxDate: ticket.endDate, + onSelect: function(selectedDate, inst) { + // Get data for the selected date + dateData = inventory[selectedDate]; + $('#GLMeventInvID_' + ticket.id).val(dateData.id); + doQuantSelection(ticket.id, dateData.id, dateData.available, dateData.tooLate); + } // Date Selection + + }); // Date Picker + } + + } + + } // if have future inventory + + }); // each ticket + + function doQuantSelection(id, invId, available, tooLate) { + + // Build the ticket quant options + var ticketQuants = ''; + var selectMax = available; + if (selectMax > 50) { + selectMax = 50; + } + + if (tooLate) { + $('#GLMticketQuantContainer_' + id).html(ticketTooLate.replace(/\[hours\]/g, {performanceDetail.purch_leadtime})); + } else { + // note that the braced lte below is needed to inject a less-than-or-equal-to operator without having flexy chew on it. + for (var i = 1; i {lte:h} (selectMax*1); i++) { + ticketQuants = ticketQuants.concat(''); + } + + // Populate the ticket quantity container + tmpQuantSel = ticketQuantSelection.replace(/\[id\]/g, id); + $('#GLMticketQuantContainer_' + id).html(tmpQuantSel.replace(/\[ticket-quants\]/g, ticketQuants)); + } + + } + + var selectButtonPressed = false; + + $('.GLMselectButton').click(function() { + // Prevent multiple submissions + if (selectButtonPressed == true) { + return; + } + + // Check for a selected ticket + var ticketSelected = false; + $('.glmTicketQuant').each(function( index ) { + if ($(this).val() != '') { + ticketSelected = true; + } + }); + + if (ticketSelected) { + selectButtonPressed = true; + setBlocker(); + $('#GLMselectForm').submit(); + } else { + alert('Please select a {term.ticket.norm} quantity.') + return false; + } + + }); + + function setBlocker() { + $('#glmReloadBlocker').show(); + } + if( $(window).width() < 768 ){ + $('.glmBlock').not(":first").each(function() { + var left = $(this).find( $('.glmBlockContentLeft') ); + left.prependTo( $(this) ).find( $('glmBlockContentRight') ); + }); + } + }); + +{end:} + diff --git a/views/front/PointerBoat/Shop_Backup/PayPalApproved.html b/views/front/PointerBoat/Shop_Backup/PayPalApproved.html new file mode 100755 index 0000000..4dff5eb --- /dev/null +++ b/views/front/PointerBoat/Shop_Backup/PayPalApproved.html @@ -0,0 +1,41 @@ + + + + + +
    + +

    Your PayPal payment has been approved.

    + + +
    + +

    + Your cart will now reflect that the payment has been made. +

    + +
    + +
    +
    Close This Window
    +
    + +
    + + + + diff --git a/views/front/PointerBoat/Shop_Backup/PayPalFail.html b/views/front/PointerBoat/Shop_Backup/PayPalFail.html new file mode 100755 index 0000000..bb62666 --- /dev/null +++ b/views/front/PointerBoat/Shop_Backup/PayPalFail.html @@ -0,0 +1,49 @@ + + + + + +
    + +

    Unable to process your payment!

    + + +
    + +

    +

    Sorry, there was a problem.
    +

    + +

    + We were unable to find your purchase information and are therefore + are unable to process your payment through PayPal. This could be + due to you not performing any action with your pending purchase + for too long. Please click the "Return to selected tickets" button + at the top of the checkout page to see if your selections are still listed. +

    + +
    + +
    +
    Close This Window
    +
    + +
    + + + + diff --git a/views/front/PointerBoat/Shop_Backup/additionalInfo.html b/views/front/PointerBoat/Shop_Backup/additionalInfo.html new file mode 100644 index 0000000..b490910 --- /dev/null +++ b/views/front/PointerBoat/Shop_Backup/additionalInfo.html @@ -0,0 +1,246 @@ + + + +
    + + + +
    +
    + + + {term.nav.show_selected} + {if:!option.ticket_shop.start_at_cart} + {term.nav.select_more} + {end:} + + +

    {cartText:h}

    + +
    +
    + +{if:reason} + + + +
    +
    +
    +

    We're sorry, we had a problem with your request:

    +
      + {foreach:reason,r}{Chuck} +
    • {r:h}
    • + {end:} +
    +
    +
    +
    +{end:} + + + +{foreach:cart,c} + + {if:option.show_location_blocks} +
    +
    +
    +
    +

    {c.name:h}

    +
    + {end:} + + + + + {if:c.needAssignemntOrDate} + {if:c.needAssignment} + +
    + {if:!c.haveAssignment} +
    {text.cart.select_assignment_location}
    + {else:} +
    {text.cart.select_assignment_location}
    + {end:} + {foreach:c.assignmentMembers,a} + {if:a.entrances} + {foreach:a.entrances,e} +
    + {if:option.cart_images} + {if:e.image} +
    + {end:} + {end:} +
    + {if:e.selected} + {a.name} - {e.name}
    + {else:} + {a.name} - {e.name}
    + {end:} +
    +
    {e.addr1}{if:e.addr2}, {e.addr2}{end:}, {e.city}
    +
    {e.phone}
    + {if:e.descr} +
    {e.descr:h}
    + {end:} +
    +
    + {end:} +
    + {else:} + {if:a.selected} + {a.name}
    + {else:} + {a.name}
    + {end:} + {end:} + {end:} +  
    + {end:} + + {if:option.ask_for_likely_date} + {if:c.needLikelyDate} +
    +

    + {if:!c.likelyDate} + + {else:} + + {end:} + {text.cart.select_likely_date}   + + mm/dd/yyyy + {if:text.cart.select_likely_date_explain} +
    {text.cart.select_likely_date_explain} + {end:} +

    +
    + {end:} + {end:} +
    +
    + {end:} + {if:!c.needAssignment} + + {if:option.cart_images}{if:c.image} +
    + + +
    + {end:}{end:} + {end:} + +
    +
    +
    + +{end:} + + + +{if:cartHasContents} +
    +
    + {if:!blockCheckout} + {term.nav.checkout} + {else:} + Please complete the items in RED above. + {end:} +
    +
    +{else:} +
    +
    +

    Your cart is currently empty.

    +
    +
    +{end:} + + + + + + + + + diff --git a/views/front/PointerBoat/Shop_Backup/cart.html b/views/front/PointerBoat/Shop_Backup/cart.html new file mode 100755 index 0000000..af2c09a --- /dev/null +++ b/views/front/PointerBoat/Shop_Backup/cart.html @@ -0,0 +1,429 @@ + + + +
    +
    + + +
    + + +
    + {if:!option.ticket_selection.start_at_cart} + {term.nav.select_more} + {end:} + +
    +
    + +
    {cartText:h}
    + {if:reason} +
    +
    We're sorry, we had a problem with your request:
    +
      + {foreach:reason,r}{Chuck} +
    • {r:h}
    • + {end:} +
    +
    + {end:} + {if:havePromoCodes} +
    +
    +
    If you have a {term.promo.norm}, please enter it here:
    +
    +
    + {end:} + {foreach:cart,c} +
    +
    {c.name}
    +
    + {foreach:c.performances,p} +
    +
    + {if:!option.ticket_selection.start_at_cart} + {term.nav.select_more_of_these} + {end:} +
    + +
    {p.name}
    +
    + {if:p.descr}
    {p.descr:h}
    {end:} + {if:p.short_descr}
    {p.short_descr:h}
    {end:} + {if:option.cart_images}{if:p.image} + + {end:}{end:} +
    +
    +
    +
    + {foreach:p.dates,d} +
    + {if:d.dateSpecific} + {d.fullDate} + {else:} + + {if:c.likelyDate} + - Likely Date {c.likelyDate} + {end:} + {end:} + {foreach:d.sections,s} + + + + {if:!p.oneSectionOnly} + + {end:} + + + + + {foreach:s.tickets,i} + + + {if:!p.oneSectionOnly} + + {end:} + + + + + {if:i.problem} + + + + {end:} + {if:i.descr} + + + {if:!p.oneSectionOnly} + + + {end:} + + {foreach:i.addons,a} + + + {if:!p.oneSectionOnly} + + {end:} + + + + + {end:} + + + {if:i.promo} + + + {if:!p.oneSectionOnly} + + {end:} + + + + {end:} + + {end:} +
    QuantSection{term.ticket.cap}PriceTotal
    + + {s.name} + {i.title} + {if:false} + {if:i.date_specific.value} + - {i.start_date.date} + {if:i.time_specific.value} + {i.ticket_time.time} + {end:} + {else:} + {if:i.time_specific.value} + - {i.ticket_time.time} + {end:} + {end:} + {end:} + {if:i.show_price}{i.price}{end:}{if:i.show_price}{i.extended}{end:}
     {i.problemText}
      + {else:} + + {end:} + {if:option.cart_images}{if:i.image} +
    + {end:}{end:} +
    {i.descr:h}
    +
       +
    + +
    +
    {a.unit_cost}/{a.unit_name}{a.money}
      {term.promo.cap}: {promoCode}  + {i.promo.credit}
    + {end:} +
    + {end:} +
    +
    + {end:} +
    + {if:c.ticket_policy}
    {c.ticket_policy:h}
    {end:} + +{if:option.ask_for_assignment_and_likely_date} + {if:c.needAssignemntOrDate} + {if:c.needAssignment} + +
    + {if:!c.haveAssignment} +
    {text.cart.select_assignment_location}
    + {else:} +
    {text.cart.select_assignment_location}
    + {end:} + {foreach:c.assignmentMembers,a} + {if:a.entrances} + {foreach:a.entrances,e} +
    + {if:option.cart_images} + {if:e.image} +
    + {end:} + {end:} +
    + {if:e.selected} + {a.name} - {e.name}
    + {else:} + {a.name} - {e.name}
    + {end:} +
    +
    {e.addr1}{if:e.addr2}, {e.addr2}{end:}, {e.city}
    +
    {e.phone}
    + {if:e.descr} +
    {e.descr:h}
    + {end:} +
    +
    + {end:} +
    + {else:} + {if:a.selected} + {a.name}
    + {else:} + {a.name}
    + {end:} + {end:} + {end:} +  
    + {end:} + + {if:option.ask_for_likely_date} + {if:c.needLikelyDate} +
    + {if:!c.likelyDate} + + {else:} + + {end:} + {text.cart.select_likely_date}   + + mm/dd/yyyy +
    + {end:} + {end:} +
    +
    + {end:} + {if:!c.needAssignment} + + {if:option.cart_images}{if:c.image} +
    + + +
    + {end:}{end:} + {end:} +{end:} + + +
    + {end:} + + +
    + {if:cartHasContents} +
    + Grand Total   {totals.price} +
    +
    + {if:totals.tickets} + + {term.nav.checkout} + + {else:} + Your cart is currently empty. + {end:} +
    + {else:} +

    Your cart is currently empty.

    + {end:} +
    + + {if:option.cart_promotions} +
    + You may also be interested in ...
    + {foreach:cartPromotions,p} +
    + + {if:p.image} +
    + {end:} +
    + {if:p.start_date} +

    + Dates: {p.start_date.date} +

    + {end:} + + {if:p.short_descr}
    {p.short_descr:h}
    {end:} + {if:p.short_descr}
    {p.short_descr:h}
    {end:} +
    +
    + {end:} +
    + {end:} + + + +
    + +{startScript:h} + + $(document).ready(function(){ + + // Block direct form submission - Everything submits by jQuery action + $('#cartForm').submit(function( event ) { + return false; + }); + + // Convert input fields to select lists + $('.glmCartQuant').each(function() { + + var id = $(this).attr('id'); + var ticket = $(this).attr('data-ticket'); + var addon = $(this).attr('data-addon'); + var max = $(this).attr('data-max'); + var value = $(this).attr('value'); + var units = $(this).attr('data-units'); + var numbSel = ''; + + // Build a picklist for this input + for (var i = 0 ; i {lte:h} max ; i++) { + if (value == i) { + numbSel = numbSel.concat(''); + } else { + numbSel = numbSel.concat(''); + } + } + + $('#quant_' + id).html('' + units); + + }); + + // Get or set vertical scroll to return to same place when cart reloads + function getVertScroll() { + var vertScroll = window.pageYOffset; + if (vertScroll == 0) { + var vertScroll = document.documentElement.scrollTop; + } + if (vertScroll == 0) { + var vertScroll = document.body.scrollTop; + } + return vertScroll; + } + + // When a cart value changes, submit it as a cart update. + $('.glmCartSelect').change(function() { + vertScroll = getVertScroll(); + var ticket = $(this).attr('data-ticket'); + var addon = $(this).attr('data-addon'); + var value = $(this).val(); + + setBlocker(); + window.location = "{baseSCRIPT}&Action=Shop_cart&cart=update&ticket_inv=" + ticket + "&addon=" + addon + "&quant=" + value + "&vertScroll=" + vertScroll; + + }); + + // When there's a change in the promo code input, submit it. + $('#promoCodeInput').change(function() { + var value = $(this).val(); + setBlocker(); + window.location = "{baseSCRIPT}&Action=Shop_cart&cart=promo_code&promo_code=" + value; + }); + + // When a member selection for unassigned items changes, submit it so it's in the session + $('.glmAssignmentChange').change(function() { + vertScroll = getVertScroll(); + var member = $(this).attr('data-Member'); + var assignedTo = $(this).val(); + var assignedToEntrance = $(this).attr('data-entrance'); + setBlocker(); + window.location = "{baseSCRIPT}&Action=Shop_cart&cart=update_assignment&member_assigned=" + member + "&assigned_to=" + assignedTo + "&entrance_assigned=" + assignedToEntrance + "&vertScroll=" + vertScroll; + }); + + // When a likely departure date changes, submit it so it's in the session + $('.glmLikelyDateChange').change(function() { + vertScroll = getVertScroll(); + var member = $(this).attr('data-Member'); + var likelyDate = $(this).val(); + setBlocker(); + window.location = "{baseSCRIPT}&Action=Shop_cart&cart=update_likelyDate&member=" + member + "&likely_date=" + likelyDate + "&vertScroll=" + vertScroll; + + }); + + // Code to start datepicker for each date input + if($("#likelyDateInput").length > 0) { + $("#likelyDateInput").datepicker({ + dateFormat: "mm/dd/yy", + minDate: -1, + maxDate: 365 + }); + } + + // Checkout action + $('#GLMcheckoutBtn').click(function() { + setBlocker(); + window.location = "{baseSCRIPT}&Action=Shop_checkout"; + }); + + function setBlocker() { + $('#glmReloadBlocker').show(); + } + + $('#GLMnavSelectEvent').on('click', function() { // Return to Event Selection + setBlocker(); + window.location = '{startURL:h}'; + }); + +/* Not using right now + // Reprint order button + $('#reprintVoucher').on('keypress', function(event) { + if(event.which == '13'){ + var orderID = $(this).val(); + var voucherWindow = window.open('{appAdminURL}&Action=Order_printVoucher&OrderID=' + orderID, + "voucherPrint", + "height=750,width=600,menubar=yes,toolbar=yes,alwaysRaised=yes,menu" + ); + voucherWindow.focus(); + voucherWindow.print(); + return false; + } + }); +*/ + + if ({vertScroll}) { + window.scrollTo(0,{vertScroll}); + } + + }); + + + diff --git a/views/front/PointerBoat/Shop_Backup/checkout.html b/views/front/PointerBoat/Shop_Backup/checkout.html new file mode 100755 index 0000000..d77584c --- /dev/null +++ b/views/front/PointerBoat/Shop_Backup/checkout.html @@ -0,0 +1,926 @@ + + + +
    + +
    +
    Selected {term.ticket.plur_cap}
    + +
    + {term.nav.show_selected} + {if:!option.ticket_selection.start_at_cart} + {term.nav.select_more} + {end:} +
    +
    + +
    {checkoutText:h}
    + {if:reason} +
    +
    We're sorry, we had a problem with your request:
    +
      + {foreach:reason,r} +
    • {r:h}
    • + {end:} +
    +

    See below for more information.

    +
    + {end:} +
    + + +
    +
    Contact Information
    + +
    +
    +
    {text.cart.checkout.first_name}:
    +
    {text.cart.checkout.first_name}:
    + {if:formData.contact.fname.problem} +
    +
    {formData.contact.fname.problem}
    + {else:} +
    + {end:} + +
    +
    +
    +
    {text.cart.checkout.last_name}:
    +
    {text.cart.checkout.last_name}:
    + {if:formData.contact.lname.problem} +
    +
    {formData.contact.lname.problem}
    + {else:} +
    + {end:} + +
    +
    +
    +
    {text.cart.checkout.address}:
    +
    {text.cart.checkout.address}:
    + {if:formData.contact.addr1.problem} +
    +
    {formData.contact.addr1.problem}
    + {else:} +
    + {end:} + +
    +
    +
    +
     
    +
     
    + {if:formData.contact.addr2.problem} +
    +
    {formData.contact.addr2.problem}
    + {else:} +
    + {end:} + +
    +
    +
    +
    {text.cart.checkout.city}:
    +
    {text.cart.checkout.city}:
    + {if:formData.contact.city.problem} +
    +
    {formData.contact.city.problem}
    + {else:} +
    + {end:} + +
    +
    +
    +
    {text.cart.checkout.state}:
    +
    {text.cart.checkout.state}:
    + {if:formData.contact.state.problem} +
    +
    {formData.contact.state.problem}
    + {else:} +
    + {end:} + +
    +
    +
    +
    {text.cart.checkout.country}:
    +
    {text.cart.checkout.country}:
    + {if:formData.contact.country.problem} +
    +
    {formData.contact.country.problem}
    + {else:} +
    + {end:} + +
    +
    +
    +
    {text.cart.checkout.zip}:
    +
    {text.cart.checkout.zip}:
    + {if:formData.contact.zip.problem} +
    +
    {formData.contact.zip.problem}
    + {else:} +
    + {end:} + +
    +
    +
    +
    {text.cart.checkout.phone}:
    +
    {text.cart.checkout.phone}:
    + {if:formData.contact.phone.problem} +
    +
    {formData.contact.phone.problem}
    + {else:} +
    + {end:} + +
    +
    +
    +
    {text.cart.checkout.email}:
    +
    {text.cart.checkout.email}:
    + {if:formData.contact.email.problem} +
    +
    {formData.contact.email.problem}
    + {else:} +
    + {end:} + +
    +
    +
    +
    {text.cart.checkout.email_again}:
    +
    {text.cart.checkout.email_again}:
    + {if:formData.contact.email2.problem} +
    +
    {formData.contact.email2.problem}
    + {else:} +
    + {end:} + +
    +
    +
    +
    Receive E-Newsletter?
    + {if:formData.contact.email_ok} +
    + {else:} +
    + {end:} + Please sign me up to receive "The Ship's Bell" e-newsletter. +
    +
    + + {if:opt_field_1_name} +
    +
    {opt_field_1_name}:
    +
    {opt_field_1_name}:
    + {if:formData.contact.opt_field_1.problem} +
    +
    {formData.contact.opt_field_1.problem}
    + {else:} +
    + {end:} + +
    +
    + {end:} + {if:opt_field_2_name} +
    +
    {opt_field_2_name}:
    +
    {opt_field_2_name}:
    + {if:formData.contact.opt_field_2.problem} +
    +
    {formData.contact.opt_field_2.problem}
    + {else:} +
    + {end:} + +
    +
    + {end:} + {if:opt_field_3_name} +
    +
    {opt_field_3_name}:
    +
    {opt_field_3_name}:
    + {if:formData.contact.opt_field_3.problem} +
    +
    {formData.contact.opt_field_3.problem}
    + {else:} +
    + {end:} + +
    +
    + {end:} + + +
    +
    + + {foreach:cart,c} + {if:c.performances} +
    +
    {term.prop.cap}: {c.name}
    + + +
    + + {foreach:c.performances,p} +
    +
    +
    +
    +
    {p.name}
    +
    + + {if:option.cart_images}{if:option.cart_images}{if:p.image}{end:}{end:}{end:} +
    +
    +
    +
    + {foreach:p.dates,d} +
    +
    + + {if:d.dateSpecific} + {d.fullDate} + {else:} + + {if:c.likelyDate} + - Likely Date {c.likelyDate} + {end:} + {end:} + +
    + + + {foreach:d.sections,s} + + + + {if:!p.oneSectionOnly} + + {end:} + + + + + {foreach:s.tickets,i} + + + {if:!p.oneSectionOnly} + + {end:} + + + + + {if:i.descr} + + + {if:!p.oneSectionOnly} + + + {end:} + + {foreach:i.addons,a} + + + {if:!p.oneSectionOnly} + + {end:} + + + + + {end:} + + {if:i.promo} + + + {if:!p.oneSectionOnly} + + {end:} + + + + {end:} + {end:} +
    QuantSection{term.ticket.cap}PriceTotal
    + {i.selected} + {s.name} + {i.title} + {if:i.time_specific.value} + - {i.ticket_time.time} + {else:} + + {end:} + {if:i.show_price}{i.price}{end:}{if:i.show_price}{i.extended}{end:}
      + {else:} + + {end:} + {if:option.cart_images} + {if:i.image} +
    + {end:} + {end:} +
    {i.descr:h}
    +
       +
    + {a.selected} {a.unit_name} +
    +
    {a.unit_cost}/{a.unit_name}{a.money}
      {term.promo.cap}: {promoCode}  + {i.promo.credit}
    + {end:} +
    + {end:} +
    +
    + {if:p.policy} +
    +
    + Please read and agree to our policy for this {term.performance.norm}. +
    +
    +

    {p.policy:h}

    +
    +
    +

    I agree to the policy stated above.

    +
    +
    + {end:} +
    + {end:} +
    + + {if:c.ticket_policy}
    {c.ticket_policy:h}
    {end:} + {if:c.ticket_policy}
    {c.ticket_policy:h}
    {end:} + +
    + + {if:c.ticket_spec_req.value} +
    +
    Please enter any special requests:
    +
    +
    + {end:} + + + {if:!formData.centralPayment} +
    + + {if:c.paymentResult} + {if:c.paymentResult.approved} +
    Card Payment Approved
    +
    Card Type
    {c.paymentResult.cctype}
    +
    Name on Card
    {c.paymentResult.ccname}
    +
    Card Number
    {c.paymentResult.ccnumb}
    +
    Expiration Date
    {c.paymentResult.ccexp}
    +
    Authorization Code
    {c.paymentResult.authCode}
    +
    +
    {term.nav.print_vouchers}
    +
    + {else:} +
    Card Payment Not Complete
    +
    • {c.paymentResult.description}
    +

    Please check the payment information below and try again or contact your credit card company for assistance.

    + {if:forceCheckoutPhase} +
    +
    {term.nav.delete_from_cart}
    +
    + {end:} + {end:} + {end:} + {if:c.paymentResult.approved} +

    Payment Accepted

    + {else:} + {if:c.havePaymentMethod} + +
    + {if:c.havePayPal} + {if:c.haveMultiplePaymentMethods} +  PayPal + {else:} + + {end:} + {end:} + {if:c.haveCreditCards} + {if:c.havePayPal} +      + {end:} + {if:c.haveMultiplePaymentMethods} +  Credit Card + {else:} + + {end:} + {end:} +
    + + {if:c.haveCreditCards} + {if:c.haveMultiplePaymentMethods} + + {else:} + + {end:} +
    +
    Total Charged to this Card
    +
    {c.totalPrice}
    +
    +
    +
    Card Type
    +
    Card Type
    + {if:c.paymentForm.cctype.problem} +
    +
    {c.paymentForm.cctype.problem}
    + {else:} +
    + {end:} + +
    +
    +
    +
    Name on Card
    +
    Name on Card
    + {if:c.paymentForm.ccname.problem} +
    +
    {c.paymentForm.ccname.problem}
    + {else:} +
    + {end:} + +
    +
    +
    +
    Card Number
    +
    Card Number
    + {if:c.paymentForm.ccnumb.problem} +
    +
    {c.paymentForm.ccnumb.problem}
    + {else:} +
    + {end:} + +
    +
    +
    +
    Expiration Date
    +
    Expiration Date
    + {if:c.paymentForm.ccexp.problem} +
    +
    {c.paymentForm.ccexp.problem}
    + {else:} +
    + {end:} + Month + + Year + +
    +
    +
    +
    Security Code
    +
    Security Code
    + {if:c.paymentForm.cccode.problem} +
    +
    {c.paymentForm.cccode.problem}
    + {else:} +
    + {end:} + +
    +
    +
    +
    + The Security Code is the three or four digit number on the signature side of your credit card. +
    +
    + + {end:} + {if:c.havePayPal} + + {if:c.haveMultiplePaymentMethods} + + {else:} + + {end:} +
    + +
    +
    + {end:} + {if:c.haveMultiplePaymentMethods} + +
    Please select a Payment Method
    +
    + {end:} + {else:} + +
    + This {term.prop.norm} does not have a payment method configured. + Please call this {term.prop.norm} to purchase {term.ticket.plur}. +
    +
    + {end:} + {end:} + +
    +
    + + {end:} +
    +
    + {end:} + + {if:!cartRequiresPayment} + + {end:} + + {end:} + +{if:cartRequiresPayment} + {if:formData.centralPayment} + +
    + + {if:formData.centralPayment.havePaymentMethod} + + {foreach:formData.centralPayment.paymentForm,p} + + {if:p.cctype} + + + +
    +
    + {if:formData.centralPayment.haveMultiplePaymentMethods} +  Credit Card + {else:} + + {end:} +
    +
    +
    +
    Card Type
    +
    Card Type
    +
    + +
    +
    +
    +
    Name on Card
    +
    Name on Card
    + {if:p.ccname.problem} +
    +
    {p.ccname.problem}
    + {else:} +
    + {end:} + +
    +
    +
    +
    Card Number
    +
    Card Number
    + {if:p.ccnumb.problem} +
    +
    {p.ccnumb.problem}
    + {else:} +
    + {end:} + +
    +
    +
    +
    Expiration Date
    +
    Expiration Date
    + {if:p.ccexp.problem} +
    +
    {p.ccexp.problem}
    + {else:} +
    + {end:} + Month + + Year + +
    +
    +
    +
    Security Code
    +
    Security Code
    + {if:p.cccode.problem} +
    +
    {p.cccode.problem}
    + {else:} +
    + {end:} + +
    +
    +
    +
    + The Security Code is the three or four digit number on the signature side of your credit card. +
    +
    + + {if:p.haveMultiplePaymentMethods} + +
    Please select a Payment Method
    +
    + {end:} + + {end:} + {end:} + +
    + + {else:} + +
    + This {term.prop.norm} does not have a payment method configured. + Please call this {term.prop.norm} to purchase {term.ticket.plur}. +
    +
    + + {end:} + + {end:} + +{end:} + + + +
    + {if:cartRequiresPayment} +
    +
    Complete Purchase
    + +

    + {ssl_seal_head_script:h} + {ssl_seal_body_script:h} +

    +
    + {else:} +
    +
    No Payment Required
    +
    + {end:} +
    +
    + {if:cartRequiresPayment} + +
    +
    + Grand Total   {totals.price} +
    + + + + + + + +
    + {end:} +
    + {if:!cartHasOneVenueOnly} + + {end:} + + {if:adminUser} +
    + No payment info required for Admin User. +
    + {if:noPaymentReasons} +
    + Reason for no payment information required:
    + +
    + {end:} + {end:} + +
    + {if:!blockCheckout} + {term.nav.purchase} + {else:} + Unable to checkout - please see above. + {end:} +
    +
    +
    + +
    + + + + + + diff --git a/views/front/PointerBoat/Shop_Backup/checkoutSuccess.html b/views/front/PointerBoat/Shop_Backup/checkoutSuccess.html new file mode 100755 index 0000000..023a3de --- /dev/null +++ b/views/front/PointerBoat/Shop_Backup/checkoutSuccess.html @@ -0,0 +1,380 @@ + + + + + +
    + + +
    Purchase Complete
    + + + + + {foreach:cart,c} + {if:c.paymentResult} + {if:c.paymentResult.approved} +

    +

    *** {term.nav.print_vouchers} for {c.name} ***
    +

    + {end:} + {end:} + {end:} + + + +
    +
    + +
    +
    + +

    + Adobe Reader is required to view and print your {term.voucher.plur}. Adobe Reader is a free program available directly from Adobe. + If you do not already have Adobe Reader installed, click the "Get Adobe Reader" link now. +

    +
    +
    +
    + +

    + If you are unable to print your {term.voucher.plur}, please print this page or write down the order number(s) + below and bring that to the ticket office when you arrive. +

    + ORDER #: + {foreach:cart,c} + {if:c.paymentResult} + {if:c.paymentResult.approved} + {c.paymentResult.orderID}  + {end:} + {end:} + {end:} +
    +
    +
    + + +
    {successText:h}
    + +
    +
    Contact Information
    +
    +
    First Name:
    {formData.contact.fname.value}
    +
    Last Name:
    {formData.contact.lname.value}
    +
    Address:
    {formData.contact.addr1.value}
    +
     
    {formData.contact.addr2.value}
    +
    City:
    {formData.contact.city.value}
    +
    State:
    {formData.contact.state.value}
    +
    Country:
    {formData.contact.country.value}
    +
    ZIP/Postal Code:
    {formData.contact.zip.value}
    +
    Phone:
    {formData.contact.phone.value}
    +
    E-Mail address:
    {formData.contact.email.value}
    + {if:opt_field_1_name}
    {opt_field_1_name}:
    {formData.contact.opt_field_1.value:h}
    {end:} + {if:opt_field_2_name}
    {opt_field_2_name}:
    {formData.contact.opt_field_2.value:h}
    {end:} + {if:opt_field_3_name}
    {opt_field_3_name}:
    {formData.contact.opt_field_3.value:h}
    {end:} +
     
    + {if:formData.contact.email_ok} + You have asked us to send information on activities and offers. + {else:} + You have asked us to NOT send information on activities and offers.
    + We will only contact you regarding this order. + {end:} +
    + +
    + +
    + + + {foreach:cart,c} +
    + +
    {term.ticket.plur_cap} at: {c.name}
    + + +
    + {if:c.descr}
    {c.descr:h}
    {end:} + {if:option.cart_images}{if:c.image}{end:}{end:} + +
    + +
    + + {foreach:c.performances,p} + +
    + +
    +
    +
    + {term.performance.cap}: {p.name} +
    +
    + + {if:option.cart_images}{if:option.cart_images}{if:p.image}{end:}{end:}{end:} +
    +
    +
    + +
    + {foreach:p.dates,d} + +
    + {term.ticket.cap} date: + + {if:d.dateSpecific} + {d.fullDate} + {else:} + Use any date + {if:c.likelyDate} + - Likely Date {c.likelyDate} + {end:} + {end:} + +
    + + + {foreach:d.sections,s} + + + + {if:!p.oneSectionOnly} + + {end:} + + + + + {foreach:s.tickets,i} + + + {if:!p.oneSectionOnly} + + {end:} + + + + + {if:i.descr} + + + {if:!p.oneSectionOnly} + + + {end:} + + {foreach:i.addons,a} + + + {if:!p.oneSectionOnly} + + {end:} + + + + + {end:} + + {if:i.promo} + + + {if:!p.oneSectionOnly} + + {end:} + + + + {end:} + {end:} +
    QuantSection{term.ticket.cap}PriceTotal
    + {i.selected} + {s.name} + {i.title} + + {if:i.date_specific.value} + - {i.start_date.date} + {if:i.time_specific.value} + {i.ticket_time.time} + {end:} + {else:} + {if:i.time_specific.value} + - {i.ticket_time.time} + {end:} + {end:} + {if:i.show_price}{i.price}{end:}{if:i.show_price}{i.extended}{end:}
      + {else:} + + {end:} + {if:option.cart_images} + {if:i.image} +
    + {end:} + {end:} +
    {i.descr:h}
    +
       +
    + {a.selected} {a.unit_name} +
    +
    {a.unit_cost}/{a.unit_name}{a.money}
      {term.promo.cap}: {promoCode}  + {i.promo.credit}
    + {end:} + + + {end:} + +
    + +
    + + {if:p.policy} +
    +
    +
    + Our policy for this {term.performance.norm}. +
    +

    {p.policy:h}

    +
    +
    + {end:} + + {end:} + +
    + + + + {if:!cartHasOneVenueOnly} + +
    +
    +
    +
    Sub Total
    +
    +
    +
    {c.totalPrice}
    +
    +
    +
    + {end:} + + {if:c.ticket_policy}
    {c.ticket_policy:h}
    {end:} + + + {if:c.ticket_policy}
    {c.ticket_policy:h}
    {end:} + + +
    + + + {if:c.ticket_spec_req.value} +
    +
    Special requests:
    +
    {c.paymentForm.spec_req.value:h}
    +
    + {end:} + + + {if:c.paymentResult} +
    + {if:c.paymentResult.approved} +
    Card Payment Approved
    + +
    Card Type
    {c.paymentResult.cctype}
    +
    Name on Card
    {c.paymentResult.ccname}
    +
    Card Number
    {c.paymentResult.ccnumb}
    +
    Expiration Date
    {c.paymentResult.ccexp}
    +
    Authorization Code
    {c.paymentResult.authCode}
    +
    +
    {term.nav.print_vouchers}
    +
    + {else:} +
    Card Payment Not Complete
    +
    • {c.paymentResult.description}
    +

    Please check the payment information below and try again or contact your credit card company for assistance.

    + {if:forceCheckoutPhase} +
    +
    {term.nav.delete_from_cart}
    +
    + {end:} + + {end:} + +
    + {end:} + +
    + +
    + + {end:} + +
    + {if:cartHasContents} +
    +
    Cart Totals
    +
    +
    +
    Grand Total
    +
    +
    +
    {totals.price}
    +
    +
    +
    + {else:} +

    Your cart is currently empty.

    + {end:} +
    + +
    + +{trackingScript:h} + + + + + diff --git a/views/front/PointerBoat/Shop_Backup/paymentSummary.html b/views/front/PointerBoat/Shop_Backup/paymentSummary.html new file mode 100755 index 0000000..8ac4b97 --- /dev/null +++ b/views/front/PointerBoat/Shop_Backup/paymentSummary.html @@ -0,0 +1,131 @@ +

    + + Click here to reprint your {term.voucher.plur} + +

    + +

    + + {cartEntry.name} +

    + + + + + + + + + + + + + + +{foreach:cartForSummaryCentral,c} +{foreach:c.performances,p} + {foreach:p.dates,d} + {foreach:d.sections,s} + + + {foreach:s.tickets,i} + + + + + + + + {foreach:i.addons,a} + + + + + + + + {end:} + {if:i.promo} + + + + + + + {end:} + {end:} + + + {end:} + {end:} +{end:} + + + + + + + + +
    Quant{term.performance.cap}{term.ticket.cap}PriceTotal
    {i.selected}{p.name:h} + {i.title:h} + {if:i.date_specific.value} + - {i.ticket_date.date} + {if:i.time_specific.value} + {i.ticket_time.time} + {end:} + {else:} + {if:i.time_specific.value} + - {i.ticket_time.time} + {end:} + {end:} + + {if:i.show_price}{i.price}{end:}{if:i.show_price}{i.extended}{end:}
       +
    + {a.selected} {a.unit_name} +
    +
    {a.unit_cost}/{a.unit_name}{a.money}
      {term.promo.cap}: {promoCode}  + {i.promo.credit}
     {c.totalPrice}
    + + +{if:c.ticket_spec_req} +

    + {c.paymentForm.spec_req.value:h} +

    +{end:} + +{end:} + +{if:cartEntry.ticket_policy}

    {cartEntry.ticket_policy:h}

    {end:} + + + + + + + + + + + + +
    First Name:{formData.contact.fname.value}
    Last Name:{formData.contact.lname.value}
    Address:{formData.contact.addr1.value}
     {formData.contact.addr2.value}
    City:{formData.contact.city.value}
    State:{formData.contact.state.value}
    Country:{formData.contact.country.value}
    ZIP/Postal Code:{formData.contact.zip.value}
    Phone:{formData.contact.phone.value}
    E-Mail address:{formData.contact.email.value}
    + +

    + + + + + + + +
    Credit Card Payment Approved
    Card Type{cartEntry.paymentResult.cctype}
    Name on Card{cartEntry.paymentResult.ccname}
    Card Number{cartEntry.paymentResult.ccnumb}
    Expiration Date{cartEntry.paymentResult.ccexp}
    Authorization Code{cartEntry.paymentResult.authCode}
    +

    + + diff --git a/views/front/PointerBoat/Shop_Backup/sectionSelect.html b/views/front/PointerBoat/Shop_Backup/sectionSelect.html new file mode 100755 index 0000000..db08efa --- /dev/null +++ b/views/front/PointerBoat/Shop_Backup/sectionSelect.html @@ -0,0 +1,96 @@ + + + + + + +
    + + +
    {term.section.cap} Selection
    + + + + + +
    {sectionText:h}
    + +{if:reason} +
    +
    We're sorry, we had a problem with your request:
    +
      + {foreach:reason,r} +
    • {r:h}
    • + {end:} +
    +
    +{end:} + +

    You have selected

    +
    +
    +
    +
    {performanceDetail.member_name}

    +
    {performanceDetail.name}
    +
    +
    + + +
    +
    +
    + + +
    +

    Please select from the following

    +
    +{foreach:sectionList,x} +
    + +
    +

    {term.section.cap}: {x.member_name}

    +

    {x.descr:h}

    +
    +
    +{end:} + +
    + +
    + + {startScript:h} + + $(document).ready(function(){ + + // Code to kick off the geolocation-display feature + $("#locationMap").geolocate({ + lat: "#lat", + lng: "#lon", + mapOptions: { + disableDefaultUI: false, + mapTypeControl: true, + mapTypeId: "roadmap", + zoom: 12 + }, + markerOptions: { + draggable: false, + title: "This is your selected location" + } + }); + + }); + + + diff --git a/views/front/PointerBoat/Shop_Backup/start-COPY.html b/views/front/PointerBoat/Shop_Backup/start-COPY.html new file mode 100644 index 0000000..feda2b4 --- /dev/null +++ b/views/front/PointerBoat/Shop_Backup/start-COPY.html @@ -0,0 +1,162 @@ + + +
    +
    +
    +
    +
    {m.name}
    +
    +
    +
    Address: {m.addr1}{if:m.addr2}, {m.addr2}{end:}, {m.city}
    +
    Phone #: {m.phone}
    +
    {m.descr:h}
    +
    +
    +
    +
    (map loads here)
    +
    + + +
    +
    + +
    + {foreach:m.performances,p} +
    +
    +
    +
    + {if:showTickets} + {p.name} + {else:} + {p.name} + {end:} +
    +
    +
    +
    {term.prop.cap}: {p.member_name}
    +
    Dates: {p.start_date.date} through {p.end_date.date}
    +
    +
    + {if:!showTickets} + {term.nav.select} + {end:} + + + {foreach:p.sections,s} +

     

    +
    +
    +
    + {if:!p.oneSectionOnly} + {s.sectionDetail.name}
    + {end:} + +
    + +
    +
    + + + {foreach:s.ticketsData,x} +
    + {if:option.ticket_selection.include_options_in_ticket_list} +
    +
    +
    Price: 
    +
    +
    {x.price}
    +
    +
    +
    +
    Select date: 
    +
    +
    + + +
    +
    +
    +
    +
    Quant: 
    +
    +
    (select date)
    +
    +
    +
    + + {end:} + +
    + {if:option.ticket_selection.include_options_in_ticket_list} +
    {x.title}
    + {else:} +
    + {x.name} +
    + {term.nav.select} + {end:} +
    +
    + {if:x.descr} +

    {x.descr:h}

    + {end:} +
    + {if:!x.date_specific.value} + Use any date{if:x.start_date.timestamp} from {x.start_date.date} to {x.end_date.date}{end:}{if:!x.time_specific.value}, {end:} + {end:} + {if:!x.time_specific.value} + Use any time of day, + {else:} + Time: {x.ticket_time.time}, + {end:} + {if:x.unlimted_use.value} + Each {term.ticket.norm} may be used an unlimited number of times + {else:} + + {end:} +
    +
    +
    + {if:option.ticket_selection.include_options_in_ticket_list} +
    +
    +
    Price each: 
    +
    +
    {x.price}
    +
    +
    +
    +
    Select date: 
    +
    +
    + + +
    +
    +
    +
    +
    Quant: 
    +
    +
    (select date)
    +
    +
    +
    + + {end:} +
    + + + {end:} + +
    + + {end:} + + + +
    + {end:} +
    +
    + {end:} diff --git a/views/front/PointerBoat/Shop_Backup/start.html b/views/front/PointerBoat/Shop_Backup/start.html new file mode 100755 index 0000000..b1e6ec4 --- /dev/null +++ b/views/front/PointerBoat/Shop_Backup/start.html @@ -0,0 +1,407 @@ + + + + +
    + +
    +
    {term.event.cap} Selection
    + + +
    + +
    {introText:h}
    + {if:reason} +
    +
    We're sorry, we had a problem with your request:
    +
      + {foreach:reason,r} +
    • {r:h}
    • + {end:} +
    +
    + {end:} +

    Please select from the following

    +{if:showTickets} +
    + + + + +{end:} + + {foreach:membersList,m} +
    +
    +
    +
    +
    {m.name}
    +
    +
    +
    Address: {m.addr1}{if:m.addr2}, {m.addr2}{end:}, {m.city}
    +
    Phone #: {m.phone}
    +
    {m.descr:h}
    +
    +
    + {if:option.select_images} + {if:m.image} +
    + {end:} + {end:} + +
    + {foreach:m.performances,p} +
    + {if:option.select_images} + {if:p.image} +
    + {else:} +
    + {end:} + {else:} +
    + {end:} +
    +
    + {if:showTickets} + {p.name} + {else:} + {p.name} + {end:} +
    +
    +
    + + {if:p.start_date.timestamp}
    Dates: {p.start_date.date}{if:p.end_date.timestamp} - {p.end_date.date} {end:}
    {end:} +
    {p.short_descr:h}
    +
    +
    + {if:option.select_images} + {if:p.image} +
    + {end:} + {end:} + {if:!showTickets} + + {end:} + + + + {foreach:p.sections,s} +

     

    +
    +
    +
    + {if:!p.oneSectionOnly} + {s.sectionDetail.name}
    + {end:} + +
    + +
    +
    + + + {foreach:s.ticketsData,x} +
    + {if:option.ticket_selection.include_options_in_ticket_list} +
    +
    +
    Price: 
    +
    +
    {x.price}
    +
    +
    +
    +
    Select date: 
    +
    +
    + + +
    +
    +
    +
    +
    Quant: 
    +
    +
    (select date)
    +
    +
    +
    + + {end:} + +
    + {if:option.ticket_selection.include_options_in_ticket_list} +
    {x.title}
    + {else:} +
    + {x.name} +
    + {term.nav.select} + {end:} +
    +
    + {if:x.descr} +

    {x.descr:h}

    + {end:} +
    + {if:!x.date_specific.value} + Use any date{if:x.start_date.timestamp} from {x.start_date.date} to {x.end_date.date}{end:}{if:!x.time_specific.value} {end:} + {end:} + {if:!x.time_specific.value} + Use any time of day, + {else:} + Time: {x.ticket_time.time}, + {end:} + {if:x.unlimted_use.value} + Each {term.ticket.norm} may be used an unlimited number of times + {else:} + + {end:} +
    +
    +
    + {if:option.ticket_selection.include_options_in_ticket_list} +
    +
    +
    Price each: 
    +
    +
    {x.price}
    +
    +
    +
    +
    Select date: 
    +
    +
    + + +
    +
    +
    +
    +
    Quant: 
    +
    +
    (select date)
    +
    +
    +
    + + {end:} +
    + + + {end:} + +
    + + {end:} + + + +
    + {end:} +
    +
    + {end:} +{if:showTickets} + + +{end:} +
    + +{startScript:h} + + var addButtonPushed = false; + + // Dates for inventory data + var tickets = {ticketsJSON:h}; + + var ticketQuantSelection = '\ + \ + '; + + var ticketTooLate = '\ +

    \ + Sorry, too late to select these {term.ticket.plur} on-line.\ +

    \ + '; + + + + $(document).ready(function(){ + + // Code to kick off the geolocation-display feature + function doLocationMap(id) { + $("#locationMap_" + id).geolocate({ + lat: "#lat_" + id, + lng: "#lon_" + id, + mapOptions: { + disableDefaultUI: false, + mapTypeControl: true, + mapTypeId: "roadmap", + zoom: 12 + }, + markerOptions: { + draggable: false, + title: "This is your selected location" + } + }); + } + {foreach:membersList,m} + doLocationMap({m.id}); + {end:} + + // DatePicker action + function avail(date) { + m = (date.getMonth()+1); + if (m < 10) { + m = '0' + m; + } + d = date.getDate(); + if (d < 10) { + d = '0' + d; + } + y = date.getFullYear(); + mdy = m + '/' + d + '/' + y; + if (dates[mdy]) { + return [true,"","Available"]; + } else { + return [false,"","Not Available"]; + } + } + + // for each ticket + $.each(tickets, function(index, ticket) { + + var inventory = ticket.inventory; + + // Build date data array and count dates for this ticket + var dateCount = 0; + var dateData = false + $.each(inventory, function(index, date) { + + // Count the number of dates + dateCount++; + + // If this is the first one, store it in case it's the only one + dateData = date; + + }); // each date + + // if there's no date specific tickets + if (!ticket.dateSpecific) { + + // Populate date input field + $('#GLMeventDateSelect_' + ticket.id).html(''); + doQuantSelection(ticket.id, dateData.id, dateData.available, dateData.tooLate); + + // if there's only one date, then display that and move on. + } else if (!ticket.dateSpecific || dateCount == 1) { + + // populate date input field + $('#GLMeventDate_' + ticket.id).html('
    Date:
    ' + dateData['date'] + '
    '); + doQuantSelection(ticket.id, dateData.id, dateData.available, dateData.tooLate); + + } else { + + // DatePicker action + function avail(date) { + m = (date.getMonth()+1); + if (m < 10) { + m = '0' + m; + } + d = date.getDate(); + if (d < 10) { + d = '0' + d; + } + y = date.getFullYear(); + mdy = m + '/' + d + '/' + y; + if (inventory[mdy]) { + return [true,"","Available"]; + } else { + return [false,"","Not Available"]; + } + } + + // Use the date picker to select a date + $('#GLMeventDateInput_' + ticket.id).datepicker({ + beforeShowDay: avail, + dateFormat: "mm/dd/yy", +// *** NEED TO FIX REFERENCE TO "performanceDetail" since that's not available on this page + minDate: "{performanceDetail.start_date.date}", + maxDate: "{performanceDetail.end_date.date}", + onSelect: function(selectedDate, inst) { + // Get data for the selected date + dateData = inventory[selectedDate]; + $('#GLMeventInvID_' + ticket.id).val(dateData.id); + doQuantSelection(ticket.id, dateData.id, dateData.available, dateData.tooLate); + } // Date Selection + + }); // Date Picker + + + } + + }); // each ticket + + function doQuantSelection(id, invId, available, tooLate) { + + // Build the ticket quant options + var ticketQuants = ''; + var selectMax = available; + if (selectMax > 50) { + selectMax = 50; + } + + if (tooLate) { + $('#GLMticketQuantContainer_' + id).html(ticketTooLate); + } else { + + // note that the braced lte below is needed to inject a less-than-or-equal-to operator without having flexy chew on it. + for (var i = 1; i {lte:h} (selectMax*1); i++) { + ticketQuants = ticketQuants.concat(''); + } + + // Populate the ticket quantity container + tmpQuantSel = ticketQuantSelection.replace(/\[id\]/g, id); + $('#GLMticketQuantContainer_' + id).html(tmpQuantSel.replace(/\[ticket-quants\]/g, ticketQuants)); + } + + } + + $('#GLMselectButton').click(function() { + + // Check for a selected ticket + var ticketSelected = false; + $('.glmTicketQuant').each(function( index ) { + if ($(this).val() != '') { + ticketSelected = true; + } + }); + + if (ticketSelected) { + selectButtonPressed = true; + setBlocker(); + $('#GLMselectForm').submit(); + } else { + alert('Please select a {term.ticket.norm} quantity.') + return false; + } + + }); + + function setBlocker() { + $('#glmReloadBlocker').show(); + } + + }); + + + diff --git a/views/front/PointerBoat/Shop_Backup/svn-commit.tmp b/views/front/PointerBoat/Shop_Backup/svn-commit.tmp new file mode 100644 index 0000000..8c664dd --- /dev/null +++ b/views/front/PointerBoat/Shop_Backup/svn-commit.tmp @@ -0,0 +1,4 @@ +Anthony changes for "use any date" or whatever +--This line, and those below, will be ignored-- + +M checkout.html diff --git a/views/front/PointerBoat/Shop_Backup/ticketOpt.html b/views/front/PointerBoat/Shop_Backup/ticketOpt.html new file mode 100755 index 0000000..6dedcf0 --- /dev/null +++ b/views/front/PointerBoat/Shop_Backup/ticketOpt.html @@ -0,0 +1,273 @@ + + + + + +
    + +
    +
    Ticket Selection
    + + +
    + +
    {ticketOptText:h}
    + {if:reason} +
    +
    We're sorry, we had a problem with your request:
    +
      + {foreach:reason,r} +
    • {r:h}
    • + {end:} +
    +
    + {end:} +

    You have selected

    + +
    +
    +
    +
    {performanceDetail.name}
    +
    +
    +
    {term.prop.cap}: {performanceDetail.member_name}
    + + +
    +
    +
    +
    +
    {sectionDetail.name}
    +
    +
    + +
    +
    +
    +
    +
    {ticketDetail.name}
    +
    +
    + {if:!ticketDetail.date_specific.value} +
    Use any date {if:ticketDetail.start_date.timestamp} from {ticketDetail.start_date.date} to {ticketDetail.end_date.date}{end:}
    + {end:} + {if:!ticketDetail.time_specific.value} +
    Use any time
    + {else:} +
    Time: {ticketDetail.ticket_time.time}
    + {end:} + {if:!ticketDetail.unlimted_use.value} + + {else:} +
    Each {term.ticket.norm} may be used an unlimited number of times
    + {end:} +
    {ticketDetail.descr:h}
    +
    +
    +
    + +

    Please select from the following.

    +
    +
    +
    +
    +
    +
    +
    +
    Select desired date:
    +
    +
    (click in field to set date)
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    Select Quantity:
    +
    +
    (please select date first)
    +
    +
    +
    +
    + {if:reason}
    (disabled - please see above)
    {else:}
    {term.nav.add_to_cart}
    {end:} +
    + +{startScript:h} + + // Whether ticket has date specific inventory + var dateSpecific = {ticketDetail.date_specific.value} + 0; + + // Dates for inventory data + var dates = {inventoryJSON:h}; + + $(document).ready(function(){ + + // DatePicker action + function avail(date) { + m = (date.getMonth()+1); + if (m < 10) { + m = '0' + m; + } + d = date.getDate(); + if (d < 10) { + d = '0' + d; + } + y = date.getFullYear(); + mdy = m + '/' + d + '/' + y; + if (dates[mdy]) { + return [true,"","Available"]; + } else { + return [false,"","Not Available"]; + } + } + var dateData = false; + + var ticketQuantSelection = '\ + \ + '; + var ticketTooLate = '\ +

    \ + Sorry, too late to select these {term.ticket.plur} on-line.\ + {term.ticket.plur_cap} must be purchased at least {detail.performance.purch_leadtime} hours prior to the {term.performance.norm}.\ + Please select another date or time.\ +

    \ + '; + var selectedInv; + var ticketQuants; + var addButtonPushed = false; + + // Start by counting the number of dates to see if we have only 1 + var dateCount = 0; +// if (dateSpecific) { + $.each(dates, function(index, date) { + dateCount = dateCount + 1; + dateData = date; + }); +// } + // if there's no date specific tickets + if (!dateSpecific) { + // Populate date input field + $('#GLMeventDateSelectBlock').html(''); + doQuantSelection(); + // if there's only one date, then display that and move on. + } else if (!dateSpecific || dateCount == 1) { + // populate date input field + $('#GLMeventDate').val(dateData['date']); + $('#GLMtickets').html('
    Date:
    ' + dateData['date'] + '
    '); + + doQuantSelection(); + } else { + // Use the date picker to select a date + dateData = false; + $("#GLMeventDate").datepicker({ + beforeShowDay: avail, + dateFormat: "mm/dd/yy", + minDate: "{performanceDetail.start_date.date}", + maxDate: "{performanceDetail.end_date.date}", + onSelect: function(selectedDate, inst) { + // Update input message + $('#GLMdateMessage').html('
    '); + + // Get data for the selected date + dateData = dates[selectedDate]; + doQuantSelection(); + } // Date Selection + + }); // Date Picker + + } + + function doQuantSelection() { + // Build the ticket quant options + ticketQuants = ''; + var selectMax = dateData['available']; + if (selectMax > 50) { + selectMax = 50; + } + var tooLate = dateData['tooLate']; + if (tooLate) { + $('#GLMticketQuantContainer').html(ticketTooLate); + } else { + // note that the braced lte below is needed to inject a less-than-or-equal-to operator without having flexy chew on it. + for (var i = 1; i {lte:h} (selectMax*1); i++) { + ticketQuants = ticketQuants.concat(''); + } + + // Populate the ticket quantity container + $('#GLMticketQuantContainer').html(ticketQuantSelection.replace(/\[ticket-quants\]/g, ticketQuants)); + } +// doAddToCartSetup(); + } + +// function doAddToCartSetup() { + // Add to cart action + $('#GLMaddToCart').click(function() { + if (addButtonPushed) { + return; + } + var reason = ''; + // Check date + if (dateData) { + selectedInv = dateData.id; + } else { + reason = reason.concat('* You need to select a date first.\n'); + } + // Check quantity + var selectedQuant = (parseInt($('#glmQuantSelector').val()) + 0); + if (selectedQuant == 0) { + reason = reason.concat('* You need to select a quantity first.\n'); + } + // Check if there's a reason we can't add this to the cart yet + if (reason != '') { + alert(reason); + return; + } + // Adding to cart + addButtonPushed = true; + $("#GLMeventDate").datepicker('disable'); + $('#glmQuantSelector').prop('disabled', 'disabled'); + setBlocker(); + // Submit to cart + window.location = "{baseSCRIPT}&Action=Shop_cart&cart=add&PerformanceID={performanceDetail.id}&SectionID={sectionDetail.id}&TicketID={ticketDetail.id}&ticket_inv=" + selectedInv + "&quant=" + selectedQuant; + + }); +// } + // Code to kick off the geolocation-display feature + $("#locationMap").geolocate({ + lat: "#lat", + lng: "#lon", + mapOptions: { + disableDefaultUI: false, + mapTypeControl: true, + mapTypeId: "roadmap", + zoom: 12 + }, + markerOptions: { + draggable: false, + title: "This is your selected location" + } + }); + // Navigation buttons + $('#GLMnavCart').click(function() { // Add to Cart + window.location = '{baseSCRIPT}&Action=Shop_cart'; + }); + $('#GLMnavSelectEvent').on('click', function() { // Return to Event Selection + window.location = '{startURL:h}'; + }); + + function setBlocker() { + $('#glmReloadBlocker').show(); + } + + }); + + diff --git a/views/front/PointerBoat/Shop_Backup/ticketSelect.html b/views/front/PointerBoat/Shop_Backup/ticketSelect.html new file mode 100755 index 0000000..77e2b51 --- /dev/null +++ b/views/front/PointerBoat/Shop_Backup/ticketSelect.html @@ -0,0 +1,326 @@ + + + +
    + +
    +
    {term.ticket.cap} Selection
    + +
    + {term.nav.show_selected} + {if:!option.ticket_selection.start_at_cart} + {term.nav.select_more} + {end:} +
    +
    + +
    {ticketText:h}
    +{if:reason} +
    +
    We're sorry, we had a problem with your request:
    +
      + {foreach:reason,r} +
    • {r:h}
    • + {end:} +
    +
    +{end:} +

    You have selected

    + + + +{foreach:sections,s} +
    +
    + + +
    + {if:performanceDetail.image} +
    +
    + {else:} +
    + {end:} + +
    +
    {performanceDetail.member_name:h}

    +
    {performanceDetail.name:h}
    +
    +
    +
    + {if:!oneSectionOnly} + {s.sectionDetail.name}
    + {end:} + +
    + + {if:performanceDetail.descr} + {performanceDetail.descr:h} + {end:} +
    +
    +
    +
    +
    + + +

    Please select from the following. If you do not see the number of tickets available that you require, please select a different date or time.

    +
    +
    + + + + + {foreach:s.ticketsData,x} + {if:!x.tooLateToBuy} +
    + {if:option.ticket_selection.include_options_in_ticket_list} +
    +
    +
    Price: 
    +
    +
    {x.price}
    +
    +
    +
    +
    Select date: 
    +
    +
    + + +
    +
    +
    +
    +
    Quant: 
    +
    +
    (select date)
    +
    +
    +
    + {end:} +
    + {if:option.ticket_selection.include_options_in_ticket_list} +
    {x.title}
    + {else:} +
    + {x.name} +
    + {end:} +
    +
    + {if:x.descr} +

    {x.short_descr:h}

    + {end:} +

    + {if:!x.date_specific.value} + {if:x.start_date.timestamp} Date: {x.start_date.date}{end:}{if:!x.start_end_dates_same} to {x.end_date.date}{end:}{if:!x.time_specific.value} {end:} + {end:} + {if:!x.time_specific.value} + + {else:} + Time: {x.ticket_time.time} + {end:} + {if:x.unlimted_use.value} + Each {term.ticket.norm} may be used an unlimited number of times + {else:} + + {end:} +

    +
    +
    +
    +
    + {end:} + {end:} + +
    +
    + +{end:} + +
    + +{if:option.ticket_selection.include_options_in_ticket_list} + + {startScript:h} + + var addButtonPushed = false; + + // Dates for inventory data + var tickets = {ticketsJSON:h}; + + var ticketQuantSelection = '\ + \ + '; + + var ticketTooLate = '\ + Sorry, too late to select these {term.ticket.plur} on-line.\ + {term.ticket.plur_cap} must be purchased at least [hours] hours prior to the {term.performance.norm}.\ + Please select another date or time.\ + '; + + + $(document).ready(function(){ + + // for each ticket + $.each(tickets, function(index, ticket) { + + if (ticket.haveFutureInventory) { + + var inventory = ticket.inventory; + + // Build date data array and count dates for this ticket + var dateCount = 0; + var dateData = false + $.each(inventory, function(index, date) { + + // Count the number of dates + dateCount++; + + // If this is the first one, store it in case it's the only one + dateData = date; + + }); // each date + + // if there's no date specific tickets + if (!ticket.dateSpecific) { + + // Populate date input field + $('#GLMeventDateSelect_' + ticket.id).html(''); + doQuantSelection(ticket.id, dateData.id, dateData.available, ticket.tooLate); + + // if there's only one date, then display that and move on. + } else if (!ticket.dateSpecific || dateCount == 1) { + + // populate date input field + $('#GLMeventDateSelect_' + ticket.id).html(' \ +
    Date Available: 
    \ +
    \ +
    \ + ' + dateData.ticket_date.date + ' \ + \ +
    \ +
    '); + + doQuantSelection(ticket.id, dateData.id, dateData.available, ticket.tooLate); + + } else { + + // DatePicker action + function avail(date) { + m = (date.getMonth()+1); + if (m < 10) { + m = '0' + m; + } + d = date.getDate(); + if (d < 10) { + d = '0' + d; + } + y = date.getFullYear(); + var mdy = m + '/' + d + '/' + y; + if (inventory[mdy]) { + if (inventory[mdy]['tooLate']) { + return [false,"","Not Available"]; + } else { + return [true,"","Available"]; + } + } else { + return [false,"","Not Available"]; + } + } + + // Use the date picker to select a date + if($('#GLMeventDateInput_' + ticket.id).length > 0) { + $('#GLMeventDateInput_' + ticket.id).datepicker({ + beforeShowDay: avail, + dateFormat: "mm/dd/yy", + minDate: ticket.startDate, + maxDate: ticket.endDate, + onSelect: function(selectedDate, inst) { + // Get data for the selected date + dateData = inventory[selectedDate]; + $('#GLMeventInvID_' + ticket.id).val(dateData.id); + doQuantSelection(ticket.id, dateData.id, dateData.available, dateData.tooLate); + } // Date Selection + + }); // Date Picker + } + + } + + } // if have future inventory + + }); // each ticket + + function doQuantSelection(id, invId, available, tooLate) { + + // Build the ticket quant options + var ticketQuants = ''; + var selectMax = available; + if (selectMax > 50) { + selectMax = 50; + } + + if (tooLate) { + $('#GLMticketQuantContainer_' + id).html(ticketTooLate.replace(/\[hours\]/g, {performanceDetail.purch_leadtime})); + } else { + // note that the braced lte below is needed to inject a less-than-or-equal-to operator without having flexy chew on it. + for (var i = 1; i {lte:h} (selectMax*1); i++) { + ticketQuants = ticketQuants.concat(''); + } + + // Populate the ticket quantity container + tmpQuantSel = ticketQuantSelection.replace(/\[id\]/g, id); + $('#GLMticketQuantContainer_' + id).html(tmpQuantSel.replace(/\[ticket-quants\]/g, ticketQuants)); + } + + } + + var selectButtonPressed = false; + + $('.GLMselectButton').click(function() { + // Prevent multiple submissions + if (selectButtonPressed == true) { + return; + } + + // Check for a selected ticket + var ticketSelected = false; + $('.glmTicketQuant').each(function( index ) { + if ($(this).val() != '') { + ticketSelected = true; + } + }); + + if (ticketSelected) { + selectButtonPressed = true; + setBlocker(); + $('#GLMselectForm').submit(); + } else { + alert('Please select a {term.ticket.norm} quantity.') + return false; + } + + }); + + function setBlocker() { + $('#glmReloadBlocker').show(); + } + if( $(window).width() < 768 ){ + $('.glmBlock').not(":first").each(function() { + var left = $(this).find( $('.glmBlockContentLeft') ); + left.prependTo( $(this) ).find( $('glmBlockContentRight') ); + }); + } + }); + +{end:} + diff --git a/views/front/PointerBoat/foot.html b/views/front/PointerBoat/foot.html new file mode 100755 index 0000000..36eb69f --- /dev/null +++ b/views/front/PointerBoat/foot.html @@ -0,0 +1,9 @@ + +{if:option.development} +

    + Running on Development Server: + + Reset Session + +

    +{end:} \ No newline at end of file diff --git a/views/front/PointerBoat/head.html b/views/front/PointerBoat/head.html new file mode 100755 index 0000000..2b09b3e --- /dev/null +++ b/views/front/PointerBoat/head.html @@ -0,0 +1,38 @@ + +{startScript:h} + // Pass some reference parameters to JAVAScript + var baseSiteURL = '{baseURL}'; + var baseAppURL = '{baseAppURL}'; + +{if:!jQueryLoaded} + +{end:} +{if:!jQueryUiLoaded} + + +{end:} + + + +{if:customCssFile} + + +{end:} +{if:frontDebug} + +
    +{end:} +{startScript:h} + var disp_setting="toolbar=no,location=no,directories=no,menubar=no,scrollbars=yes,width=1000, height=700, left=100, top=25"; + {if:frontDebug} + debugWindowFront = window.open("{baseURL}index.php?Action=Debug_update","emDebugWindowFront",disp_setting); + {end:} + + +
    +
    Updating your information
    Please wait ...
    +
    + + {if:adminUser} +

    Purchasing By Admin User

    + {end:} diff --git a/views/front/PointerBoat/index.html b/views/front/PointerBoat/index.html new file mode 100755 index 0000000..9f04bbb --- /dev/null +++ b/views/front/PointerBoat/index.html @@ -0,0 +1,34 @@ + + + + + + + + + + +

    PLEASE NOTE:

    + +

    + There is no general access to this site. + All access to this site should be through an appropriate link. + If you arrived here by mistake (or exploring), nothing but this message will be displayed. + If you have any concerns about this site, please contact Gaslight Media. +

    + +

    + Gaslight Media
    + 120 East Lake Street
    + Petoskey, MI 49770
    +  
    + Phone: 231-487-0692
    + E-Mail: info@gaslightmedia.com
    + Web: http://www.gaslightmedia.com +

    + + + + + + diff --git a/views/front/SaultSteMarie/Debug/index.html b/views/front/SaultSteMarie/Debug/index.html new file mode 100755 index 0000000..a42397f --- /dev/null +++ b/views/front/SaultSteMarie/Debug/index.html @@ -0,0 +1,42 @@ + + + + + + +
    Startup: {debugStartupTime}
    +
    Event Management Front-End Debug
    +
    +
    + Updated: {debugUpdateTime} +
    +
    + {debugData:h} +
    + + + {startScript:h} + + // Reload the current window with Action = Debug_update + function reloadDebugWindow() + { + window.location("{baseSCRIPT}&Action=Debug_update"); + } + + + \ No newline at end of file diff --git a/views/front/SaultSteMarie/Debug/start.html b/views/front/SaultSteMarie/Debug/start.html new file mode 100755 index 0000000..66c3023 --- /dev/null +++ b/views/front/SaultSteMarie/Debug/start.html @@ -0,0 +1,27 @@ + + + + + + +
    Startup: {debugStartupTime}
    +
    Event Management Front-End Debug
    +
    +
    Debug Startup
    + + \ No newline at end of file diff --git a/views/front/SaultSteMarie/Shop/PayPalApproved.html b/views/front/SaultSteMarie/Shop/PayPalApproved.html new file mode 100755 index 0000000..f4b3996 --- /dev/null +++ b/views/front/SaultSteMarie/Shop/PayPalApproved.html @@ -0,0 +1,41 @@ + + + + + +
    + +

    Your PayPal payment has been approved.

    + + +
    + +

    + Your cart will now reflect that the payment has been made. +

    + +
    + +
    +
    Close This Window
    +
    + +
    + + + + diff --git a/views/front/SaultSteMarie/Shop/PayPalFail.html b/views/front/SaultSteMarie/Shop/PayPalFail.html new file mode 100755 index 0000000..a3bb3c8 --- /dev/null +++ b/views/front/SaultSteMarie/Shop/PayPalFail.html @@ -0,0 +1,49 @@ + + + + + +
    + +

    Unable to process your payment!

    + + +
    + +

    +

    Sorry, there was a problem.
    +

    + +

    + We were unable to find your purchase information and are therefore + are unable to process your payment through PayPal. This could be + due to you not performing any action with your pending purchase + for too long. Please click the "Return to selected tickets" button + at the top of the checkout page to see if your selections are still listed. +

    + +
    + +
    +
    Close This Window
    +
    + +
    + + + + diff --git a/views/front/SaultSteMarie/Shop/additionalInfo.html b/views/front/SaultSteMarie/Shop/additionalInfo.html new file mode 100644 index 0000000..5c50a8a --- /dev/null +++ b/views/front/SaultSteMarie/Shop/additionalInfo.html @@ -0,0 +1,246 @@ + + + +
    + + + +
    +
    + + + {term.nav.show_selected} + {if:!option.ticket_shop.start_at_cart} + {term.nav.select_more} + {end:} + + +

    {cartText:h}

    + +
    +
    + +{if:reason} + + + +
    +
    +
    +

    We're sorry, we had a problem with your request:

    +
      + {foreach:reason,r}{Chuck} +
    • {r:h}
    • + {end:} +
    +
    +
    +
    +{end:} + + + +{foreach:cart,c} + + {if:option.show_location_blocks} +
    +
    +
    +
    +

    {c.name:h}

    +
    + {end:} + + + + + {if:c.needAssignemntOrDate} + {if:c.needAssignment} + +
    + {if:!c.haveAssignment} +
    {text.cart.select_assignment_location}
    + {else:} +
    {text.cart.select_assignment_location}
    + {end:} + {foreach:c.assignmentMembers,a} + {if:a.entrances} + {foreach:a.entrances,e} +
    + {if:option.cart_images} + {if:e.image} +
    + {end:} + {end:} +
    + {if:e.selected} + {a.name} - {e.name}
    + {else:} + {a.name} - {e.name}
    + {end:} +
    +
    {e.addr1}{if:e.addr2}, {e.addr2}{end:}, {e.city}
    +
    {e.phone}
    + {if:e.descr} +
    {e.descr:h}
    + {end:} +
    +
    + {end:} +
    + {else:} + {if:a.selected} + {a.name}
    + {else:} + {a.name}
    + {end:} + {end:} + {end:} +  
    + {end:} + + {if:option.ask_for_likely_date} + {if:c.needLikelyDate} +
    +

    + {if:!c.likelyDate} + + {else:} + + {end:} + {text.cart.select_likely_date}   + + mm/dd/yyyy + {if:text.cart.select_likely_date_explain} +
    {text.cart.select_likely_date_explain} + {end:} +

    +
    + {end:} + {end:} +
    +
    + {end:} + {if:!c.needAssignment} + + {if:option.cart_images}{if:c.image} +
    + + +
    + {end:}{end:} + {end:} + +
    +
    +
    + +{end:} + + + +{if:cartHasContents} +
    +
    + {if:!blockCheckout} + {term.nav.checkout} + {else:} + Please complete the items in RED above. + {end:} +
    +
    +{else:} +
    +
    +

    Your cart is currently empty.

    +
    +
    +{end:} + + + + + + + + + diff --git a/views/front/SaultSteMarie/Shop/cart.html b/views/front/SaultSteMarie/Shop/cart.html new file mode 100755 index 0000000..4fbe846 --- /dev/null +++ b/views/front/SaultSteMarie/Shop/cart.html @@ -0,0 +1,415 @@ + + + +
    +
    + + +
    + + +
    + {if:!option.ticket_selection.start_at_cart} + {term.nav.select_more} + {end:} + +
    +
    + +
    {cartText:h}
    + {if:reason} +
    +
    We're sorry, we had a problem with your request:
    +
      + {foreach:reason,r}{Chuck} +
    • {r:h}
    • + {end:} +
    +
    + {end:} + {if:havePromoCodes} +
    +
    +
    If you have a {term.promo.norm}, please enter it here:
    +
    +
    + {end:} + {foreach:cart,c} +
    +
    {c.name}
    +
    + {foreach:c.performances,p} +
    +
    + {if:!option.ticket_selection.start_at_cart} + {term.nav.select_more_of_these} + {end:} +
    + +
    {p.name}
    +
    + {if:p.descr}
    {p.descr:h}
    {end:} + {if:p.short_descr}
    {p.short_descr:h}
    {end:} + {if:option.cart_images}{if:p.image} + + {end:}{end:} +
    +
    +
    +
    + {foreach:p.dates,d} +
    + {if:d.dateSpecific} + {d.fullDate} + {else:} + + {if:c.likelyDate} + - Likely Date {c.likelyDate} + {end:} + {end:} + {foreach:d.sections,s} + + + + {if:!p.oneSectionOnly} + + {end:} + + + + + {foreach:s.tickets,i} + + + {if:!p.oneSectionOnly} + + {end:} + + + + + {if:i.problem} + + + + {end:} + {if:i.descr} + + + {if:!p.oneSectionOnly} + + + {end:} + + {foreach:i.addons,a} + + + {if:!p.oneSectionOnly} + + {end:} + + + + + {end:} + + + {if:i.promo} + + + {if:!p.oneSectionOnly} + + {end:} + + + + {end:} + + {end:} +
    QuantSection{term.ticket.cap}PriceTotal
    + + {s.name}{i.title}{if:i.show_price}{i.price}{end:}{if:i.show_price}{i.extended}{end:}
     {i.problemText}
      + {else:} + + {end:} + {if:option.cart_images}{if:i.image} +
    + {end:}{end:} +
    {i.descr:h}
    +
       +
    + +
    +
    {a.unit_cost}/{a.unit_name}{a.money}
      {term.promo.cap}: {promoCode}  + {i.promo.credit}
    + {end:} +
    + {end:} +
    +
    + {end:} +
    + {if:c.ticket_policy}
    {c.ticket_policy:h}
    {end:} + +{if:option.ask_for_assignment_and_likely_date} + {if:c.needAssignemntOrDate} + {if:c.needAssignment} + +
    + {if:!c.haveAssignment} +
    {text.cart.select_assignment_location}
    + {else:} +
    {text.cart.select_assignment_location}
    + {end:} + {foreach:c.assignmentMembers,a} + {if:a.entrances} + {foreach:a.entrances,e} +
    + {if:option.cart_images} + {if:e.image} +
    + {end:} + {end:} +
    + {if:e.selected} + {a.name} - {e.name}
    + {else:} + {a.name} - {e.name}
    + {end:} +
    +
    {e.addr1}{if:e.addr2}, {e.addr2}{end:}, {e.city}
    +
    {e.phone}
    + {if:e.descr} +
    {e.descr:h}
    + {end:} +
    +
    + {end:} +
    + {else:} + {if:a.selected} + {a.name}
    + {else:} + {a.name}
    + {end:} + {end:} + {end:} +  
    + {end:} + + {if:option.ask_for_likely_date} + {if:c.needLikelyDate} +
    + {if:!c.likelyDate} + + {else:} + + {end:} + {text.cart.select_likely_date}   + + mm/dd/yyyy +
    + {end:} + {end:} +
    +
    + {end:} + {if:!c.needAssignment} + + {if:option.cart_images}{if:c.image} +
    + + +
    + {end:}{end:} + {end:} +{end:} + + +
    + {end:} + + +
    + {if:cartHasContents} +
    + Grand Total   {totals.price} +
    +
    + {if:totals.tickets} + + {term.nav.checkout} + + {else:} + Your cart is currently empty. + {end:} +
    + {else:} +

    Your cart is currently empty.

    + {end:} +
    + + {if:option.cart_promotions} +
    + You may also be interested in ...
    + {foreach:cartPromotions,p} +
    + + {if:p.image} +
    + {end:} +
    + {if:p.start_date} +

    + Dates: {p.start_date.date} +

    + {end:} + + {if:p.short_descr}
    {p.short_descr:h}
    {end:} + {if:p.short_descr}
    {p.short_descr:h}
    {end:} +
    +
    + {end:} +
    + {end:} + + + +
    + +{startScript:h} + + $(document).ready(function(){ + + // Block direct form submission - Everything submits by jQuery action + $('#cartForm').submit(function( event ) { + return false; + }); + + // Convert input fields to select lists + $('.glmCartQuant').each(function() { + + var id = $(this).attr('id'); + var ticket = $(this).attr('data-ticket'); + var addon = $(this).attr('data-addon'); + var max = $(this).attr('data-max'); + var value = $(this).attr('value'); + var units = $(this).attr('data-units'); + var numbSel = ''; + + // Build a picklist for this input + for (var i = 0 ; i {lte:h} max ; i++) { + if (value == i) { + numbSel = numbSel.concat(''); + } else { + numbSel = numbSel.concat(''); + } + } + + $('#quant_' + id).html('' + units); + + }); + + // Get or set vertical scroll to return to same place when cart reloads + function getVertScroll() { + var vertScroll = window.pageYOffset; + if (vertScroll == 0) { + var vertScroll = document.documentElement.scrollTop; + } + if (vertScroll == 0) { + var vertScroll = document.body.scrollTop; + } + return vertScroll; + } + + // When a cart value changes, submit it as a cart update. + $('.glmCartSelect').change(function() { + vertScroll = getVertScroll(); + var ticket = $(this).attr('data-ticket'); + var addon = $(this).attr('data-addon'); + var value = $(this).val(); + + setBlocker(); + window.location = "{baseSCRIPT}&Action=Shop_cart&cart=update&ticket_inv=" + ticket + "&addon=" + addon + "&quant=" + value + "&vertScroll=" + vertScroll; + + }); + + // When there's a change in the promo code input, submit it. + $('#promoCodeInput').change(function() { + var value = $(this).val(); + setBlocker(); + window.location = "{baseSCRIPT}&Action=Shop_cart&cart=promo_code&promo_code=" + value; + }); + + // When a member selection for unassigned items changes, submit it so it's in the session + $('.glmAssignmentChange').change(function() { + vertScroll = getVertScroll(); + var member = $(this).attr('data-Member'); + var assignedTo = $(this).val(); + var assignedToEntrance = $(this).attr('data-entrance'); + setBlocker(); + window.location = "{baseSCRIPT}&Action=Shop_cart&cart=update_assignment&member_assigned=" + member + "&assigned_to=" + assignedTo + "&entrance_assigned=" + assignedToEntrance + "&vertScroll=" + vertScroll; + }); + + // When a likely departure date changes, submit it so it's in the session + $('.glmLikelyDateChange').change(function() { + vertScroll = getVertScroll(); + var member = $(this).attr('data-Member'); + var likelyDate = $(this).val(); + setBlocker(); + window.location = "{baseSCRIPT}&Action=Shop_cart&cart=update_likelyDate&member=" + member + "&likely_date=" + likelyDate + "&vertScroll=" + vertScroll; + + }); + + // Code to start datepicker for each date input + if($("#likelyDateInput").length > 0) { + $("#likelyDateInput").datepicker({ + dateFormat: "mm/dd/yy", + minDate: -1, + maxDate: 365 + }); + } + + // Checkout action + $('#GLMcheckoutBtn').click(function() { + setBlocker(); + window.location = "{baseSCRIPT}&Action=Shop_checkout"; + }); + + function setBlocker() { + $('#glmReloadBlocker').show(); + } + + $('#GLMnavSelectEvent').on('click', function() { // Return to Event Selection + setBlocker(); + window.location = '{startURL:h}'; + }); + +/* Not using right now + // Reprint order button + $('#reprintVoucher').on('keypress', function(event) { + if(event.which == '13'){ + var orderID = $(this).val(); + var voucherWindow = window.open('{appAdminURL}&Action=Order_printVoucher&OrderID=' + orderID, + "voucherPrint", + "height=750,width=600,menubar=yes,toolbar=yes,alwaysRaised=yes,menu" + ); + voucherWindow.focus(); + voucherWindow.print(); + return false; + } + }); +*/ + + if ({vertScroll}) { + window.scrollTo(0,{vertScroll}); + } + + }); + + + diff --git a/views/front/SaultSteMarie/Shop/checkout.html b/views/front/SaultSteMarie/Shop/checkout.html new file mode 100755 index 0000000..b4a0e49 --- /dev/null +++ b/views/front/SaultSteMarie/Shop/checkout.html @@ -0,0 +1,885 @@ + + + +
    + +
    +
    Selected {term.ticket.plur_cap}
    + +
    + {term.nav.show_selected} + {if:!option.ticket_selection.start_at_cart} + {term.nav.select_more} + {end:} +
    +
    + +
    {checkoutText:h}
    + {if:reason} +
    +
    We're sorry, we had a problem with your request:
    +
      + {foreach:reason,r} +
    • {r:h}
    • + {end:} +
    +

    See below for more information.

    +
    + {end:} +
    + + +
    +
    Contact Information
    + +
    +
    +
    {text.cart.checkout.first_name}:
    +
    {text.cart.checkout.first_name}:
    + {if:formData.contact.fname.problem} +
    +
    {formData.contact.fname.problem}
    + {else:} +
    + {end:} + +
    +
    +
    +
    {text.cart.checkout.last_name}:
    +
    {text.cart.checkout.last_name}:
    + {if:formData.contact.lname.problem} +
    +
    {formData.contact.lname.problem}
    + {else:} +
    + {end:} + +
    +
    +
    +
    {text.cart.checkout.address}:
    +
    {text.cart.checkout.address}:
    + {if:formData.contact.addr1.problem} +
    +
    {formData.contact.addr1.problem}
    + {else:} +
    + {end:} + +
    +
    +
    +
     
    +
     
    + {if:formData.contact.addr2.problem} +
    +
    {formData.contact.addr2.problem}
    + {else:} +
    + {end:} + +
    +
    +
    +
    {text.cart.checkout.city}:
    +
    {text.cart.checkout.city}:
    + {if:formData.contact.city.problem} +
    +
    {formData.contact.city.problem}
    + {else:} +
    + {end:} + +
    +
    +
    +
    {text.cart.checkout.state}:
    +
    {text.cart.checkout.state}:
    + {if:formData.contact.state.problem} +
    +
    {formData.contact.state.problem}
    + {else:} +
    + {end:} + +
    +
    +
    +
    {text.cart.checkout.country}:
    +
    {text.cart.checkout.country}:
    + {if:formData.contact.country.problem} +
    +
    {formData.contact.country.problem}
    + {else:} +
    + {end:} + +
    +
    +
    +
    {text.cart.checkout.zip}:
    +
    {text.cart.checkout.zip}:
    + {if:formData.contact.zip.problem} +
    +
    {formData.contact.zip.problem}
    + {else:} +
    + {end:} + +
    +
    +
    +
    {text.cart.checkout.phone}:
    +
    {text.cart.checkout.phone}:
    + {if:formData.contact.phone.problem} +
    +
    {formData.contact.phone.problem}
    + {else:} +
    + {end:} + +
    +
    +
    +
    {text.cart.checkout.email}:
    +
    {text.cart.checkout.email}:
    + {if:formData.contact.email.problem} +
    +
    {formData.contact.email.problem}
    + {else:} +
    + {end:} + +
    +
    +
    +
    {text.cart.checkout.email_again}:
    +
    {text.cart.checkout.email_again}:
    + {if:formData.contact.email2.problem} +
    +
    {formData.contact.email2.problem}
    + {else:} +
    + {end:} + +
    +
    +
    +
    OK to Send E-Mail?
    + {if:formData.contact.email_ok} +
    {text.cart.checkout.activities_offers}
    + {else:} +
    {text.cart.checkout.activities_offers}
    + {end:} +
    + + {if:opt_field_1_name} +
    +
    {opt_field_1_name}:
    +
    {opt_field_1_name}:
    + {if:formData.contact.opt_field_1.problem} +
    +
    {formData.contact.opt_field_1.problem}
    + {else:} +
    + {end:} + +
    +
    + {end:} + {if:opt_field_2_name} +
    +
    {opt_field_2_name}:
    +
    {opt_field_2_name}:
    + {if:formData.contact.opt_field_2.problem} +
    +
    {formData.contact.opt_field_2.problem}
    + {else:} +
    + {end:} + +
    +
    + {end:} + {if:opt_field_3_name} +
    +
    {opt_field_3_name}:
    +
    {opt_field_3_name}:
    + {if:formData.contact.opt_field_3.problem} +
    +
    {formData.contact.opt_field_3.problem}
    + {else:} +
    + {end:} + +
    +
    + {end:} + + +
    +
    + + {foreach:cart,c} + {if:c.performances} +
    +
    {term.prop.cap}: {c.name}
    + + +
    + + {foreach:c.performances,p} +
    +
    +
    +
    +
    {p.name}
    +
    + + {if:option.cart_images}{if:option.cart_images}{if:p.image}{end:}{end:}{end:} +
    +
    +
    +
    + {foreach:p.dates,d} +
    +
    + + {if:d.dateSpecific} + {d.fullDate} + {else:} + + {if:c.likelyDate} + - Likely Date {c.likelyDate} + {end:} + {end:} + +
    + + + {foreach:d.sections,s} + + + + {if:!p.oneSectionOnly} + + {end:} + + + + + {foreach:s.tickets,i} + + + {if:!p.oneSectionOnly} + + {end:} + + + + + {if:i.descr} + + + {if:!p.oneSectionOnly} + + + {end:} + + {foreach:i.addons,a} + + + {if:!p.oneSectionOnly} + + {end:} + + + + + {end:} + + {if:i.promo} + + + {if:!p.oneSectionOnly} + + {end:} + + + + {end:} + {end:} +
    QuantSection{term.ticket.cap}PriceTotal
    + {i.selected} + {s.name}{i.title}{if:i.show_price}{i.price}{end:}{if:i.show_price}{i.extended}{end:}
      + {else:} + + {end:} + {if:option.cart_images} + {if:i.image} +
    + {end:} + {end:} +
    {i.descr:h}
    +
       +
    + {a.selected} {a.unit_name} +
    +
    {a.unit_cost}/{a.unit_name}{a.money}
      {term.promo.cap}: {promoCode}  + {i.promo.credit}
    + {end:} +
    + {end:} +
    +
    + {if:p.policy} +
    +
    + Please read and agree to our policy for this {term.performance.norm}. +
    +
    +

    {p.policy:h}

    +
    +
    +

    I agree to the policy stated above.

    +
    +
    + {end:} +
    + {end:} +
    + + {if:c.ticket_policy}
    {c.ticket_policy:h}
    {end:} + {if:c.ticket_policy}
    {c.ticket_policy:h}
    {end:} + +
    + + {if:c.ticket_spec_req.value} +
    +
    Please enter any special requests:
    +
    +
    + {end:} + + + {if:!formData.centralPayment} +
    + + {if:c.paymentResult} + {if:c.paymentResult.approved} +
    Card Payment Approved
    +
    Card Type
    {c.paymentResult.cctype}
    +
    Name on Card
    {c.paymentResult.ccname}
    +
    Card Number
    {c.paymentResult.ccnumb}
    +
    Expiration Date
    {c.paymentResult.ccexp}
    +
    Authorization Code
    {c.paymentResult.authCode}
    +
    +
    {term.nav.print_vouchers}
    +
    + {else:} +
    Card Payment Not Complete
    +
    • {c.paymentResult.description}
    +

    Please check the payment information below and try again or contact your credit card company for assistance.

    + {if:forceCheckoutPhase} +
    +
    {term.nav.delete_from_cart}
    +
    + {end:} + {end:} + {end:} + {if:c.paymentResult.approved} +

    Payment Accepted

    + {else:} + {if:c.havePaymentMethod} + +
    + {if:c.havePayPal} + {if:c.haveMultiplePaymentMethods} +  PayPal + {else:} + + {end:} + {end:} + {if:c.haveCreditCards} + {if:c.havePayPal} +      + {end:} + {if:c.haveMultiplePaymentMethods} +  Credit Card + {else:} + + {end:} + {end:} +
    + + {if:c.haveCreditCards} + {if:c.haveMultiplePaymentMethods} + + {else:} + + {end:} +
    +
    Total Charged to this Card
    +
    {c.totalPrice}
    +
    +
    +
    Card Type
    +
    Card Type
    + {if:c.paymentForm.cctype.problem} +
    +
    {c.paymentForm.cctype.problem}
    + {else:} +
    + {end:} + +
    +
    +
    +
    Name on Card
    +
    Name on Card
    + {if:c.paymentForm.ccname.problem} +
    +
    {c.paymentForm.ccname.problem}
    + {else:} +
    + {end:} + +
    +
    +
    +
    Card Number
    +
    Card Number
    + {if:c.paymentForm.ccnumb.problem} +
    +
    {c.paymentForm.ccnumb.problem}
    + {else:} +
    + {end:} + +
    +
    +
    +
    Expiration Date
    +
    Expiration Date
    + {if:c.paymentForm.ccexp.problem} +
    +
    {c.paymentForm.ccexp.problem}
    + {else:} +
    + {end:} + Month + + Year + +
    +
    +
    +
    Security Code
    +
    Security Code
    + {if:c.paymentForm.cccode.problem} +
    +
    {c.paymentForm.cccode.problem}
    + {else:} +
    + {end:} + +
    +
    +
    +
    + The Security Code is the three or four digit number on the signature side of your credit card. +
    +
    + + {end:} + {if:c.havePayPal} + + {if:c.haveMultiplePaymentMethods} + + {else:} + + {end:} +
    + +
    +
    + {end:} + {if:c.haveMultiplePaymentMethods} + +
    Please select a Payment Method
    +
    + {end:} + {else:} + +
    + This {term.prop.norm} does not have a payment method configured. + Please call this {term.prop.norm} to purchase {term.ticket.plur}. +
    +
    + {end:} + {end:} + +
    +
    + + {end:} +
    +
    + {end:} + + {if:!cartRequiresPayment} + + {end:} + + {end:} + +{if:cartRequiresPayment} + {if:formData.centralPayment} + +
    + + {if:formData.centralPayment.havePaymentMethod} + + {foreach:formData.centralPayment.paymentForm,p} + + {if:p.cctype} + + + +
    +
    + {if:formData.centralPayment.haveMultiplePaymentMethods} +  Credit Card + {else:} + + {end:} +
    +
    +
    +
    Card Type
    +
    Card Type
    +
    + +
    +
    +
    +
    Name on Card
    +
    Name on Card
    + {if:p.ccname.problem} +
    +
    {p.ccname.problem}
    + {else:} +
    + {end:} + +
    +
    +
    +
    Card Number
    +
    Card Number
    + {if:p.ccnumb.problem} +
    +
    {p.ccnumb.problem}
    + {else:} +
    + {end:} + +
    +
    +
    +
    Expiration Date
    +
    Expiration Date
    + {if:p.ccexp.problem} +
    +
    {p.ccexp.problem}
    + {else:} +
    + {end:} + Month + + Year + +
    +
    +
    +
    Security Code
    +
    Security Code
    + {if:p.cccode.problem} +
    +
    {p.cccode.problem}
    + {else:} +
    + {end:} + +
    +
    +
    +
    + The Security Code is the three or four digit number on the signature side of your credit card. +
    +
    + + {if:p.haveMultiplePaymentMethods} + +
    Please select a Payment Method
    +
    + {end:} + + {end:} + {end:} + +
    + + {else:} + +
    + This {term.prop.norm} does not have a payment method configured. + Please call this {term.prop.norm} to purchase {term.ticket.plur}. +
    +
    + + {end:} + + {end:} + +{end:} + + + +
    + {if:cartRequiresPayment} +
    +
    Complete Purchase
    + +

    + {ssl_seal_head_script:h} + {ssl_seal_body_script:h} +

    +
    + {else:} +
    +
    No Payment Required
    +
    + {end:} +
    +
    + {if:cartRequiresPayment} + +
    + +
    Grand Total
    +
    +
    + +
    {totals.price}
    +
    + {end:} +
    + {if:!cartHasOneVenueOnly} + + {end:} + + {if:adminUser} +
    + No payment info required for Admin User. +
    + {end:} + +
    + {if:!blockCheckout} + {term.nav.purchase} + {else:} + Unable to checkout - please see above. + {end:} +
    +
    +
    + +
    + + + + + + diff --git a/views/front/SaultSteMarie/Shop/checkoutSuccess.html b/views/front/SaultSteMarie/Shop/checkoutSuccess.html new file mode 100755 index 0000000..32e7a7f --- /dev/null +++ b/views/front/SaultSteMarie/Shop/checkoutSuccess.html @@ -0,0 +1,367 @@ + + + + + +
    + + +
    Purchase Complete
    + + + + + {foreach:cart,c} + {if:c.paymentResult} + {if:c.paymentResult.approved} +

    +

    *** {term.nav.print_vouchers} for {c.name} ***
    +

    + {end:} + {end:} + {end:} + + + +
    +
    + +
    +
    + +

    + Adobe Reader is required to view and print your {term.voucher.plur}. Adobe Reader is a free program available directly from Adobe. + If you do not already have Adobe Reader installed, click the "Get Adobe Reader" link now. +

    +
    +
    +
    + +

    + If you are unable to print your {term.voucher.plur}, please print this page or write down the order number(s) + below and bring that to the ticket office when you arrive. +

    + ORDER #: + {foreach:cart,c} + {if:c.paymentResult} + {if:c.paymentResult.approved} + {c.paymentResult.orderID}  + {end:} + {end:} + {end:} +
    +
    +
    + + +
    {successText:h}
    + +
    +
    Contact Information
    +
    +
    First Name:
    {formData.contact.fname.value}
    +
    Last Name:
    {formData.contact.lname.value}
    +
    Address:
    {formData.contact.addr1.value}
    +
     
    {formData.contact.addr2.value}
    +
    City:
    {formData.contact.city.value}
    +
    State:
    {formData.contact.state.value}
    +
    Country:
    {formData.contact.country.value}
    +
    ZIP/Postal Code:
    {formData.contact.zip.value}
    +
    Phone:
    {formData.contact.phone.value}
    +
    E-Mail address:
    {formData.contact.email.value}
    + {if:opt_field_1_name}
    {opt_field_1_name}:
    {formData.contact.opt_field_1.value:h}
    {end:} + {if:opt_field_2_name}
    {opt_field_2_name}:
    {formData.contact.opt_field_2.value:h}
    {end:} + {if:opt_field_3_name}
    {opt_field_3_name}:
    {formData.contact.opt_field_3.value:h}
    {end:} +
     
    + {if:formData.contact.email_ok} + You have asked us to send information on activities and offers. + {else:} + You have asked us to NOT send information on activities and offers.
    + We will only contact you regarding this order. + {end:} +
    + +
    + +
    + + + {foreach:cart,c} +
    + +
    {term.ticket.plur_cap} at: {c.name}
    + + +
    + {if:c.descr}
    {c.descr:h}
    {end:} + {if:option.cart_images}{if:c.image}{end:}{end:} + +
    + +
    + + {foreach:c.performances,p} + +
    + +
    +
    +
    + {term.performance.cap}: {p.name} +
    +
    + + {if:option.cart_images}{if:option.cart_images}{if:p.image}{end:}{end:}{end:} +
    +
    +
    + +
    + {foreach:p.dates,d} + +
    + {term.ticket.cap} date: + + {if:d.dateSpecific} + {d.fullDate} + {else:} + Use any date + {if:c.likelyDate} + - Likely Date {c.likelyDate} + {end:} + {end:} + +
    + + + {foreach:d.sections,s} + + + + {if:!p.oneSectionOnly} + + {end:} + + + + + {foreach:s.tickets,i} + + + {if:!p.oneSectionOnly} + + {end:} + + + + + {if:i.descr} + + + {if:!p.oneSectionOnly} + + + {end:} + + {foreach:i.addons,a} + + + {if:!p.oneSectionOnly} + + {end:} + + + + + {end:} + + {if:i.promo} + + + {if:!p.oneSectionOnly} + + {end:} + + + + {end:} + {end:} +
    QuantSection{term.ticket.cap}PriceTotal
    + {i.selected} + {s.name}{i.title}{if:i.show_price}{i.price}{end:}{if:i.show_price}{i.extended}{end:}
      + {else:} + + {end:} + {if:option.cart_images} + {if:i.image} +
    + {end:} + {end:} +
    {i.descr:h}
    +
       +
    + {a.selected} {a.unit_name} +
    +
    {a.unit_cost}/{a.unit_name}{a.money}
      {term.promo.cap}: {promoCode}  + {i.promo.credit}
    + {end:} + + + {end:} + +
    + +
    + + {if:p.policy} +
    +
    +
    + Our policy for this {term.performance.norm}. +
    +

    {p.policy:h}

    +
    +
    + {end:} + + {end:} + +
    + + + + {if:!cartHasOneVenueOnly} + +
    +
    +
    +
    Sub Total
    +
    +
    +
    {c.totalPrice}
    +
    +
    +
    + {end:} + + {if:c.ticket_policy}
    {c.ticket_policy:h}
    {end:} + + + {if:c.ticket_policy}
    {c.ticket_policy:h}
    {end:} + + +
    + + + {if:c.ticket_spec_req.value} +
    +
    Special requests:
    +
    {c.paymentForm.spec_req.value:h}
    +
    + {end:} + + + {if:c.paymentResult} +
    + {if:c.paymentResult.approved} +
    Card Payment Approved
    + +
    Card Type
    {c.paymentResult.cctype}
    +
    Name on Card
    {c.paymentResult.ccname}
    +
    Card Number
    {c.paymentResult.ccnumb}
    +
    Expiration Date
    {c.paymentResult.ccexp}
    +
    Authorization Code
    {c.paymentResult.authCode}
    +
    +
    {term.nav.print_vouchers}
    +
    + {else:} +
    Card Payment Not Complete
    +
    • {c.paymentResult.description}
    +

    Please check the payment information below and try again or contact your credit card company for assistance.

    + {if:forceCheckoutPhase} +
    +
    {term.nav.delete_from_cart}
    +
    + {end:} + + {end:} + +
    + {end:} + +
    + +
    + + {end:} + +
    + {if:cartHasContents} +
    +
    Cart Totals
    +
    +
    +
    Grand Total
    +
    +
    +
    {totals.price}
    +
    +
    +
    + {else:} +

    Your cart is currently empty.

    + {end:} +
    + +
    + +{trackingScript:h} + + + + + diff --git a/views/front/SaultSteMarie/Shop/paymentSummary.html b/views/front/SaultSteMarie/Shop/paymentSummary.html new file mode 100755 index 0000000..486954d --- /dev/null +++ b/views/front/SaultSteMarie/Shop/paymentSummary.html @@ -0,0 +1,118 @@ +

    + + Click here to reprint your {term.voucher.plur} + +

    + +

    + + {cartEntry.name} +

    + + + + + + + + + + + + + + +{foreach:cartForSummaryCentral,c} +{foreach:c.performances,p} + {foreach:p.dates,d} + {foreach:d.sections,s} + + + {foreach:s.tickets,i} + + + + + + + + {foreach:i.addons,a} + + + + + + + + {end:} + {if:i.promo} + + + + + + + {end:} + {end:} + + + {end:} + {end:} +{end:} + + + + + + + + +
    Quant{term.performance.cap}{term.ticket.cap}PriceTotal
    {i.selected}{p.name:h}{i.title:h}{if:i.show_price}{i.price}{end:}{if:i.show_price}{i.extended}{end:}
       +
    + {a.selected} {a.unit_name} +
    +
    {a.unit_cost}/{a.unit_name}{a.money}
      {term.promo.cap}: {promoCode}  + {i.promo.credit}
     {c.totalPrice}
    + + +{if:c.ticket_spec_req} +

    + {c.paymentForm.spec_req.value:h} +

    +{end:} + +{end:} + +{if:cartEntry.ticket_policy}

    {cartEntry.ticket_policy:h}

    {end:} + + + + + + + + + + + + +
    First Name:{formData.contact.fname.value}
    Last Name:{formData.contact.lname.value}
    Address:{formData.contact.addr1.value}
     {formData.contact.addr2.value}
    City:{formData.contact.city.value}
    State:{formData.contact.state.value}
    Country:{formData.contact.country.value}
    ZIP/Postal Code:{formData.contact.zip.value}
    Phone:{formData.contact.phone.value}
    E-Mail address:{formData.contact.email.value}
    + +

    + + + + + + + +
    Credit Card Payment Approved
    Card Type{cartEntry.paymentResult.cctype}
    Name on Card{cartEntry.paymentResult.ccname}
    Card Number{cartEntry.paymentResult.ccnumb}
    Expiration Date{cartEntry.paymentResult.ccexp}
    Authorization Code{cartEntry.paymentResult.authCode}
    +

    + + diff --git a/views/front/SaultSteMarie/Shop/sectionSelect.html b/views/front/SaultSteMarie/Shop/sectionSelect.html new file mode 100755 index 0000000..b9dd2fc --- /dev/null +++ b/views/front/SaultSteMarie/Shop/sectionSelect.html @@ -0,0 +1,96 @@ + + + + + + +
    + + +
    {term.section.cap} Selection
    + + + + + +
    {sectionText:h}
    + +{if:reason} +
    +
    We're sorry, we had a problem with your request:
    +
      + {foreach:reason,r} +
    • {r:h}
    • + {end:} +
    +
    +{end:} + +

    You have selected

    +
    +
    +
    +
    {performanceDetail.member_name}

    +
    {performanceDetail.name}
    +
    +
    + + +
    +
    +
    + + +
    +

    Please select from the following

    +
    +{foreach:sectionList,x} +
    + +
    +

    {term.section.cap}: {x.member_name}

    +

    {x.descr:h}

    +
    +
    +{end:} + +
    + +
    + + {startScript:h} + + $(document).ready(function(){ + + // Code to kick off the geolocation-display feature + $("#locationMap").geolocate({ + lat: "#lat", + lng: "#lon", + mapOptions: { + disableDefaultUI: false, + mapTypeControl: true, + mapTypeId: "roadmap", + zoom: 12 + }, + markerOptions: { + draggable: false, + title: "This is your selected location" + } + }); + + }); + + + diff --git a/views/front/SaultSteMarie/Shop/start-COPY.html b/views/front/SaultSteMarie/Shop/start-COPY.html new file mode 100644 index 0000000..feda2b4 --- /dev/null +++ b/views/front/SaultSteMarie/Shop/start-COPY.html @@ -0,0 +1,162 @@ + + +
    +
    +
    +
    +
    {m.name}
    +
    +
    +
    Address: {m.addr1}{if:m.addr2}, {m.addr2}{end:}, {m.city}
    +
    Phone #: {m.phone}
    +
    {m.descr:h}
    +
    +
    +
    +
    (map loads here)
    +
    + + +
    +
    + +
    + {foreach:m.performances,p} +
    +
    +
    +
    + {if:showTickets} + {p.name} + {else:} + {p.name} + {end:} +
    +
    +
    +
    {term.prop.cap}: {p.member_name}
    +
    Dates: {p.start_date.date} through {p.end_date.date}
    +
    +
    + {if:!showTickets} + {term.nav.select} + {end:} + + + {foreach:p.sections,s} +

     

    +
    +
    +
    + {if:!p.oneSectionOnly} + {s.sectionDetail.name}
    + {end:} + +
    + +
    +
    + + + {foreach:s.ticketsData,x} +
    + {if:option.ticket_selection.include_options_in_ticket_list} +
    +
    +
    Price: 
    +
    +
    {x.price}
    +
    +
    +
    +
    Select date: 
    +
    +
    + + +
    +
    +
    +
    +
    Quant: 
    +
    +
    (select date)
    +
    +
    +
    + + {end:} + +
    + {if:option.ticket_selection.include_options_in_ticket_list} +
    {x.title}
    + {else:} +
    + {x.name} +
    + {term.nav.select} + {end:} +
    +
    + {if:x.descr} +

    {x.descr:h}

    + {end:} +
    + {if:!x.date_specific.value} + Use any date{if:x.start_date.timestamp} from {x.start_date.date} to {x.end_date.date}{end:}{if:!x.time_specific.value}, {end:} + {end:} + {if:!x.time_specific.value} + Use any time of day, + {else:} + Time: {x.ticket_time.time}, + {end:} + {if:x.unlimted_use.value} + Each {term.ticket.norm} may be used an unlimited number of times + {else:} + + {end:} +
    +
    +
    + {if:option.ticket_selection.include_options_in_ticket_list} +
    +
    +
    Price each: 
    +
    +
    {x.price}
    +
    +
    +
    +
    Select date: 
    +
    +
    + + +
    +
    +
    +
    +
    Quant: 
    +
    +
    (select date)
    +
    +
    +
    + + {end:} +
    + + + {end:} + +
    + + {end:} + + + +
    + {end:} +
    +
    + {end:} diff --git a/views/front/SaultSteMarie/Shop/start.html b/views/front/SaultSteMarie/Shop/start.html new file mode 100755 index 0000000..6170b0d --- /dev/null +++ b/views/front/SaultSteMarie/Shop/start.html @@ -0,0 +1,398 @@ + + + +
    + +
    +
    {term.event.cap} Selection
    + + +
    + +
    {introText:h}
    + {if:reason} +
    +
    We're sorry, we had a problem with your request:
    +
      + {foreach:reason,r} +
    • {r:h}
    • + {end:} +
    +
    + {end:} +

    Please select from the following

    +{if:showTickets} +
    + + + + +{end:} + + {foreach:membersList,m} +
    +
    +
    +
    +
    {m.name}
    +
    +
    +
    Address: {m.addr1}{if:m.addr2}, {m.addr2}{end:}, {m.city}
    +
    Phone #: {m.phone}
    +
    {m.descr:h}
    +
    +
    + {if:option.select_images} + {if:m.image} +
    + {end:} + {end:} + +
    + {foreach:m.performances,p} +
    +
    +
    +
    + {if:showTickets} + {p.name} + {else:} + {p.name} + {end:} +
    +
    +
    + + {if:p.start_date.timestamp}
    Dates: {p.start_date.date}{if:p.end_date.timestamp} - {p.end_date.date} {end:}
    {end:} +
    {p.short_descr:h}
    +
    +
    + {if:option.select_images} + {if:p.image} +
    + {end:} + {end:} + {if:!showTickets} + + {end:} + + + + {foreach:p.sections,s} +

     

    +
    +
    +
    + {if:!p.oneSectionOnly} + {s.sectionDetail.name}
    + {end:} + +
    + +
    +
    + + + {foreach:s.ticketsData,x} +
    + {if:option.ticket_selection.include_options_in_ticket_list} +
    +
    +
    Price: 
    +
    +
    {x.price}
    +
    +
    +
    +
    Select date: 
    +
    +
    + + +
    +
    +
    +
    +
    Quant: 
    +
    +
    (select date)
    +
    +
    +
    + + {end:} + +
    + {if:option.ticket_selection.include_options_in_ticket_list} +
    {x.title}
    + {else:} +
    + {x.name} +
    + {term.nav.select} + {end:} +
    +
    + {if:x.descr} +

    {x.descr:h}

    + {end:} +
    + {if:!x.date_specific.value} + Use any date{if:x.start_date.timestamp} from {x.start_date.date} to {x.end_date.date}{end:}{if:!x.time_specific.value} {end:} + {end:} + {if:!x.time_specific.value} + Use any time of day, + {else:} + Time: {x.ticket_time.time}, + {end:} + {if:x.unlimted_use.value} + Each {term.ticket.norm} may be used an unlimited number of times + {else:} + + {end:} +
    +
    +
    + {if:option.ticket_selection.include_options_in_ticket_list} +
    +
    +
    Price each: 
    +
    +
    {x.price}
    +
    +
    +
    +
    Select date: 
    +
    +
    + + +
    +
    +
    +
    +
    Quant: 
    +
    +
    (select date)
    +
    +
    +
    + + {end:} +
    + + + {end:} + +
    + + {end:} + + + +
    + {end:} +
    +
    + {end:} +{if:showTickets} + +
    +{end:} +
    + +{startScript:h} + + var addButtonPushed = false; + + // Dates for inventory data + var tickets = {ticketsJSON:h}; + + var ticketQuantSelection = '\ + \ + '; + + var ticketTooLate = '\ +

    \ + Sorry, too late to select these {term.ticket.plur} on-line.\ +

    \ + '; + + + + $(document).ready(function(){ + + // Code to kick off the geolocation-display feature + function doLocationMap(id) { + $("#locationMap_" + id).geolocate({ + lat: "#lat_" + id, + lng: "#lon_" + id, + mapOptions: { + disableDefaultUI: false, + mapTypeControl: true, + mapTypeId: "roadmap", + zoom: 12 + }, + markerOptions: { + draggable: false, + title: "This is your selected location" + } + }); + } + {foreach:membersList,m} + doLocationMap({m.id}); + {end:} + + // DatePicker action + function avail(date) { + m = (date.getMonth()+1); + if (m < 10) { + m = '0' + m; + } + d = date.getDate(); + if (d < 10) { + d = '0' + d; + } + y = date.getFullYear(); + mdy = m + '/' + d + '/' + y; + if (dates[mdy]) { + return [true,"","Available"]; + } else { + return [false,"","Not Available"]; + } + } + + // for each ticket + $.each(tickets, function(index, ticket) { + + var inventory = ticket.inventory; + + // Build date data array and count dates for this ticket + var dateCount = 0; + var dateData = false + $.each(inventory, function(index, date) { + + // Count the number of dates + dateCount++; + + // If this is the first one, store it in case it's the only one + dateData = date; + + }); // each date + + // if there's no date specific tickets + if (!ticket.dateSpecific) { + + // Populate date input field + $('#GLMeventDateSelect_' + ticket.id).html(''); + doQuantSelection(ticket.id, dateData.id, dateData.available, dateData.tooLate); + + // if there's only one date, then display that and move on. + } else if (!ticket.dateSpecific || dateCount == 1) { + + // populate date input field + $('#GLMeventDate_' + ticket.id).html('
    Date:
    ' + dateData['date'] + '
    '); + doQuantSelection(ticket.id, dateData.id, dateData.available, dateData.tooLate); + + } else { + + // DatePicker action + function avail(date) { + m = (date.getMonth()+1); + if (m < 10) { + m = '0' + m; + } + d = date.getDate(); + if (d < 10) { + d = '0' + d; + } + y = date.getFullYear(); + mdy = m + '/' + d + '/' + y; + if (inventory[mdy]) { + return [true,"","Available"]; + } else { + return [false,"","Not Available"]; + } + } + + // Use the date picker to select a date + $('#GLMeventDateInput_' + ticket.id).datepicker({ + beforeShowDay: avail, + dateFormat: "mm/dd/yy", +// *** NEED TO FIX REFERENCE TO "performanceDetail" since that's not available on this page + minDate: "{performanceDetail.start_date.date}", + maxDate: "{performanceDetail.end_date.date}", + onSelect: function(selectedDate, inst) { + // Get data for the selected date + dateData = inventory[selectedDate]; + $('#GLMeventInvID_' + ticket.id).val(dateData.id); + doQuantSelection(ticket.id, dateData.id, dateData.available, dateData.tooLate); + } // Date Selection + + }); // Date Picker + + + } + + }); // each ticket + + function doQuantSelection(id, invId, available, tooLate) { + + // Build the ticket quant options + var ticketQuants = ''; + var selectMax = available; + if (selectMax > 50) { + selectMax = 50; + } + + if (tooLate) { + $('#GLMticketQuantContainer_' + id).html(ticketTooLate); + } else { + + // note that the braced lte below is needed to inject a less-than-or-equal-to operator without having flexy chew on it. + for (var i = 1; i {lte:h} (selectMax*1); i++) { + ticketQuants = ticketQuants.concat(''); + } + + // Populate the ticket quantity container + tmpQuantSel = ticketQuantSelection.replace(/\[id\]/g, id); + $('#GLMticketQuantContainer_' + id).html(tmpQuantSel.replace(/\[ticket-quants\]/g, ticketQuants)); + } + + } + + $('#GLMselectButton').click(function() { + + // Check for a selected ticket + var ticketSelected = false; + $('.glmTicketQuant').each(function( index ) { + if ($(this).val() != '') { + ticketSelected = true; + } + }); + + if (ticketSelected) { + selectButtonPressed = true; + setBlocker(); + $('#GLMselectForm').submit(); + } else { + alert('Please select a {term.ticket.norm} quantity.') + return false; + } + + }); + + function setBlocker() { + $('#glmReloadBlocker').show(); + } + + }); + + + diff --git a/views/front/SaultSteMarie/Shop/ticketOpt.html b/views/front/SaultSteMarie/Shop/ticketOpt.html new file mode 100755 index 0000000..4573467 --- /dev/null +++ b/views/front/SaultSteMarie/Shop/ticketOpt.html @@ -0,0 +1,273 @@ + + + + + +
    + +
    +
    Ticket Selection
    + + +
    + +
    {ticketOptText:h}
    + {if:reason} +
    +
    We're sorry, we had a problem with your request:
    +
      + {foreach:reason,r} +
    • {r:h}
    • + {end:} +
    +
    + {end:} +

    You have selected

    + +
    +
    +
    +
    {performanceDetail.name}
    +
    +
    +
    {term.prop.cap}: {performanceDetail.member_name}
    + + +
    +
    +
    +
    +
    {sectionDetail.name}
    +
    +
    + +
    +
    +
    +
    +
    {ticketDetail.name}
    +
    +
    + {if:!ticketDetail.date_specific.value} +
    Use any date {if:ticketDetail.start_date.timestamp} from {ticketDetail.start_date.date} to {ticketDetail.end_date.date}{end:}
    + {end:} + {if:!ticketDetail.time_specific.value} +
    Use any time
    + {else:} +
    Time: {ticketDetail.ticket_time.time}
    + {end:} + {if:!ticketDetail.unlimted_use.value} + + {else:} +
    Each {term.ticket.norm} may be used an unlimited number of times
    + {end:} +
    {ticketDetail.descr:h}
    +
    +
    +
    + +

    Please select from the following

    +
    +
    +
    +
    +
    +
    +
    +
    Select desired date:
    +
    +
    (click in field to set date)
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    Select Quantity:
    +
    +
    (please select date first)
    +
    +
    +
    +
    + {if:reason}
    (disabled - please see above)
    {else:}
    {term.nav.add_to_cart}
    {end:} +
    + +{startScript:h} + + // Whether ticket has date specific inventory + var dateSpecific = {ticketDetail.date_specific.value} + 0; + + // Dates for inventory data + var dates = {inventoryJSON:h}; + + $(document).ready(function(){ + + // DatePicker action + function avail(date) { + m = (date.getMonth()+1); + if (m < 10) { + m = '0' + m; + } + d = date.getDate(); + if (d < 10) { + d = '0' + d; + } + y = date.getFullYear(); + mdy = m + '/' + d + '/' + y; + if (dates[mdy]) { + return [true,"","Available"]; + } else { + return [false,"","Not Available"]; + } + } + var dateData = false; + + var ticketQuantSelection = '\ + \ + '; + var ticketTooLate = '\ +

    \ + Sorry, too late to select these {term.ticket.plur} on-line.\ + {term.ticket.plur_cap} must be purchased at least {detail.performance.purch_leadtime} hours prior to the {term.performance.norm}.\ + Please select another date or time.\ +

    \ + '; + var selectedInv; + var ticketQuants; + var addButtonPushed = false; + + // Start by counting the number of dates to see if we have only 1 + var dateCount = 0; +// if (dateSpecific) { + $.each(dates, function(index, date) { + dateCount = dateCount + 1; + dateData = date; + }); +// } + // if there's no date specific tickets + if (!dateSpecific) { + // Populate date input field + $('#GLMeventDateSelectBlock').html(''); + doQuantSelection(); + // if there's only one date, then display that and move on. + } else if (!dateSpecific || dateCount == 1) { + // populate date input field + $('#GLMeventDate').val(dateData['date']); + $('#GLMtickets').html('
    Date:
    ' + dateData['date'] + '
    '); + + doQuantSelection(); + } else { + // Use the date picker to select a date + dateData = false; + $("#GLMeventDate").datepicker({ + beforeShowDay: avail, + dateFormat: "mm/dd/yy", + minDate: "{performanceDetail.start_date.date}", + maxDate: "{performanceDetail.end_date.date}", + onSelect: function(selectedDate, inst) { + // Update input message + $('#GLMdateMessage').html('
    '); + + // Get data for the selected date + dateData = dates[selectedDate]; + doQuantSelection(); + } // Date Selection + + }); // Date Picker + + } + + function doQuantSelection() { + // Build the ticket quant options + ticketQuants = ''; + var selectMax = dateData['available']; + if (selectMax > 50) { + selectMax = 50; + } + var tooLate = dateData['tooLate']; + if (tooLate) { + $('#GLMticketQuantContainer').html(ticketTooLate); + } else { + // note that the braced lte below is needed to inject a less-than-or-equal-to operator without having flexy chew on it. + for (var i = 1; i {lte:h} (selectMax*1); i++) { + ticketQuants = ticketQuants.concat(''); + } + + // Populate the ticket quantity container + $('#GLMticketQuantContainer').html(ticketQuantSelection.replace(/\[ticket-quants\]/g, ticketQuants)); + } +// doAddToCartSetup(); + } + +// function doAddToCartSetup() { + // Add to cart action + $('#GLMaddToCart').click(function() { + if (addButtonPushed) { + return; + } + var reason = ''; + // Check date + if (dateData) { + selectedInv = dateData.id; + } else { + reason = reason.concat('* You need to select a date first.\n'); + } + // Check quantity + var selectedQuant = (parseInt($('#glmQuantSelector').val()) + 0); + if (selectedQuant == 0) { + reason = reason.concat('* You need to select a quantity first.\n'); + } + // Check if there's a reason we can't add this to the cart yet + if (reason != '') { + alert(reason); + return; + } + // Adding to cart + addButtonPushed = true; + $("#GLMeventDate").datepicker('disable'); + $('#glmQuantSelector').prop('disabled', 'disabled'); + setBlocker(); + // Submit to cart + window.location = "{baseSCRIPT}&Action=Shop_cart&cart=add&PerformanceID={performanceDetail.id}&SectionID={sectionDetail.id}&TicketID={ticketDetail.id}&ticket_inv=" + selectedInv + "&quant=" + selectedQuant; + + }); +// } + // Code to kick off the geolocation-display feature + $("#locationMap").geolocate({ + lat: "#lat", + lng: "#lon", + mapOptions: { + disableDefaultUI: false, + mapTypeControl: true, + mapTypeId: "roadmap", + zoom: 12 + }, + markerOptions: { + draggable: false, + title: "This is your selected location" + } + }); + // Navigation buttons + $('#GLMnavCart').click(function() { // Add to Cart + window.location = '{baseSCRIPT}&Action=Shop_cart'; + }); + $('#GLMnavSelectEvent').on('click', function() { // Return to Event Selection + window.location = '{startURL:h}'; + }); + + function setBlocker() { + $('#glmReloadBlocker').show(); + } + + }); + + diff --git a/views/front/SaultSteMarie/Shop/ticketSelect.html b/views/front/SaultSteMarie/Shop/ticketSelect.html new file mode 100755 index 0000000..5617e51 --- /dev/null +++ b/views/front/SaultSteMarie/Shop/ticketSelect.html @@ -0,0 +1,314 @@ + + + +
    + +
    +
    {term.ticket.cap} Selection
    + +
    + {term.nav.show_selected} + {if:!option.ticket_selection.start_at_cart} + {term.nav.select_more} + {end:} +
    +
    + +
    {ticketText:h}
    +{if:reason} +
    +
    We're sorry, we had a problem with your request:
    +
      + {foreach:reason,r} +
    • {r:h}
    • + {end:} +
    +
    +{end:} +

    You have selected

    + + + +{foreach:sections,s} +
    +
    + + +
    + {if:performanceDetail.image} +
    + {end:} +
    + +
    +
    {performanceDetail.member_name:h}

    +
    {performanceDetail.name:h}
    +
    +
    +
    + {if:!oneSectionOnly} + {s.sectionDetail.name}
    + {end:} + +
    + + {if:performanceDetail.descr} + {performanceDetail.descr:h} + {end:} +
    +
    +
    +
    +
    + +

    Please select from the following

    +
    +
    + + + + + {foreach:s.ticketsData,x} +
    + {if:option.ticket_selection.include_options_in_ticket_list} +
    +
    +
    Price: 
    +
    +
    {x.price}
    +
    +
    +
    +
    Select date: 
    +
    +
    + + +
    +
    +
    +
    +
    Quant: 
    +
    +
    (select date)
    +
    +
    +
    + {end:} +
    + {if:option.ticket_selection.include_options_in_ticket_list} +
    {x.title}
    + {else:} +
    + {x.name} +
    + {end:} +
    +
    + {if:x.descr} +

    {x.short_descr:h}

    + {end:} +

    + {if:!x.date_specific.value} + {if:x.start_date.timestamp} Date: {x.start_date.date}{end:}{if:!x.start_end_dates_same} to {x.end_date.date}{end:}{if:!x.time_specific.value} {end:} + {end:} + {if:!x.time_specific.value} + + {else:} + Time: {x.ticket_time.time} + {end:} + {if:x.unlimted_use.value} + Each {term.ticket.norm} may be used an unlimited number of times + {else:} + + {end:} +

    +
    +
    +
    +
    + {end:} + +
    +
    + +{end:} + +
    + +{if:option.ticket_selection.include_options_in_ticket_list} + + {startScript:h} + + var addButtonPushed = false; + + // Dates for inventory data + var tickets = {ticketsJSON:h}; + + var ticketQuantSelection = '\ + \ + '; + + var ticketTooLate = '\ +

    \ + Sorry, too late to select these {term.ticket.plur} on-line.\ + {term.ticket.plur_cap} must be purchased at least [hours] hours prior to the {term.performance.norm}.\ + Please select another date or time.\ +

    \ + '; + + + $(document).ready(function(){ + + // for each ticket + $.each(tickets, function(index, ticket) { + + var inventory = ticket.inventory; + + // Build date data array and count dates for this ticket + var dateCount = 0; + var dateData = false + $.each(inventory, function(index, date) { + + // Count the number of dates + dateCount++; + + // If this is the first one, store it in case it's the only one + dateData = date; + + }); // each date + + // if there's no date specific tickets + if (!ticket.dateSpecific) { + + // Populate date input field + $('#GLMeventDateSelect_' + ticket.id).html(''); + doQuantSelection(ticket.id, dateData.id, dateData.available, ticket.tooLate); + + // if there's only one date, then display that and move on. + } else if (!ticket.dateSpecific || dateCount == 1) { + + // populate date input field + $('#GLMeventDateSelect_' + ticket.id).html(' \ +
    Date Available: 
    \ +
    \ +
    \ + ' + dateData.ticket_date.date + ' \ + \ +
    \ +
    '); + + doQuantSelection(ticket.id, dateData.id, dateData.available, ticket.tooLate); + + } else { + + // DatePicker action + function avail(date) { + m = (date.getMonth()+1); + if (m < 10) { + m = '0' + m; + } + d = date.getDate(); + if (d < 10) { + d = '0' + d; + } + y = date.getFullYear(); + mdy = m + '/' + d + '/' + y; + if (inventory[mdy]) { + return [true,"","Available"]; + } else { + return [false,"","Not Available"]; + } + } + + // Use the date picker to select a date + if($('#GLMeventDateInput_' + ticket.id).length > 0) { + $('#GLMeventDateInput_' + ticket.id).datepicker({ + beforeShowDay: avail, + dateFormat: "mm/dd/yy", + minDate: ticket.startDate, + maxDate: ticket.endDate, + onSelect: function(selectedDate, inst) { + // Get data for the selected date + dateData = inventory[selectedDate]; + $('#GLMeventInvID_' + ticket.id).val(dateData.id); + doQuantSelection(ticket.id, dateData.id, dateData.available, ticket.tooLate); + } // Date Selection + + }); // Date Picker + } + + } + + }); // each ticket + + function doQuantSelection(id, invId, available, tooLate) { + + // Build the ticket quant options + var ticketQuants = ''; + var selectMax = available; + if (selectMax > 50) { + selectMax = 50; + } + + if (tooLate) { + $('#GLMticketQuantContainer_' + id).html(ticketTooLate.replace(/\[hours\]/g, {performanceDetail.purch_leadtime})); + } else { + // note that the braced lte below is needed to inject a less-than-or-equal-to operator without having flexy chew on it. + for (var i = 1; i {lte:h} (selectMax*1); i++) { + ticketQuants = ticketQuants.concat(''); + } + + // Populate the ticket quantity container + tmpQuantSel = ticketQuantSelection.replace(/\[id\]/g, id); + $('#GLMticketQuantContainer_' + id).html(tmpQuantSel.replace(/\[ticket-quants\]/g, ticketQuants)); + } + + } + + var selectButtonPressed = false; + + $('#GLMselectButton').click(function() { + + // Prevent multiple submissions + if (selectButtonPressed == true) { + return; + } + + // Check for a selected ticket + var ticketSelected = false; + $('.glmTicketQuant').each(function( index ) { + if ($(this).val() != '') { + ticketSelected = true; + } + }); + + if (ticketSelected) { + selectButtonPressed = true; + setBlocker(); + $('#GLMselectForm').submit(); + } else { + alert('Please select a {term.ticket.norm} quantity.') + return false; + } + + }); + + function setBlocker() { + $('#glmReloadBlocker').show(); + } + if( $(window).width() < 768 ){ + $('.glmBlock').not(":first").each(function() { + var left = $(this).find( $('.glmBlockContentLeft') ); + left.prependTo( $(this) ).find( $('glmBlockContentRight') ); + }); + } + }); + +{end:} + diff --git a/views/front/SaultSteMarie/foot.html b/views/front/SaultSteMarie/foot.html new file mode 100755 index 0000000..36eb69f --- /dev/null +++ b/views/front/SaultSteMarie/foot.html @@ -0,0 +1,9 @@ + +{if:option.development} +

    + Running on Development Server: + + Reset Session + +

    +{end:} \ No newline at end of file diff --git a/views/front/SaultSteMarie/head.html b/views/front/SaultSteMarie/head.html new file mode 100755 index 0000000..2b09b3e --- /dev/null +++ b/views/front/SaultSteMarie/head.html @@ -0,0 +1,38 @@ + +{startScript:h} + // Pass some reference parameters to JAVAScript + var baseSiteURL = '{baseURL}'; + var baseAppURL = '{baseAppURL}'; + +{if:!jQueryLoaded} + +{end:} +{if:!jQueryUiLoaded} + + +{end:} + + + +{if:customCssFile} + + +{end:} +{if:frontDebug} + +
    +{end:} +{startScript:h} + var disp_setting="toolbar=no,location=no,directories=no,menubar=no,scrollbars=yes,width=1000, height=700, left=100, top=25"; + {if:frontDebug} + debugWindowFront = window.open("{baseURL}index.php?Action=Debug_update","emDebugWindowFront",disp_setting); + {end:} + + +
    +
    Updating your information
    Please wait ...
    +
    + + {if:adminUser} +

    Purchasing By Admin User

    + {end:} diff --git a/views/front/SaultSteMarie/index.html b/views/front/SaultSteMarie/index.html new file mode 100755 index 0000000..fca55f0 --- /dev/null +++ b/views/front/SaultSteMarie/index.html @@ -0,0 +1,34 @@ + + + + + + + + + + +

    PLEASE NOTE:

    + +

    + There is no general access to this site. + All access to this site should be through an appropriate link. + If you arrived here by mistake (or exploring), nothing but this message will be displayed. + If you have any concerns about this site, please contact Gaslight Media. +

    + +

    + Gaslight Media
    + 120 East Lake Street
    + Petoskey, MI 49770
    +  
    + Phone: 231-487-0692
    + E-Mail: info@gaslightmedia.com
    + Web: http://www.gaslightmedia.com +

    + + + + + + diff --git a/views/front/TicketsFoundation/Debug/index.html b/views/front/TicketsFoundation/Debug/index.html new file mode 100644 index 0000000..6af2dc9 --- /dev/null +++ b/views/front/TicketsFoundation/Debug/index.html @@ -0,0 +1,44 @@ + + + + + + +
    Startup: {debugStartupTime}
    +
    Event Management Front-End Debug
    +
    +
    + Updated: {debugUpdateTime} +
    +
    + {debugData:h} +
    + + + + + {startScript:h} + + // Reload the current window with Action = Debug_update + function reloadDebugWindow() + { + window.location("{baseSCRIPT}&Action=Debug_update"); + } + + + \ No newline at end of file diff --git a/views/front/TicketsFoundation/Debug/start.html b/views/front/TicketsFoundation/Debug/start.html new file mode 100644 index 0000000..66c3023 --- /dev/null +++ b/views/front/TicketsFoundation/Debug/start.html @@ -0,0 +1,27 @@ + + + + + + +
    Startup: {debugStartupTime}
    +
    Event Management Front-End Debug
    +
    +
    Debug Startup
    + + \ No newline at end of file diff --git a/views/front/TicketsFoundation/Shop/Copy of cart.html b/views/front/TicketsFoundation/Shop/Copy of cart.html new file mode 100644 index 0000000..c95b7ea --- /dev/null +++ b/views/front/TicketsFoundation/Shop/Copy of cart.html @@ -0,0 +1,404 @@ + + + +
    +
    + + +
    + + +
    + {if:!option.ticket_selection.start_at_cart} + {term.nav.select_more} + {end:} + +
    +
    + +
    {cartText:h}
    + {if:reason} +
    +
    We're sorry, we had a problem with your request:
    +
      + {foreach:reason,r}{Chuck} +
    • {r:h}
    • + {end:} +
    +
    + {end:} + {if:havePromoCodes} +
    +
    +
    If you have a {term.promo.norm}, please enter it here:
    +
    +
    + {end:} + {foreach:cart,c} +
    +
    {c.name:h}
    +
    + {foreach:c.performances,p} +
    +
    + {if:!option.ticket_selection.start_at_cart} + {term.nav.select_more_of_these} + {end:} +
    + +
    {p.name:h}
    +
    + {if:p.descr}
    {p.descr:h}
    {end:} + {if:p.short_descr}
    {p.short_descr:h}
    {end:} + {if:option.cart_images}{if:p.image} + + {end:}{end:} +
    +
    +
    +
    + {foreach:p.dates,d} +
    + {if:d.dateSpecific} + {d.fullDate} + {else:} + Use any date + {if:c.likelyDate} + - Likely Date {c.likelyDate} + {end:} + {end:} + {foreach:d.sections,s} + + + + {if:!p.oneSectionOnly} + + {end:} + + + + + {foreach:s.tickets,i} + + + {if:!p.oneSectionOnly} + + {end:} + + + + + {if:i.descr} + + + {if:!p.oneSectionOnly} + + + {end:} + + {foreach:i.addons,a} + + + {if:!p.oneSectionOnly} + + {end:} + + + + + {end:} + + + {if:i.promo} + + + {if:!p.oneSectionOnly} + + {end:} + + + + {end:} + + {end:} +
    QuantSection{term.ticket.cap}PriceTotal
    + + {s.name:h}{i.title}{if:i.show_price}{i.price}{end:}{if:i.show_price}{i.extended}{end:}
      + {else:} + + {end:} + {if:option.cart_images}{if:i.image} +
    + {end:}{end:} +
    {i.descr:h}
    +
       +
    + +
    +
    {a.unit_cost}/{a.unit_name:h}{a.money}
      {term.promo.cap}: {promoCode}  + {i.promo.credit}
    + {end:} +
    + {end:} +
    +
    + {end:} +
    + {if:c.ticket_policy}
    {c.ticket_policy:h}
    {end:} + + {if:c.needAssignemntOrDate} + {if:c.needAssignment} + +
    + {if:!c.haveAssignment} +
    {text.cart.select_assignment_location}
    + {else:} +
    {text.cart.select_assignment_location}
    + {end:} + {foreach:c.assignmentMembers,a} + {if:a.entrances} + {foreach:a.entrances,e} +
    + {if:option.cart_images} + {if:e.image} +
    + {end:} + {end:} +
    + {if:e.selected} + {a.name:h} - {e.name:h}
    + {else:} + {a.name:h} - {e.name:h}
    + {end:} +
    +
    {e.addr1}{if:e.addr2}, {e.addr2}{end:}, {e.city}
    +
    {e.phone}
    + {if:e.descr} +
    {e.descr:h}
    + {end:} +
    +
    + {end:} +
    + {else:} + {if:a.selected} + {a.name:h}
    + {else:} + {a.name:h}
    + {end:} + {end:} + {end:} +  
    + {end:} + + {if:option.ask_for_likely_date} + {if:c.needLikelyDate} +
    + {if:!c.likelyDate} + + {else:} + + {end:} + {text.cart.select_likely_date}   + + mm/dd/yyyy +
    + {end:} + {end:} +
    +
    + {end:} + {if:!c.needAssignment} + + {if:option.cart_images}{if:c.image} +
    + + +
    + {end:}{end:} + {end:} + + + + +
    + {end:} + + +
    + {if:cartHasContents} +
    + Grand Total   {totals.price} +
    +
    + {if:totals.tickets} + {if:!blockCheckout} + {term.nav.checkout} + {else:} + Please complete the items in RED above. + {end:} + {else:} + Your cart is currently empty. + {end:} +
    + {else:} +

    Your cart is currently empty.

    + {end:} +
    + + {if:option.cart_promotions} +
    + You may also be interested in ...
    + {foreach:cartPromotions,p} +
    + + {if:p.image} +
    + {end:} +
    + + {if:p.short_descr}
    {p.short_descr:h}
    {end:} + {if:p.short_descr}
    {p.short_descr:h}
    {end:} +
    +
    + {end:} +
    + {end:} + + + +
    + +{startScript:h} + + $(document).ready(function(){ + + $('#cartForm').submit(function( event ) { + return false; + }); + + // Convert input fields to select lists + $('.glmCartQuant').each(function() { + + var id = $(this).attr('id'); + var ticket = $(this).attr('data-ticket'); + var addon = $(this).attr('data-addon'); + var max = $(this).attr('data-max'); + var value = $(this).attr('value'); + var units = $(this).attr('data-units'); + var numbSel = ''; + + // Build a picklist for this input + for (var i = 0 ; i {lte:h} max ; i++) { + if (value == i) { + numbSel = numbSel.concat(''); + } else { + numbSel = numbSel.concat(''); + } + } + + $('#quant_' + id).html('' + units); + + }); + + // Get or set vertical scroll to return to same place when cart reloads + function getVertScroll() { + var vertScroll = window.pageYOffset; + if (vertScroll == 0) { + var vertScroll = document.documentElement.scrollTop; + } + if (vertScroll == 0) { + var vertScroll = document.body.scrollTop; + } + return vertScroll; + } + + // When a cart value changes, submit it as a cart update. + $('.glmCartSelect').change(function() { + vertScroll = getVertScroll(); + var ticket = $(this).attr('data-ticket'); + var addon = $(this).attr('data-addon'); + var value = $(this).val(); + + setBlocker(); + window.location = "{baseSCRIPT}&Action=Shop_cart&cart=update&ticket_inv=" + ticket + "&addon=" + addon + "&quant=" + value + "&vertScroll=" + vertScroll; + + }); + + // When there's a change in the promo code input, submit it. + $('#promoCodeInput').change(function() { + var value = $(this).val(); + setBlocker(); + window.location = "{baseSCRIPT}&Action=Shop_cart&cart=promo_code&promo_code=" + value; + }); + + // When a member selection for unassigned items changes, submit it so it's in the session + $('.glmAssignmentChange').change(function() { + vertScroll = getVertScroll(); + var member = $(this).attr('data-Member'); + var assignedTo = $(this).val(); + var assignedToEntrance = $(this).attr('data-entrance'); + setBlocker(); + window.location = "{baseSCRIPT}&Action=Shop_cart&cart=update_assignment&member_assigned=" + member + "&assigned_to=" + assignedTo + "&entrance_assigned=" + assignedToEntrance + "&vertScroll=" + vertScroll; + }); + + // When a likely departure date changes, submit it so it's in the session + $('.glmLikelyDateChange').change(function() { + vertScroll = getVertScroll(); + var member = $(this).attr('data-Member'); + var likelyDate = $(this).val(); + setBlocker(); + window.location = "{baseSCRIPT}&Action=Shop_cart&cart=update_likelyDate&member=" + member + "&likely_date=" + likelyDate + "&vertScroll=" + vertScroll; + + }); + + // Code to start datepicker for each date input + if($("#likelyDateInput").length > 0) { + $("#likelyDateInput").datepicker({ + dateFormat: "mm/dd/yy", + minDate: -1, + maxDate: 365 + }); + } + + // Checkout action + $('#GLMcheckoutBtn').click(function() { + setBlocker(); + window.location = "{baseSCRIPT}&Action=Shop_checkout"; + }); + + function setBlocker() { + $('#glmReloadBlocker').show(); + } + + $('#GLMnavSelectEvent').on('click', function() { // Return to Event Selection + setBlocker(); + window.location = '{startURL:h}'; + }); + +/* Not using right now + // Reprint order button + $('#reprintVoucher').on('keypress', function(event) { + if(event.which == '13'){ + var orderID = $(this).val(); + var voucherWindow = window.open('{appAdminURL}&Action=Order_printVoucher&OrderID=' + orderID, + "voucherPrint", + "height=750,width=600,menubar=yes,toolbar=yes,alwaysRaised=yes,menu" + ); + voucherWindow.focus(); + voucherWindow.print(); + return false; + } + }); +*/ + + if ({vertScroll}) { + window.scrollTo(0,{vertScroll}); + } + + }); + + + diff --git a/views/front/TicketsFoundation/Shop/PayPalApproved.html b/views/front/TicketsFoundation/Shop/PayPalApproved.html new file mode 100644 index 0000000..100d251 --- /dev/null +++ b/views/front/TicketsFoundation/Shop/PayPalApproved.html @@ -0,0 +1,41 @@ + + + + + +
    + +

    Your PayPal payment has been approved.

    + + +
    + +

    + Your cart will now reflect that the payment has been made. +

    + +
    + +
    +
    Close This Window
    +
    + +
    + + + + diff --git a/views/front/TicketsFoundation/Shop/PayPalFail.html b/views/front/TicketsFoundation/Shop/PayPalFail.html new file mode 100644 index 0000000..f8bed73 --- /dev/null +++ b/views/front/TicketsFoundation/Shop/PayPalFail.html @@ -0,0 +1,49 @@ + + + + + +
    + +

    Unable to process your payment!

    + + +
    + +

    +

    Sorry, there was a problem.
    +

    + +

    + We were unable to find your purchase information and are therefore + are unable to process your payment through PayPal. This could be + due to you not performing any action with your pending purchase + for too long. Please click the "Return to selected tickets" button + at the top of the checkout page to see if your selections are still listed. +

    + +
    + +
    +
    Close This Window
    +
    + +
    + + + + diff --git a/views/front/TicketsFoundation/Shop/cart.html b/views/front/TicketsFoundation/Shop/cart.html new file mode 100644 index 0000000..50525ef --- /dev/null +++ b/views/front/TicketsFoundation/Shop/cart.html @@ -0,0 +1,534 @@ + + + +
    + + + +
    +
    + + + {if:!option.ticket_selection.start_at_cart} + {term.nav.select_more} + {end:} + + +

    {cartText:h}

    + +
    +
    + +{if:reason} + + + +
    +
    +
    +

    We're sorry, we had a problem with your request:

    +
      + {foreach:reason,r}{Chuck} +
    • {r:h}
    • + {end:} +
    +
    +
    +
    +{end:} + +{if:havePromoCodes} + + + +
    +
    + +
    +
    + +
    +
    +{end:} + + + +{foreach:cart,c} + + {if:option.show_location_blocks} +
    +
    +
    +
    +

    {c.name:h}

    +
    + {end:} + + + + {foreach:c.performances,p} +
    +
    +
    + + + +
    +
    +

    {p.name:h} + {if:!option.ticket_selection.start_at_cart} + {term.nav.select_more_of_these} + {end:} +

    +
    +
    + + + +
    + {if:!option.cart_images} +
    + {if:p.image} + + {end:} +
    + {end:} +
    + {if:p.short_descr} + {p.short_descr:h} + {else:} + {if:p.descr} + {p.descr:h} + {end:} + {end:} +
    + {if:!option.cart_images} +
    + {if:p.image} + + {end:} +
    + {end:} +
    + + + + {foreach:p.dates,d} +
    +
    +
    + {if:d.dateSpecific} + {d.fullDate} + {else:} + Use any date + {if:c.likelyDate} + - Likely Date {c.likelyDate} + {end:} + {end:} +
    +
    +
    + + + + {foreach:d.sections,s} +
    +
    Quant
    + {if:!p.oneSectionOnly} +
    {term.section.cap}
    +
    + {else:} +
    + {end:} + {term.ticket.cap} +
    +
    Price
    +
    Total
    +
    + + + + {foreach:s.tickets,i} + + + +
    +
    + +
    + {if:!p.oneSectionOnly} +
    {s.name:h}
    +
    + {else:} +
    + {end:} + {i.title} +
    +
    {if:i.show_price}{i.price}{end:}
    +
    {if:i.show_price}{i.extended}{end:}
    +
    + + + +
    +
    +

    {i.title}

    +
    + {if:i.problem} +
    +
    +
    {i.problemText}
    +
    +
    + {end:} + {if:i.descr} + + +
    +
    +
    + {if:option.cart_images} + {if:i.image} + + {end:} + {end:} + {i.descr:h} +
    +
    + {end:} + + {if:!p.oneSectionOnly} +
    +
    {term.section.cap}:
    +
    {s.name:h}
    +
    + {end:} +
    +
    Quant:
    +
     
    +
    + +
    +
    +
    +
    Price:
    +
    {if:i.show_price}{i.price}{end:}
    +
    +
    +
    Total:
    +
    {if:i.show_price}{i.extended}{end:}
    +
    +
    + + {if:i.descr} + + +
    +
    +
    + {if:option.cart_images} + {if:i.image} + + {end:} + {end:} + {i.descr:h} +
    +
    + {end:} + + + + {foreach:i.addons,a} + + + +
    +
     
    +
    + +
    +
    {a.name}
    +
    {a.unit_cost}/{a.unit_name:h}
    +
    {a.money}
    +
    + + + +
    +
    +

    {a.name}

    +
    +
    +
    Quant:
    +
     
    +
    + +
    +
    +
    +
    Price:
    +
    {a.unit_cost}/{a.unit_name:h}
    +
    +
    +
    Total:
    +
    {a.money}
    +
    +
    + + {end:} + + + + {if:i.promo} +
    +
     
    +
    + {term.promo.cap}: {promoCode} +
    +
    +
    + {i.promo.credit} +
    +
    +
    +
    Promo:
    +
    {promoCode}:
    +
    {i.promo.credit}
    +
    + + {end:} + + {end:} + + {end:} + + {end:} + +
    +
    +
    + + {end:} + + + + {if:option.show_location_blocks} +
    +
    +
    + {end:} + +{end:} + + + +{if:cartHasContents} +
    +
    +

    Grand Total {totals.price}

    +
    +
    +
    +
    + {if:!blockCheckout} + {term.nav.checkout} + {else:} + Please complete the items in RED above. + {end:} +
    +
    +{else:} +
    +
    +

    Your cart is currently empty.

    +
    +
    +{end:} + + + +{if:option.cart_promotions} +
    +
    +
    +
    +
    You may also be interested in ...
    +
    + {foreach:cartPromotions,p} +
    + + {if:p.image} +
    + +
    + {end:} +
    + {if:p.short_descr}{p.short_descr:h}{end:} +
    +
    + {if:p.image} + + {end:} +
    +
    + {end:} +
    +
    +
    +{end:} + + + + + + + + + diff --git a/views/front/TicketsFoundation/Shop/checkout.html b/views/front/TicketsFoundation/Shop/checkout.html new file mode 100644 index 0000000..1890d95 --- /dev/null +++ b/views/front/TicketsFoundation/Shop/checkout.html @@ -0,0 +1,927 @@ + + + +
    + + + + +
    +
    + + + {term.nav.show_selected} + {if:!option.ticket_selection.start_at_cart} + {term.nav.select_more} + {end:} + + +

    {checkoutText:h}

    + +
    +
    + +{if:reason} +
    +
    +
    +

    We're sorry, we had a problem with your request:

    +
      + {foreach:reason,r}{Chuck} +
    • {r:h}
    • + {end:} +
    +
    +
    +
    +{end:} + + + +
    +
    +
    +
    +
    +

    Contact Information

    +
    +
    +
    +
    +
    +
    + {if:formData.contact.fname.required}
    +
    + {if:formData.contact.lname.required}
    +
    + {if:formData.contact.addr1.required}
    +
    + {if:formData.contact.addr2.required}
    +
    + {if:formData.contact.city.required}
    +
    + {if:formData.contact.state.required}
    +
    + {if:formData.contact.country.required}
    +
    + {if:formData.contact.zip.required}
    +
    +
    +
    +
    +
    + {if:formData.contact.phone.required}
    +
    + {if:formData.contact.email.required}
    +
    + {if:formData.contact.email2.required}
    +
    + +
    +
    + {if:formData.contact.email_ok} +
    + {else:} +
    + {end:} +
    + {if:opt_field_1_name} +
    + {if:formData.contact.opt_field_1.required}
    + {end:} + {if:opt_field_2_name} +
    + {if:formData.contact.opt_field_2.required}
    + {end:} + {if:opt_field_1_name} +
    + {if:formData.contact.opt_field_3.required}
    + {end:} +
    +
    +
    +
    +
    +
    + + + +{foreach:cart,c} + + {if:option.show_location_blocks} +
    +
    +
    +
    +
    +

    {c.name:h}

    +
    +
    + {end:} + + + + {foreach:c.performances,p} + +
    +
    +
    + + + +
    +
    +

    {p.name:h}

    +
    +
    + + + +
    +
    + {if:p.short_descr} + {p.short_descr:h} + {else:} + {if:p.descr} + {p.descr:h} + {end:} + {end:} +
    +
    + + + + {foreach:p.dates,d} +
    +
    +
    + {if:d.dateSpecific} + {d.fullDate} + {else:} + Use any date + {if:c.likelyDate} + - Likely Date {c.likelyDate} + {end:} + {end:} +
    +
    +
    + + + + {foreach:d.sections,s} +
    +
    + Quant +
    + {if:!p.oneSectionOnly} +
    + {term.section.cap} +
    +
    + {else:} +
    + {end:} + {term.ticket.cap} +
    +
    + Price +
    +
    + Total +
    +
    + + + + {foreach:s.tickets,i} +
    +
    + {i.selected} +
    + {if:!p.oneSectionOnly} +
    + {s.name:h} +
    +
    + {else:} +
    + {end:} + {i.title} +
    +
    + {if:i.show_price}{i.price}{end:} +
    +
    + {if:i.show_price}{i.extended}{end:} +
    +
    + + + + {if:i.descr} +
    +
    +
    + {i.descr:h} +
    +
    + {end:} + + + + {foreach:i.addons,a} +
    +
     
    +
    + {a.selected} +
    +
    + {a.name} +
    +
    + {a.unit_cost}/{a.unit_name:h} +
    +
    + {a.money} +
    +
    + {end:} + + + + {if:i.promo} +
    +
     
    +
    + {term.promo.cap}: {promoCode} +
    +
    +
    + {i.promo.credit} +
    +
    + {end:} + + {end:} + + {end:} + + {end:} + + {if:p.policy} +
    +
    +

     

    +
    Please read and agree to our policy for this {term.performance.norm}.
    +

    {p.policy:h}

    + +
    +
    + {end:} + +
    +
    +
    + + {end:} + + + + {foreach:c.performances,p} + +
    +
    +
    + + + +
    +
    +

    {p.name:h}

    +
    +
    + + + +
    +
    + {if:p.short_descr} + {p.short_descr:h} + {else:} + {if:p.descr} + {p.descr:h} + {end:} + {end:} +
    +
    + + + + {foreach:p.dates,d} +
    +
    + {if:d.dateSpecific} + {d.fullDate} + {else:} + Use any date + {if:c.likelyDate} + - Likely Date {c.likelyDate} + {end:} + {end:} +
    +
    + + + + {foreach:d.sections,s} + {if:!p.oneSectionOnly} +
    +
    + {term.section.cap}: {s.name:h} +
    +
    + {end:} + + + + {foreach:s.tickets,i} +
    +
    +

    {i.title}

    +

    +
    + {if:i.descr} +
    +
    +
    + {i.descr:h} +
    +
    + {end:} + +
    +
    + Quant +
    +
    {i.selected}
    +
    + {if:i.show_price} +
    +
    + Price +
    +
    {i.price}
    +
    +
    +
    + Total +
    +
    {i.extended}
    +
    + {end:} + + + + {foreach:i.addons,a} +
    +
    + {a.name} +
    +
    +
    +
    + Quant +
    +
    {a.selected}
    +
    +
    +
    + {a.unit_cost}/{a.unit_name:h} +
    +
    {a.money}
    +
    + {end:} + + + + {if:i.promo} +
    +
     
    +
    + {term.promo.cap}: {promoCode} +
    +
    +
    + {i.promo.credit} +
    +
    + {end:} + + {end:} + + {end:} + + {end:} + + {if:p.policy} +
    +
    +

     

    +
    Please read and agree to our policy for this {term.performance.norm}.
    +

    {p.policy:h}

    + +
    +
    + {end:} + +
    +
    +
    + + {end:} + + {if:c.ticket_spec_req.value} +
    +
    + +
    +
    + {end:} + + + +
    +
    +
    +
    +
    +
    Payment for {term.ticket.plur} at {c.name:h}
    +
    +
    +
    {c.totalPrice}
    +
    +
    +
    +
    +   +
    +
    + + {if:c.paymentResult} + {if:c.paymentResult.approved} +
    +
    + Card Payment Approved +
    +
    +
    +
    + Card Type: +
    +
    + {c.paymentResult.cctype} +
    +
    +
    +
    + Name on Card: +
    +
    + {c.paymentResult.ccname} +
    +
    +
    +
    + Card Number: +
    +
    + {c.paymentResult.ccnumb} +
    +
    +
    +
    + Expiration Date: +
    +
    + {c.paymentResult.ccexp} +
    +
    +
    +
    + Authorization Code: +
    +
    + {c.paymentResult.authCode} +
    +
    + + {else:} +
    +
    +
    Card Payment Not Complete
    +
    +
    +
    +
    +

    {c.paymentResult.description}

    +

    Please check the payment information below and try again or contact your credit card company for assistance.

    + {if:forceCheckoutPhase} + {term.nav.delete_from_cart} + {end:} +
    +
    + {end:} + + {else:} + + {if:c.havePaymentMethod} + + {if:c.paypal.value} +
    +
    + {if:c.haveMultiplePaymentMethods} +  PayPal + {else:} + + {end:} +
    +
    + {end:} + {if:c.haveCreditCards} +
    +
    + {if:c.haveMultiplePaymentMethods} +  Credit Card + {else:} + + {end:} +
    +
    +
    +
    + {if:c.paymentForm.cctype.required}
    +
    +
    +
    +
    + {if:c.paymentForm.ccname.required}
    +
    +
    +
    + {if:c.paymentForm.ccnumb.required}
    +
    +
    +
    +
    +
    +
    + {if:c.paymentForm.ccexp.required}
    +
    + {if:c.paymentForm.ccexp.required}
    +
    + {if:c.paymentForm.ccexp.problem} + {c.paymentForm.ccexp.problem} + {end:} +
    +
    +
    +
    + {if:c.paymentForm.cccode.required}
    +
    +
    + {end:} + + {if:c.havePayPal} +
    +
    + +
    +
    + {end:} + + {else:} +
    +
    +

    + This {term.prop.norm} does not have a payment method configured.asdasdsadasd + Please call this {term.prop.norm} to purchase {term.ticket.plur}. +

    +
    +
    + + + {end:} + + + {end:} + +
    +
    +
    + + + {if:option.show_location_blocks} +
    +
    +
    + {end:} +{end:} + +
    +
    +

    Grand Total {totals.price}

    + {if:!cartHasOneVenueOnly} +

    NOTE: There will be a separate credit card transaction for each {term.prop.norm}.

    + {end:} +
    +
    +
    +
    + {ssl_seal_head_script:h} + {ssl_seal_body_script:h} +
    +
    + {if:!blockCheckout} + {term.nav.purchase} + {else:} + Unable to checkout - please see above. + {end:} +
    +
    + + + + + + \ No newline at end of file diff --git a/views/front/TicketsFoundation/Shop/checkoutSuccess.html b/views/front/TicketsFoundation/Shop/checkoutSuccess.html new file mode 100644 index 0000000..b159f83 --- /dev/null +++ b/views/front/TicketsFoundation/Shop/checkoutSuccess.html @@ -0,0 +1,489 @@ + + +asdasdasdasdasdasd +{if:checkoutSucccessText} +
    +
    + +

    {checkoutSuccessText:h}

    +
    +
    +{end:} + +
    +
    +

    Purchase Complete

    +
    +
    + + + +
    +
    +
    +
    +
    + {foreach:cart,c} + {if:c.paymentResult} + {if:c.paymentResult.approved} +

    + *** {term.nav.print_vouchers} for {c.name} *** +

    + {end:} + {end:} + {end:} +
    +
    +
    +
    + + Adobe Reader is required to view and print your {term.voucher.plur}. Adobe Reader is a free program available directly from Adobe. + If you do not already have Adobe Reader installed, click the "Get Adobe Reader" link now. + +
    +
    + +
    +
    + + + If you are unable to print your {term.voucher.plur}, please print this page or write down the order number(s) + below and bring that to the ticket office when you arrive. + + +
    +
    + + ORDER #: + {foreach:cart,c} + {if:c.paymentResult} + {if:c.paymentResult.approved} + {c.paymentResult.orderID}  + {end:} + {end:} + {end:} + +
    +
    +
    +
    +
    + + + +
    +
    +
    +
    +
    +

    Contact Information

    +
    +
    +
    +
    + Name: +
    +
    + {formData.contact.fname.value} {formData.contact.lname.value} +
    +
    +
    +
    + {text.cart.checkout.address}: +
    +
    + {formData.contact.addr1.value}
    + {if:formData.contact.addr2.value} + {formData.contact.addr2.value}
    + {end:} + {formData.contact.city.value}, {formData.contact.state.name} {formData.contact.zip.value}
    + {formData.contact.country.name} +
    +
    +
    +
    + {text.cart.checkout.phone}: +
    +
    + {formData.contact.phone.value} +
    +
    +
    +
    + {text.cart.checkout.email}: +
    +
    + {formData.contact.email.value} +
    +
    +
    +
    + OK to Send E-Mail?: +
    +
    + {if:formData.contact.email_ok} + You have asked us to send information on activities and offers. + {else:} + You have asked us to NOT send information on activities and offers. + We will only contact you regarding this order. + {end:} +
    +
    + {if:opt_field_1_name} +
    +
    + {opt_field_1_name}: +
    +
    + {formData.contact.opt_field_1.value} +
    +
    + {end:} + {if:opt_field_2_name} +
    +
    + {opt_field_2_name}: +
    +
    + {formData.contact.opt_field_2.value} +
    +
    + {end:} + {if:opt_field_3_name} +
    +
    + {opt_field_3_name}: +
    +
    + {formData.contact.opt_field_3.value} +
    +
    + {end:} + +
    +
    +
    + + + +{foreach:cart,c} + + {if:option.show_location_blocks} +
    +
    +
    +
    +
    +

    {c.name:h}

    +
    +
    + {end:} + + + + {foreach:c.performances,p} +
    +
    +
    + + + +
    +
    +

    {p.name:h}

    +
    +
    + + + +
    +
    + {if:p.short_descr} + {p.short_descr:h} + {else:} + {if:p.descr} + {p.descr:h} + {end:} + {end:} +
    +
    + + + + {foreach:p.dates,d} +
    +
    +
    + {if:d.dateSpecific} + {d.fullDate} + {else:} + Use any date + {if:c.likelyDate} + - Likely Date {c.likelyDate} + {end:} + {end:} +
    +
    +
    + + + + {foreach:d.sections,s} +
    +
    + Quant +
    + {if:!p.oneSectionOnly} +
    + {term.section.cap} +
    +
    + {term.ticket.cap} +
    + {else:} +
    + {term.ticket.cap} +
    + {end:} +
    + Price +
    +
    + Total +
    +
    + + + + {foreach:s.tickets,i} +
    +
    Quant
    +
    {i.selected}
    +
    {i.selected}
    + {if:!p.oneSectionOnly} +
    {term.section.cap}
    +
    {s.name:h}
    +
    {term.ticket.cap}
    +
    {i.name:h}
    + {else:} +
    {term.ticket.cap}
    +
    {i.name:h}
    + {end:} +
    Price
    +
    {i.price}
    +
    {i.price}
    +
    Total
    +
    {i.extended}
    +
    {i.extended}
    +
    + + + + {if:i.descr} +
    +
    +
    + {i.descr:h} +
    +
    + {end:} + + + + {foreach:i.addons,a} +
    +
     
    +
    Quant
    +
    {a.selected}
    +
    {a.selected}
    + +
    {term.ticket.cap}
    +
    {a.name:h}
    + +
    Price
    +
    {a.unit_cost}/{a.unit_name:h}
    +
    {a.unit_cost}/{a.unit_name:h}
    + +
    Total
    +
    {a.money}
    +
    {a.money}
    +
    + {end:} + + + + {if:i.promo} +
    +
     
    +
    + {term.promo.cap}: {promoCode} +
    +
    +
    + {i.promo.credit} +
    +
    + {end:} + + {end:} + + {end:} + + {end:} + + {if:p.policy} + + + +
    +
    +

    {p.policy:h}

    +
    +
    + {end:} + +
    +
    +
    + + {end:} + + {if:c.paymentForm.spec_req.value} + + + +
    +
    + {c.paymentForm.spec_req.value:h} +
    +
    + {end:} + + + +
    +
    +
    +
    +
    + Payment for {term.ticket.plur} at {c.name:h} +
    +
    +
    {c.totalPrice}
    +
    +
    +
    +
    +   +
    +
    +
    +
    + Card Payment Approved +
    +
    +
    +
    + Card Type: +
    +
    + {c.paymentResult.cctype} +
    +
    +
    +
    + Name on Card: +
    +
    + {c.paymentResult.ccname} +
    +
    +
    +
    + Card Number: +
    +
    + {c.paymentResult.ccnumb} +
    +
    +
    +
    + Expiration Date: +
    +
    + {c.paymentResult.ccexp} +
    +
    +
    +
    + Authorization Code: +
    +
    + {c.paymentResult.authCode} +
    +
    +
    +
    +
    + + {if:c.ticket_policy} +
    +
    + {c.ticket_policy:h} +
    +
    + {end:} + + {if:option.show_location_blocks} +
    +
    +
    + {end:} +{end:} + + + +
    +
    +

    Grand Total {totals.price}

    +{if:!cartHasOneVenueOnly} +

    NOTE: You will see a separate credit card transaction for each {term.prop.norm} above.

    +{end:} +
    +
    + +{trackingScript:h} + + + \ No newline at end of file diff --git a/views/front/TicketsFoundation/Shop/paymentSummary.html b/views/front/TicketsFoundation/Shop/paymentSummary.html new file mode 100644 index 0000000..e5b1642 --- /dev/null +++ b/views/front/TicketsFoundation/Shop/paymentSummary.html @@ -0,0 +1,112 @@ + +

    + + Click here to reprint your {term.voucher.plur} + +

    + +

    + {term.ticket.plur_cap} Purchased at:
    + {cartEntry.name} +

    + + +{if:cartEntry.descr}

    {cartEntry.descr:h}

    {end:} + + + + + + + + + + + +{foreach:cartEntry.performances,p} + {foreach:p.dates,d} + {foreach:d.sections,s} + + + {foreach:s.tickets,i} + + + + + + + + {foreach:i.addons,a} + + + + + + + + {end:} + {if:i.promo} + + + + + + + {end:} + {end:} + + + {end:} + {end:} +{end:} + + + + + + + + +
    Quant{term.performance.cap}{term.ticket.cap}PriceTotal
    {i.selected}{p.name:h}{i.title:h}{if:i.show_price}{i.price}{end:}{if:i.show_price}{i.extended}{end:}
       +
    + {a.selected} {a.unit_name} +
    +
    {a.unit_cost}/{a.unit_name}{a.money}
      {term.promo.cap}: {promoCode}  + {i.promo.credit}
     {cartEntry.totalPrice}
    + + +{if:cartEntry.ticket_spec_req} +

    + Special requests: {cartEntry.paymentForm.spec_req.value:h} +

    +{end:} + + +{if:cartEntry.ticket_policy}

    {cartEntry.ticket_policy:h}

    {end:} + +

    + + + + + + + +
    Credit Card Payment Approved
    Card Type{cartEntry.paymentResult.cctype}
    Name on Card{cartEntry.paymentResult.ccname}
    Card Number{cartEntry.paymentResult.ccnumb}
    Expiration Date{cartEntry.paymentResult.ccexp}
    Authorization Code{cartEntry.paymentResult.authCode}
    +

    + + \ No newline at end of file diff --git a/views/front/TicketsFoundation/Shop/sectionSelect.html b/views/front/TicketsFoundation/Shop/sectionSelect.html new file mode 100644 index 0000000..eda22a2 --- /dev/null +++ b/views/front/TicketsFoundation/Shop/sectionSelect.html @@ -0,0 +1,96 @@ + + + + + + +
    + + +
    {term.section.cap} Selection
    + + + + + +
    {sectionText:h}
    + +{if:reason} +
    +
    We're sorry, we had a problem with your request:
    +
      + {foreach:reason,r} +
    • {r:h}
    • + {end:} +
    +
    +{end:} + +

    You have selected

    +
    +
    +
    +
    {performanceDetail.member_name}

    +
    {performanceDetail.name}
    +
    +
    + + +
    +
    +
    + + +
    +

    Please select from the following

    +
    +{foreach:sectionList,x} +
    + +
    +

    {term.section.cap}: {x.member_name}

    +

    {x.descr:h}

    +
    +
    +{end:} + +
    + +
    + + + \ No newline at end of file diff --git a/views/front/TicketsFoundation/Shop/start.html b/views/front/TicketsFoundation/Shop/start.html new file mode 100644 index 0000000..a735605 --- /dev/null +++ b/views/front/TicketsFoundation/Shop/start.html @@ -0,0 +1,396 @@ + + + +
    + +
    +
    {term.event.cap} Selection
    + + +
    + +
    {introText:h}
    + {if:reason} +
    +
    We're sorry, we had a problem with your request:
    +
      + {foreach:reason,r} +
    • {r:h}
    • + {end:} +
    +
    + {end:} +

    Please select from the following

    +{if:showTickets} +
    + + + + +{end:} + + {foreach:membersList,m} +
    +
    +
    +
    +
    {m.name}
    +
    +
    +
    Address: {m.addr1}{if:m.addr2}, {m.addr2}{end:}, {m.city}
    +
    Phone #: {m.phone}
    +
    {m.descr:h}
    +
    +
    +
    +
    (map loads here)
    + + + + +
    + +
    + {foreach:m.performances,p} +
    +
    +
    +
    + {if:showTickets} + {p.name} + {else:} + {p.name} + {end:} +
    +
    +
    +
    {term.prop.cap}: {p.member_name}
    +
    Dates: {p.start_date.date} through {p.end_date.date}
    +
    +
    + {if:!showTickets} + {term.nav.select} + {end:} + + + {foreach:p.sections,s} +

     

    +
    +
    +
    + {if:!p.oneSectionOnly} + {s.sectionDetail.name}
    + {end:} + +
    + +
    +
    + + + {foreach:s.ticketsData,x} +
    + {if:option.ticket_selection.include_options_in_ticket_list} +
    +
    +
    Price: 
    +
    +
    {x.price}
    +
    +
    +
    +
    Select date: 
    +
    +
    + + +
    +
    +
    +
    +
    Quant: 
    +
    +
    (select date)
    +
    +
    +
    + + {end:} + +
    + {if:option.ticket_selection.include_options_in_ticket_list} +
    {x.title}
    + {else:} +
    + {x.name} +
    + {term.nav.select} + {end:} +
    +
    + {if:x.descr} +

    {x.descr:h}

    + {end:} +
    + {if:!x.date_specific.value} + Use any date{if:x.start_date.timestamp} from {x.start_date.date} to {x.end_date.date}{end:}{if:!x.time_specific.value}, {end:} + {end:} + {if:!x.time_specific.value} + Use any time of day, + {else:} + Time: {x.ticket_time.time}, + {end:} + {if:x.unlimted_use.value} + Each {term.ticket.norm} may be used an unlimited number of times + {else:} + + {end:} +
    +
    +
    + {if:option.ticket_selection.include_options_in_ticket_list} +
    +
    +
    Price each: 
    +
    +
    {x.price}
    +
    +
    +
    +
    Select date: 
    +
    +
    + + +
    +
    +
    +
    +
    Quant: 
    +
    +
    (select date)
    +
    +
    +
    + + {end:} +
    + + + {end:} + +
    + + {end:} + + + +
    + {end:} +
    +
    + {end:} +{if:showTickets} + + +{end:} +
    + + + + + + \ No newline at end of file diff --git a/views/front/TicketsFoundation/Shop/ticketOpt.html b/views/front/TicketsFoundation/Shop/ticketOpt.html new file mode 100644 index 0000000..197419e --- /dev/null +++ b/views/front/TicketsFoundation/Shop/ticketOpt.html @@ -0,0 +1,286 @@ + + + + + +
    + +
    +
    Ticket Selection
    + + +
    + +
    {ticketOptText:h}
    + {if:reason} +
    +
    We're sorry, we had a problem with your request:
    +
      + {foreach:reason,r} +
    • {r:h}
    • + {end:} +
    +
    + {end:} +

    You have selected

    + +
    +
    +
    +
    {performanceDetail.name}
    +
    +
    +
    {term.prop.cap}: {performanceDetail.member_name}
    + + +
    +
    +
    +
    +
    {sectionDetail.name}
    +
    +
    + +
    +
    +
    +
    +
    {ticketDetail.name}
    +
    +
    + {if:!ticketDetail.date_specific.value} +
    Use any date {if:ticketDetail.start_date.timestamp} from {ticketDetail.start_date.date} to {ticketDetail.end_date.date}{end:}
    + {end:} + {if:!ticketDetail.time_specific.value} +
    Use any time
    + {else:} +
    Time: {ticketDetail.ticket_time.time}
    + {end:} + {if:!ticketDetail.unlimted_use.value} + + {else:} +
    Each {term.ticket.norm} may be used an unlimited number of times
    + {end:} +
    {ticketDetail.descr:h}
    +
    +
    +
    + +

    Please select from the following

    +
    +
    +
    +
    +
    +
    +
    +
    Select desired date:
    +
    +
    (click in field to set date)
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    Select Quantity:
    +
    +
    (please select date first)
    +
    +
    +
    +
    + {if:reason}
    (disabled - please see above)
    {else:}
    {term.nav.add_to_cart}
    {end:} +
    + + + + + + \ No newline at end of file diff --git a/views/front/TicketsFoundation/Shop/ticketSelect.html b/views/front/TicketsFoundation/Shop/ticketSelect.html new file mode 100644 index 0000000..cc806ba --- /dev/null +++ b/views/front/TicketsFoundation/Shop/ticketSelect.html @@ -0,0 +1,425 @@ + + + +
    + + + + + + + +
    +
    + + + {term.nav.show_selected} + {if:!option.ticket_selection.start_at_cart} + {term.nav.select_more} + {end:} + + +

    {ticketText:h}

    + +
    +
    + +{if:reason} +
    +
    +
    +

    We're sorry, we had a problem with your request:

    +
      + {foreach:reason,r}{Chuck} +
    • {r:h}
    • + {end:} +
    +
    +
    +
    +{end:} + + + +{foreach:sections,s} + +
    +
    +
    + +
    +
    +

    {performanceDetail.member_name:h}

    +

    {performanceDetail.name:h}

    +
    + {if:performanceDetail.image} +
    +
    +
    + {end:} +
    + + + +
    +
    + {if:!oneSectionOnly} +
    {s.sectionDetail.name}
    + {end:} + {if:performanceDetail.descr} + {performanceDetail.descr:h} + {end:} +
    +
    + +
    +
    +
    + + + + {foreach:s.ticketsData,x} + +
    +
    +
    + + + +
    +
    + {if:option.ticket_selection.include_options_in_ticket_list} +

    {x.title}

    + {else:} +

    {x.name}

    + {end:} +
    +
    +
    +
    + {if:x.descr} + {x.descr:h} + {end:} +

    + {if:!x.date_specific.value} + Use any date{if:x.start_date.timestamp} from {x.start_date.date} to {x.end_date.date}{end:}
    + {end:} + + {if:!x.time_specific.value} + Use any time of day, + {else:} + Time: {x.ticket_time.time} + {end:} + + {if:x.unlimted_use.value} + Each {term.ticket.norm} may be used an unlimited number of times + {end:} +

    +
    +
    + {if:option.ticket_selection.include_options_in_ticket_list} + +
    +
    + Price
    + {x.price} + +
    +
    + +
    +
    + +
    +
    + + + + {foreach:x.addons,a} + +
    +
     
    +
    + {a.name} - {a.unit_cost} +
    +
    + + + +
    +
    + + {end:} + + {end:} + +
    +
    +
    + + {end:} + +{end:} + + + + + +
    + +{if:option.ticket_selection.include_options_in_ticket_list} + + + {startScript:h} + var tickets = {ticketsJSON:h}; + + + + + + + +{end:} + \ No newline at end of file diff --git a/views/front/TicketsFoundation/foot.html b/views/front/TicketsFoundation/foot.html new file mode 100644 index 0000000..2353504 --- /dev/null +++ b/views/front/TicketsFoundation/foot.html @@ -0,0 +1,19 @@ + + + {if:option.development} +
    +
    +
    +
    +
    +
    Running on Development Server:
    +
    + +
    +
    +
    +
    + {end:} + diff --git a/views/front/TicketsFoundation/head.html b/views/front/TicketsFoundation/head.html new file mode 100644 index 0000000..f6cce73 --- /dev/null +++ b/views/front/TicketsFoundation/head.html @@ -0,0 +1,66 @@ + + + + + + {if:!jQueryLoaded} + + + + {end:} + + {if:!jQueryUiLoaded} + + + + + {end:} + + + + + + + {if:customCssFile} + + + + + {end:} + + {if:frontDebug} + + +
    + + + + + {end:} + + +
    +
    Updating your information
    Please wait ...
    +
    Updating
    Please wait ...
    +
    + + {if:adminUser} +

    Purchasing By Admin User

    + {end:} + \ No newline at end of file diff --git a/views/front/TicketsFoundation/index.html b/views/front/TicketsFoundation/index.html new file mode 100644 index 0000000..fca55f0 --- /dev/null +++ b/views/front/TicketsFoundation/index.html @@ -0,0 +1,34 @@ + + + + + + + + + + +

    PLEASE NOTE:

    + +

    + There is no general access to this site. + All access to this site should be through an appropriate link. + If you arrived here by mistake (or exploring), nothing but this message will be displayed. + If you have any concerns about this site, please contact Gaslight Media. +

    + +

    + Gaslight Media
    + 120 East Lake Street
    + Petoskey, MI 49770
    +  
    + Phone: 231-487-0692
    + E-Mail: info@gaslightmedia.com
    + Web: http://www.gaslightmedia.com +

    + + + + + + diff --git a/views/front/tickets/Debug/index.html b/views/front/tickets/Debug/index.html new file mode 100644 index 0000000..a42397f --- /dev/null +++ b/views/front/tickets/Debug/index.html @@ -0,0 +1,42 @@ + + + + + + +
    Startup: {debugStartupTime}
    +
    Event Management Front-End Debug
    +
    +
    + Updated: {debugUpdateTime} +
    +
    + {debugData:h} +
    + + + {startScript:h} + + // Reload the current window with Action = Debug_update + function reloadDebugWindow() + { + window.location("{baseSCRIPT}&Action=Debug_update"); + } + + + \ No newline at end of file diff --git a/views/front/tickets/Debug/start.html b/views/front/tickets/Debug/start.html new file mode 100644 index 0000000..66c3023 --- /dev/null +++ b/views/front/tickets/Debug/start.html @@ -0,0 +1,27 @@ + + + + + + +
    Startup: {debugStartupTime}
    +
    Event Management Front-End Debug
    +
    +
    Debug Startup
    + + \ No newline at end of file diff --git a/views/front/tickets/Shop/PayPalApproved.html b/views/front/tickets/Shop/PayPalApproved.html new file mode 100644 index 0000000..7df6e28 --- /dev/null +++ b/views/front/tickets/Shop/PayPalApproved.html @@ -0,0 +1,41 @@ + + + + + +
    + +

    Your PayPal payment has been approved.

    + + +
    + +

    + Your cart will now reflect that the payment has been made. +

    + +
    + +
    +
    Close This Window
    +
    + +
    + + + + diff --git a/views/front/tickets/Shop/PayPalFail.html b/views/front/tickets/Shop/PayPalFail.html new file mode 100644 index 0000000..9dcd4ec --- /dev/null +++ b/views/front/tickets/Shop/PayPalFail.html @@ -0,0 +1,49 @@ + + + + + +
    + +

    Unable to process your payment!

    + + +
    + +

    +

    Sorry, there was a problem.
    +

    + +

    + We were unable to find your purchase information and are therefore + are unable to process your payment through PayPal. This could be + due to you not performing any action with your pending purchase + for too long. Please click the "Return to selected tickets" button + at the top of the checkout page to see if your selections are still listed. +

    + +
    + +
    +
    Close This Window
    +
    + +
    + + + + diff --git a/views/front/tickets/Shop/cart.html b/views/front/tickets/Shop/cart.html new file mode 100644 index 0000000..e5e858d --- /dev/null +++ b/views/front/tickets/Shop/cart.html @@ -0,0 +1,410 @@ + + + +
    +
    + + +
    + + +
    + {if:!option.ticket_selection.start_at_cart} + {term.nav.select_more} + {end:} + +
    +
    + +
    {cartText:h}
    + {if:reason} +
    +
    We're sorry, we had a problem with your request:
    +
      + {foreach:reason,r}{Chuck} +
    • {r:h}
    • + {end:} +
    +
    + {end:} + {if:havePromoCodes} +
    +
    +
    If you have a {term.promo.norm}, please enter it here:
    +
    +
    + {end:} + {foreach:cart,c} +
    +
    {c.name}
    +
    + {foreach:c.performances,p} +
    +
    + {if:!option.ticket_selection.start_at_cart} + {term.nav.select_more_of_these} + {end:} +
    + +
    {p.name}
    +
    + {if:p.descr}
    {p.descr:h}
    {end:} + {if:p.short_descr}
    {p.short_descr:h}
    {end:} + {if:option.cart_images}{if:p.image} + + {end:}{end:} +
    +
    +
    +
    + {foreach:p.dates,d} +
    + {if:d.dateSpecific} + {d.fullDate} + {else:} + Use any date + {if:c.likelyDate} + - Likely Date {c.likelyDate} + {end:} + {end:} + {foreach:d.sections,s} + + + + {if:!p.oneSectionOnly} + + {end:} + + + + + {foreach:s.tickets,i} + + + {if:!p.oneSectionOnly} + + {end:} + + + + + {if:i.problem} + + + + {end:} + {if:i.descr} + + + {if:!p.oneSectionOnly} + + + {end:} + + {foreach:i.addons,a} + + + {if:!p.oneSectionOnly} + + {end:} + + + + + {end:} + + + {if:i.promo} + + + {if:!p.oneSectionOnly} + + {end:} + + + + {end:} + + {end:} +
    QuantSection{term.ticket.cap}PriceTotal
    + + {s.name}{i.title}{if:i.show_price}{i.price}{end:}{if:i.show_price}{i.extended}{end:}
     {i.problemText}
      + {else:} + + {end:} + {if:option.cart_images}{if:i.image} +
    + {end:}{end:} +
    {i.descr:h}
    +
       +
    + +
    +
    {a.unit_cost}/{a.unit_name}{a.money}
      {term.promo.cap}: {promoCode}  + {i.promo.credit}
    + {end:} +
    + {end:} +
    +
    + {end:} +
    + {if:c.ticket_policy}
    {c.ticket_policy:h}
    {end:} + + {if:c.needAssignemntOrDate} + {if:c.needAssignment} + +
    + {if:!c.haveAssignment} +
    {text.cart.select_assignment_location}
    + {else:} +
    {text.cart.select_assignment_location}
    + {end:} + {foreach:c.assignmentMembers,a} + {if:a.entrances} + {foreach:a.entrances,e} +
    + {if:option.cart_images} + {if:e.image} +
    + {end:} + {end:} +
    + {if:e.selected} + {a.name} - {e.name}
    + {else:} + {a.name} - {e.name}
    + {end:} +
    +
    {e.addr1}{if:e.addr2}, {e.addr2}{end:}, {e.city}
    +
    {e.phone}
    + {if:e.descr} +
    {e.descr:h}
    + {end:} +
    +
    + {end:} +
    + {else:} + {if:a.selected} + {a.name}
    + {else:} + {a.name}
    + {end:} + {end:} + {end:} +  
    + {end:} + + {if:option.ask_for_likely_date} + {if:c.needLikelyDate} +
    + {if:!c.likelyDate} + + {else:} + + {end:} + {text.cart.select_likely_date}   + + mm/dd/yyyy +
    + {end:} + {end:} +
    +
    + {end:} + {if:!c.needAssignment} + + {if:option.cart_images}{if:c.image} +
    + + +
    + {end:}{end:} + {end:} + + + + +
    + {end:} + + +
    + {if:cartHasContents} +
    + Grand Total   {totals.price} +
    +
    + {if:totals.tickets} + {if:!blockCheckout} + {term.nav.checkout} + {else:} + Please complete the items in RED above. + {end:} + {else:} + Your cart is currently empty. + {end:} +
    + {else:} +

    Your cart is currently empty.

    + {end:} +
    + + {if:option.cart_promotions} +
    + You may also be interested in ...
    + {foreach:cartPromotions,p} +
    + + {if:p.image} +
    + {end:} +
    + + {if:p.short_descr}
    {p.short_descr:h}
    {end:} + {if:p.short_descr}
    {p.short_descr:h}
    {end:} +
    +
    + {end:} +
    + {end:} + + + +
    + +{startScript:h} + + $(document).ready(function(){ + + // Block direct form submission - Everything submits by jQuery action + $('#cartForm').submit(function( event ) { + return false; + }); + + // Convert input fields to select lists + $('.glmCartQuant').each(function() { + + var id = $(this).attr('id'); + var ticket = $(this).attr('data-ticket'); + var addon = $(this).attr('data-addon'); + var max = $(this).attr('data-max'); + var value = $(this).attr('value'); + var units = $(this).attr('data-units'); + var numbSel = ''; + + // Build a picklist for this input + for (var i = 0 ; i {lte:h} max ; i++) { + if (value == i) { + numbSel = numbSel.concat(''); + } else { + numbSel = numbSel.concat(''); + } + } + + $('#quant_' + id).html('' + units); + + }); + + // Get or set vertical scroll to return to same place when cart reloads + function getVertScroll() { + var vertScroll = window.pageYOffset; + if (vertScroll == 0) { + var vertScroll = document.documentElement.scrollTop; + } + if (vertScroll == 0) { + var vertScroll = document.body.scrollTop; + } + return vertScroll; + } + + // When a cart value changes, submit it as a cart update. + $('.glmCartSelect').change(function() { + vertScroll = getVertScroll(); + var ticket = $(this).attr('data-ticket'); + var addon = $(this).attr('data-addon'); + var value = $(this).val(); + + setBlocker(); + window.location = "{baseSCRIPT}&Action=Shop_cart&cart=update&ticket_inv=" + ticket + "&addon=" + addon + "&quant=" + value + "&vertScroll=" + vertScroll; + + }); + + // When there's a change in the promo code input, submit it. + $('#promoCodeInput').change(function() { + var value = $(this).val(); + setBlocker(); + window.location = "{baseSCRIPT}&Action=Shop_cart&cart=promo_code&promo_code=" + value; + }); + + // When a member selection for unassigned items changes, submit it so it's in the session + $('.glmAssignmentChange').change(function() { + vertScroll = getVertScroll(); + var member = $(this).attr('data-Member'); + var assignedTo = $(this).val(); + var assignedToEntrance = $(this).attr('data-entrance'); + setBlocker(); + window.location = "{baseSCRIPT}&Action=Shop_cart&cart=update_assignment&member_assigned=" + member + "&assigned_to=" + assignedTo + "&entrance_assigned=" + assignedToEntrance + "&vertScroll=" + vertScroll; + }); + + // When a likely departure date changes, submit it so it's in the session + $('.glmLikelyDateChange').change(function() { + vertScroll = getVertScroll(); + var member = $(this).attr('data-Member'); + var likelyDate = $(this).val(); + setBlocker(); + window.location = "{baseSCRIPT}&Action=Shop_cart&cart=update_likelyDate&member=" + member + "&likely_date=" + likelyDate + "&vertScroll=" + vertScroll; + + }); + + // Code to start datepicker for each date input + if($("#likelyDateInput").length > 0) { + $("#likelyDateInput").datepicker({ + dateFormat: "mm/dd/yy", + minDate: -1, + maxDate: 365 + }); + } + + // Checkout action + $('#GLMcheckoutBtn').click(function() { + setBlocker(); + window.location = "{baseSCRIPT}&Action=Shop_checkout"; + }); + + function setBlocker() { + $('#glmReloadBlocker').show(); + } + + $('#GLMnavSelectEvent').on('click', function() { // Return to Event Selection + setBlocker(); + window.location = '{startURL:h}'; + }); + +/* Not using right now + // Reprint order button + $('#reprintVoucher').on('keypress', function(event) { + if(event.which == '13'){ + var orderID = $(this).val(); + var voucherWindow = window.open('{appAdminURL}&Action=Order_printVoucher&OrderID=' + orderID, + "voucherPrint", + "height=750,width=600,menubar=yes,toolbar=yes,alwaysRaised=yes,menu" + ); + voucherWindow.focus(); + voucherWindow.print(); + return false; + } + }); +*/ + + if ({vertScroll}) { + window.scrollTo(0,{vertScroll}); + } + + }); + + + diff --git a/views/front/tickets/Shop/checkout.html b/views/front/tickets/Shop/checkout.html new file mode 100644 index 0000000..057d6e1 --- /dev/null +++ b/views/front/tickets/Shop/checkout.html @@ -0,0 +1,717 @@ + + + +
    + +
    +
    Selected {term.ticket.plur_cap}
    + +
    + {term.nav.show_selected} + {if:!option.ticket_selection.start_at_cart} + {term.nav.select_more} + {end:} +
    +
    + +
    {checkoutText:h}
    + {if:reason} +
    +
    We're sorry, we had a problem with your request:
    +
      + {foreach:reason,r} +
    • {r:h}
    • + {end:} +
    +

    See below for more information.

    +
    + {end:} +
    + + +
    +
    Contact Information
    + +
    +
    +
    {text.cart.checkout.first_name}:
    +
    {text.cart.checkout.first_name}:
    + {if:formData.contact.fname.problem} +
    +
    {formData.contact.fname.problem}
    + {else:} +
    + {end:} + +
    +
    +
    +
    {text.cart.checkout.last_name}:
    +
    {text.cart.checkout.last_name}:
    + {if:formData.contact.lname.problem} +
    +
    {formData.contact.lname.problem}
    + {else:} +
    + {end:} + +
    +
    +
    +
    {text.cart.checkout.address}:
    +
    {text.cart.checkout.address}:
    + {if:formData.contact.addr1.problem} +
    +
    {formData.contact.addr1.problem}
    + {else:} +
    + {end:} + +
    +
    +
    +
     
    +
     
    + {if:formData.contact.addr2.problem} +
    +
    {formData.contact.addr2.problem}
    + {else:} +
    + {end:} + +
    +
    +
    +
    {text.cart.checkout.city}:
    +
    {text.cart.checkout.city}:
    + {if:formData.contact.city.problem} +
    +
    {formData.contact.city.problem}
    + {else:} +
    + {end:} + +
    +
    +
    +
    {text.cart.checkout.state}:
    +
    {text.cart.checkout.state}:
    + {if:formData.contact.state.problem} +
    +
    {formData.contact.state.problem}
    + {else:} +
    + {end:} + +
    +
    +
    +
    {text.cart.checkout.country}:
    +
    {text.cart.checkout.country}:
    + {if:formData.contact.country.problem} +
    +
    {formData.contact.country.problem}
    + {else:} +
    + {end:} + +
    +
    +
    +
    {text.cart.checkout.zip}:
    +
    {text.cart.checkout.zip}:
    + {if:formData.contact.zip.problem} +
    +
    {formData.contact.zip.problem}
    + {else:} +
    + {end:} + +
    +
    +
    +
    {text.cart.checkout.phone}:
    +
    {text.cart.checkout.phone}:
    + {if:formData.contact.phone.problem} +
    +
    {formData.contact.phone.problem}
    + {else:} +
    + {end:} + +
    +
    +
    +
    {text.cart.checkout.email}:
    +
    {text.cart.checkout.email}:
    + {if:formData.contact.email.problem} +
    +
    {formData.contact.email.problem}
    + {else:} +
    + {end:} + +
    +
    +
    +
    {text.cart.checkout.email_again}:
    +
    {text.cart.checkout.email_again}:
    + {if:formData.contact.email2.problem} +
    +
    {formData.contact.email2.problem}
    + {else:} +
    + {end:} + +
    +
    +
    +
    OK to Send E-Mail?
    + {if:formData.contact.email_ok} +
    {text.cart.checkout.activities_offers}
    + {else:} +
    {text.cart.checkout.activities_offers}
    + {end:} +
    + + {if:opt_field_1_name} +
    +
    {opt_field_1_name}:
    +
    {opt_field_1_name}:
    + {if:formData.contact.opt_field_1.problem} +
    +
    {formData.contact.opt_field_1.problem}
    + {else:} +
    + {end:} + +
    +
    + {end:} + {if:opt_field_2_name} +
    +
    {opt_field_2_name}:
    +
    {opt_field_2_name}:
    + {if:formData.contact.opt_field_2.problem} +
    +
    {formData.contact.opt_field_2.problem}
    + {else:} +
    + {end:} + +
    +
    + {end:} + {if:opt_field_3_name} +
    +
    {opt_field_3_name}:
    +
    {opt_field_3_name}:
    + {if:formData.contact.opt_field_3.problem} +
    +
    {formData.contact.opt_field_3.problem}
    + {else:} +
    + {end:} + +
    +
    + {end:} + + +
    +
    + + {foreach:cart,c} +
    +
    {term.prop.cap}: {c.name}
    + + +
    + {foreach:c.performances,p} +
    +
    +
    +
    +
    {p.name}
    +
    + + {if:option.cart_images}{if:option.cart_images}{if:p.image}{end:}{end:}{end:} +
    +
    +
    +
    + {foreach:p.dates,d} +
    +
    + + {if:d.dateSpecific} + {d.fullDate} + {else:} + Use any date + {if:c.likelyDate} + - Likely Date {c.likelyDate} + {end:} + {end:} + +
    + + + {foreach:d.sections,s} + + + + {if:!p.oneSectionOnly} + + {end:} + + + + + {foreach:s.tickets,i} + + + {if:!p.oneSectionOnly} + + {end:} + + + + + {if:i.descr} + + + {if:!p.oneSectionOnly} + + + {end:} + + {foreach:i.addons,a} + + + {if:!p.oneSectionOnly} + + {end:} + + + + + {end:} + + {if:i.promo} + + + {if:!p.oneSectionOnly} + + {end:} + + + + {end:} + {end:} +
    QuantSection{term.ticket.cap}PriceTotal
    + {i.selected} + {s.name}{i.title}{if:i.show_price}{i.price}{end:}{if:i.show_price}{i.extended}{end:}
      + {else:} + + {end:} + {if:option.cart_images} + {if:i.image} +
    + {end:} + {end:} +
    {i.descr:h}
    +
       +
    + {a.selected} {a.unit_name} +
    +
    {a.unit_cost}/{a.unit_name}{a.money}
      {term.promo.cap}: {promoCode}  + {i.promo.credit}
    + {end:} +
    + {end:} +
    +
    + {if:p.policy} +
    +
    + Please read and agree to our policy for this {term.performance.norm}. +
    +
    +

    {p.policy:h}

    +
    +
    +

    I agree to the policy stated above.

    +
    +
    + {end:} +
    + {end:} +
    + + {if:c.ticket_policy}
    {c.ticket_policy:h}
    {end:} + {if:c.ticket_policy}
    {c.ticket_policy:h}
    {end:} + +
    + + {if:c.ticket_spec_req.value} +
    +
    Please enter any special requests:
    +
    +
    + {end:} +
    Payment for {term.ticket.plur} at {c.name}
    +
    + + {if:c.paymentResult} + {if:c.paymentResult.approved} +
    Card Payment Approved
    +
    Card Type
    {c.paymentResult.cctype}
    +
    Name on Card
    {c.paymentResult.ccname}
    +
    Card Number
    {c.paymentResult.ccnumb}
    +
    Expiration Date
    {c.paymentResult.ccexp}
    +
    Authorization Code
    {c.paymentResult.authCode}
    +
    +
    {term.nav.print_vouchers}
    +
    + {else:} +
    Card Payment Not Complete
    +
    • {c.paymentResult.description}
    +

    Please check the payment information below and try again or contact your credit card company for assistance.

    + {if:forceCheckoutPhase} +
    +
    {term.nav.delete_from_cart}
    +
    + {end:} + {end:} + {end:} + {if:c.paymentResult.approved} +

    Payment Accepted

    + {else:} + {if:c.havePaymentMethod} + +
    + {if:c.havePayPal} + {if:c.haveMultiplePaymentMethods} +  PayPal + {else:} + + {end:} + {end:} + {if:c.haveCreditCards} + {if:c.havePayPal} +      + {end:} + {if:c.haveMultiplePaymentMethods} +  Credit Card + {else:} + + {end:} + {end:} +
    + + {if:c.haveCreditCards} + {if:c.haveMultiplePaymentMethods} + + {else:} + + {end:} +
    +
    Total Charged to this Card
    +
    {c.totalPrice}
    +
    +
    +
    Card Type
    +
    Card Type
    + {if:c.paymentForm.cctype.problem} +
    +
    {c.paymentForm.cctype.problem}
    + {else:} +
    + {end:} + +
    +
    +
    +
    Name on Card
    +
    Name on Card
    + {if:c.paymentForm.ccname.problem} +
    +
    {c.paymentForm.ccname.problem}
    + {else:} +
    + {end:} + +
    +
    +
    +
    Card Number
    +
    Card Number
    + {if:c.paymentForm.ccnumb.problem} +
    +
    {c.paymentForm.ccnumb.problem}
    + {else:} +
    + {end:} + +
    +
    +
    +
    Expiration Date
    +
    Expiration Date
    + {if:c.paymentForm.ccexp.problem} +
    +
    {c.paymentForm.ccexp.problem}
    + {else:} +
    + {end:} + Month + + Year + +
    +
    +
    +
    Security Code
    +
    Security Code
    + {if:c.paymentForm.cccode.problem} +
    +
    {c.paymentForm.cccode.problem}
    + {else:} +
    + {end:} + +
    +
    +
    +
    + The Security Code is the three or four digit number on the signature side of your credit card. +
    +
    + + {end:} + {if:c.havePayPal} + + {if:c.haveMultiplePaymentMethods} + + {else:} + + {end:} +
    + +
    +
    + {end:} + {if:c.haveMultiplePaymentMethods} + +
    Please select a Payment Method
    +
    + {end:} + {else:} + +
    + This {term.prop.norm} does not have a payment method configured. + Please call this {term.prop.norm} to purchase {term.ticket.plur}. +
    +
    + {end:} + {end:} +
    +
    +
    + {end:} + + +
    +
    +
    Complete Purchase
    + +

    + {ssl_seal_head_script:h} + {ssl_seal_body_script:h} +

    +
    +
    +
    + +
    + +
    Grand Total
    +
    +
    + +
    {totals.price}
    +
    +
    + {if:!cartHasOneVenueOnly} +
    + NOTE: There will be a separate order number and a separate credit card transaction for each {term.prop.norm}. +
    + {end:} +
    + {if:!blockCheckout} + {term.nav.purchase} + {else:} + Unable to checkout - please see above. + {end:} +
    +
    +
    + +
    + + + + + + \ No newline at end of file diff --git a/views/front/tickets/Shop/checkoutSuccess.html b/views/front/tickets/Shop/checkoutSuccess.html new file mode 100644 index 0000000..c295276 --- /dev/null +++ b/views/front/tickets/Shop/checkoutSuccess.html @@ -0,0 +1,367 @@ + + + + + +
    + + +
    Purchase Complete
    + + + + + {foreach:cart,c} + {if:c.paymentResult} + {if:c.paymentResult.approved} +

    +

    *** {term.nav.print_vouchers} for {c.name} ***
    +

    + {end:} + {end:} + {end:} + + + +
    +
    + +
    +
    + +

    + Adobe Reader is required to view and print your {term.voucher.plur}. Adobe Reader is a free program available directly from Adobe. + If you do not already have Adobe Reader installed, click the "Get Adobe Reader" link now. +

    +
    +
    +
    + +

    + If you are unable to print your {term.voucher.plur}, please print this page or write down the order number(s) + below and bring that to the ticket office when you arrive. +

    + ORDER #: + {foreach:cart,c} + {if:c.paymentResult} + {if:c.paymentResult.approved} + {c.paymentResult.orderID}  + {end:} + {end:} + {end:} +
    +
    +
    + + +
    {successText:h}
    + +
    +
    Contact Information
    +
    +
    First Name:
    {formData.contact.fname.value}
    +
    Last Name:
    {formData.contact.lname.value}
    +
    Address:
    {formData.contact.addr1.value}
    +
     
    {formData.contact.addr2.value}
    +
    City:
    {formData.contact.city.value}
    +
    State:
    {formData.contact.state.value}
    +
    Country:
    {formData.contact.country.value}
    +
    ZIP/Postal Code:
    {formData.contact.zip.value}
    +
    Phone:
    {formData.contact.phone.value}
    +
    E-Mail address:
    {formData.contact.email.value}
    + {if:opt_field_1_name}
    {opt_field_1_name}:
    {formData.contact.opt_field_1.value:h}
    {end:} + {if:opt_field_2_name}
    {opt_field_2_name}:
    {formData.contact.opt_field_2.value:h}
    {end:} + {if:opt_field_3_name}
    {opt_field_3_name}:
    {formData.contact.opt_field_3.value:h}
    {end:} +
     
    + {if:formData.contact.email_ok} + You have asked us to send information on activities and offers. + {else:} + You have asked us to NOT send information on activities and offers.
    + We will only contact you regarding this order. + {end:} +
    + +
    + +
    + + + {foreach:cart,c} +
    + +
    {term.ticket.plur_cap} at: {c.name}
    + + +
    + {if:c.descr}
    {c.descr:h}
    {end:} + {if:option.cart_images}{if:c.image}{end:}{end:} + +
    + +
    + + {foreach:c.performances,p} + +
    + +
    +
    +
    + {term.performance.cap}: {p.name} +
    +
    + + {if:option.cart_images}{if:option.cart_images}{if:p.image}{end:}{end:}{end:} +
    +
    +
    + +
    + {foreach:p.dates,d} + +
    + {term.ticket.cap} date: + + {if:d.dateSpecific} + {d.fullDate} + {else:} + Use any date + {if:c.likelyDate} + - Likely Date {c.likelyDate} + {end:} + {end:} + +
    + + + {foreach:d.sections,s} + + + + {if:!p.oneSectionOnly} + + {end:} + + + + + {foreach:s.tickets,i} + + + {if:!p.oneSectionOnly} + + {end:} + + + + + {if:i.descr} + + + {if:!p.oneSectionOnly} + + + {end:} + + {foreach:i.addons,a} + + + {if:!p.oneSectionOnly} + + {end:} + + + + + {end:} + + {if:i.promo} + + + {if:!p.oneSectionOnly} + + {end:} + + + + {end:} + {end:} +
    QuantSection{term.ticket.cap}PriceTotal
    + {i.selected} + {s.name}{i.title}{if:i.show_price}{i.price}{end:}{if:i.show_price}{i.extended}{end:}
      + {else:} + + {end:} + {if:option.cart_images} + {if:i.image} +
    + {end:} + {end:} +
    {i.descr:h}
    +
       +
    + {a.selected} {a.unit_name} +
    +
    {a.unit_cost}/{a.unit_name}{a.money}
      {term.promo.cap}: {promoCode}  + {i.promo.credit}
    + {end:} + + + {end:} + +
    + +
    + + {if:p.policy} +
    +
    +
    + Our policy for this {term.performance.norm}. +
    +

    {p.policy:h}

    +
    +
    + {end:} + + {end:} + +
    + + + + {if:!cartHasOneVenueOnly} + +
    +
    +
    +
    Sub Total
    +
    +
    +
    {c.totalPrice}
    +
    +
    +
    + {end:} + + {if:c.ticket_policy}
    {c.ticket_policy:h}
    {end:} + + + {if:c.ticket_policy}
    {c.ticket_policy:h}
    {end:} + + +
    + + + {if:c.ticket_spec_req.value} +
    +
    Special requests:
    +
    {c.paymentForm.spec_req.value:h}
    +
    + {end:} + + + {if:c.paymentResult} +
    + {if:c.paymentResult.approved} +
    Card Payment Approved
    + +
    Card Type
    {c.paymentResult.cctype}
    +
    Name on Card
    {c.paymentResult.ccname}
    +
    Card Number
    {c.paymentResult.ccnumb}
    +
    Expiration Date
    {c.paymentResult.ccexp}
    +
    Authorization Code
    {c.paymentResult.authCode}
    +
    +
    {term.nav.print_vouchers}
    +
    + {else:} +
    Card Payment Not Complete
    +
    • {c.paymentResult.description}
    +

    Please check the payment information below and try again or contact your credit card company for assistance.

    + {if:forceCheckoutPhase} +
    +
    {term.nav.delete_from_cart}
    +
    + {end:} + + {end:} + +
    + {end:} + +
    + +
    + + {end:} + +
    + {if:cartHasContents} +
    +
    Cart Totals
    +
    +
    +
    Grand Total
    +
    +
    +
    {totals.price}
    +
    +
    +
    + {else:} +

    Your cart is currently empty.

    + {end:} +
    + +
    + +{trackingScript:h} + + + + + \ No newline at end of file diff --git a/views/front/tickets/Shop/paymentSummary.html b/views/front/tickets/Shop/paymentSummary.html new file mode 100644 index 0000000..de870b4 --- /dev/null +++ b/views/front/tickets/Shop/paymentSummary.html @@ -0,0 +1,103 @@ +

    + + Click here to reprint your {term.voucher.plur} + +

    + +

    + {term.ticket.plur_cap} Purchased at:
    + {cartEntry.name} +

    + + +{if:cartEntry.descr}

    {cartEntry.descr:h}

    {end:} + + + + + + + + + + + +{foreach:cartEntry.performances,p} + {foreach:p.dates,d} + {foreach:d.sections,s} + + + {foreach:s.tickets,i} + + + + + + + + {foreach:i.addons,a} + + + + + + + + {end:} + {if:i.promo} + + + + + + + {end:} + {end:} + + + {end:} + {end:} +{end:} + + + + + + + + +
    Quant{term.performance.cap}{term.ticket.cap}PriceTotal
    {i.selected}{p.name:h}{i.title:h}{if:i.show_price}{i.price}{end:}{if:i.show_price}{i.extended}{end:}
       +
    + {a.selected} {a.unit_name} +
    +
    {a.unit_cost}/{a.unit_name}{a.money}
      {term.promo.cap}: {promoCode}  + {i.promo.credit}
     {cartEntry.totalPrice}
    + + +{if:cartEntry.ticket_spec_req} +

    + Special requests: {cartEntry.paymentForm.spec_req.value:h} +

    +{end:} + + +{if:cartEntry.ticket_policy}

    {cartEntry.ticket_policy:h}

    {end:} + +

    + + + + + + + +
    Credit Card Payment Approved
    Card Type{cartEntry.paymentResult.cctype}
    Name on Card{cartEntry.paymentResult.ccname}
    Card Number{cartEntry.paymentResult.ccnumb}
    Expiration Date{cartEntry.paymentResult.ccexp}
    Authorization Code{cartEntry.paymentResult.authCode}
    +

    + + \ No newline at end of file diff --git a/views/front/tickets/Shop/sectionSelect.html b/views/front/tickets/Shop/sectionSelect.html new file mode 100644 index 0000000..54bf3d5 --- /dev/null +++ b/views/front/tickets/Shop/sectionSelect.html @@ -0,0 +1,96 @@ + + + + + + +
    + + +
    {term.section.cap} Selection
    + + + + + +
    {sectionText:h}
    + +{if:reason} +
    +
    We're sorry, we had a problem with your request:
    +
      + {foreach:reason,r} +
    • {r:h}
    • + {end:} +
    +
    +{end:} + +

    You have selected

    +
    +
    +
    +
    {performanceDetail.member_name}

    +
    {performanceDetail.name}
    +
    +
    + + +
    +
    +
    + + +
    +

    Please select from the following

    +
    +{foreach:sectionList,x} +
    + +
    +

    {term.section.cap}: {x.member_name}

    +

    {x.descr:h}

    +
    +
    +{end:} + +
    + +
    + + {startScript:h} + + $(document).ready(function(){ + + // Code to kick off the geolocation-display feature + $("#locationMap").geolocate({ + lat: "#lat", + lng: "#lon", + mapOptions: { + disableDefaultUI: false, + mapTypeControl: true, + mapTypeId: "roadmap", + zoom: 12 + }, + markerOptions: { + draggable: false, + title: "This is your selected location" + } + }); + + }); + + + \ No newline at end of file diff --git a/views/front/tickets/Shop/start.html b/views/front/tickets/Shop/start.html new file mode 100644 index 0000000..0433743 --- /dev/null +++ b/views/front/tickets/Shop/start.html @@ -0,0 +1,398 @@ + + + +
    + +
    +
    {term.event.cap} Selection
    + + +
    + +
    {introText:h}
    + {if:reason} +
    +
    We're sorry, we had a problem with your request:
    +
      + {foreach:reason,r} +
    • {r:h}
    • + {end:} +
    +
    + {end:} +

    Please select from the following

    +{if:showTickets} +
    + + + + +{end:} + + {foreach:membersList,m} +
    +
    +
    +
    +
    {m.name}
    +
    +
    +
    Address: {m.addr1}{if:m.addr2}, {m.addr2}{end:}, {m.city}
    +
    Phone #: {m.phone}
    +
    {m.descr:h}
    +
    +
    + {if:option.select_images} + {if:m.image} +
    + {end:} + {end:} + +
    + {foreach:m.performances,p} +
    +
    +
    +
    + {if:showTickets} + {p.name} + {else:} + {p.name} + {end:} +
    +
    +
    +
    {term.prop.cap}: {p.member_name}
    +
    Dates: {p.start_date.date} through {p.end_date.date}
    +
    {p.descr:h}
    +
    +
    + {if:option.select_images} + {if:p.image} +
    + {end:} + {end:} + {if:!showTickets} + + {end:} + + + + {foreach:p.sections,s} +

     

    +
    +
    +
    + {if:!p.oneSectionOnly} + {s.sectionDetail.name}
    + {end:} + +
    + +
    +
    + + + {foreach:s.ticketsData,x} +
    + {if:option.ticket_selection.include_options_in_ticket_list} +
    +
    +
    Price: 
    +
    +
    {x.price}
    +
    +
    +
    +
    Select date: 
    +
    +
    + + +
    +
    +
    +
    +
    Quant: 
    +
    +
    (select date)
    +
    +
    +
    + + {end:} + +
    + {if:option.ticket_selection.include_options_in_ticket_list} +
    {x.title}
    + {else:} +
    + {x.name} +
    + {term.nav.select} + {end:} +
    +
    + {if:x.descr} +

    {x.descr:h}

    + {end:} +
    + {if:!x.date_specific.value} + Use any date{if:x.start_date.timestamp} from {x.start_date.date} to {x.end_date.date}{end:}{if:!x.time_specific.value}, {end:} + {end:} + {if:!x.time_specific.value} + Use any time of day, + {else:} + Time: {x.ticket_time.time}, + {end:} + {if:x.unlimted_use.value} + Each {term.ticket.norm} may be used an unlimited number of times + {else:} + + {end:} +
    +
    +
    + {if:option.ticket_selection.include_options_in_ticket_list} +
    +
    +
    Price each: 
    +
    +
    {x.price}
    +
    +
    +
    +
    Select date: 
    +
    +
    + + +
    +
    +
    +
    +
    Quant: 
    +
    +
    (select date)
    +
    +
    +
    + + {end:} +
    + + + {end:} + +
    + + {end:} + + + +
    + {end:} +
    +
    + {end:} +{if:showTickets} + +
    +{end:} +
    + +{startScript:h} + + var addButtonPushed = false; + + // Dates for inventory data + var tickets = {ticketsJSON:h}; + + var ticketQuantSelection = '\ + \ + '; + + var ticketTooLate = '\ +

    \ + Sorry, too late to select these {term.ticket.plur} on-line.\ +

    \ + '; + + + + $(document).ready(function(){ + + // Code to kick off the geolocation-display feature + function doLocationMap(id) { + $("#locationMap_" + id).geolocate({ + lat: "#lat_" + id, + lng: "#lon_" + id, + mapOptions: { + disableDefaultUI: false, + mapTypeControl: true, + mapTypeId: "roadmap", + zoom: 12 + }, + markerOptions: { + draggable: false, + title: "This is your selected location" + } + }); + } + {foreach:membersList,m} + doLocationMap({m.id}); + {end:} + + // DatePicker action + function avail(date) { + m = (date.getMonth()+1); + if (m < 10) { + m = '0' + m; + } + d = date.getDate(); + if (d < 10) { + d = '0' + d; + } + y = date.getFullYear(); + mdy = m + '/' + d + '/' + y; + if (dates[mdy]) { + return [true,"","Available"]; + } else { + return [false,"","Not Available"]; + } + } + + // for each ticket + $.each(tickets, function(index, ticket) { + + var inventory = ticket.inventory; + + // Build date data array and count dates for this ticket + var dateCount = 0; + var dateData = false + $.each(inventory, function(index, date) { + + // Count the number of dates + dateCount++; + + // If this is the first one, store it in case it's the only one + dateData = date; + + }); // each date + + // if there's no date specific tickets + if (!ticket.dateSpecific) { + + // Populate date input field + $('#GLMeventDateSelect_' + ticket.id).html(''); + doQuantSelection(ticket.id, dateData.id, dateData.available, dateData.tooLate); + + // if there's only one date, then display that and move on. + } else if (!ticket.dateSpecific || dateCount == 1) { + + // populate date input field + $('#GLMeventDate_' + ticket.id).html('
    Date:
    ' + dateData['date'] + '
    '); + doQuantSelection(ticket.id, dateData.id, dateData.available, dateData.tooLate); + + } else { + + // DatePicker action + function avail(date) { + m = (date.getMonth()+1); + if (m < 10) { + m = '0' + m; + } + d = date.getDate(); + if (d < 10) { + d = '0' + d; + } + y = date.getFullYear(); + mdy = m + '/' + d + '/' + y; + if (inventory[mdy]) { + return [true,"","Available"]; + } else { + return [false,"","Not Available"]; + } + } + + // Use the date picker to select a date + $('#GLMeventDateInput_' + ticket.id).datepicker({ + beforeShowDay: avail, + dateFormat: "mm/dd/yy", +// *** NEED TO FIX REFERENCE TO "performanceDetail" since that's not available on this page + minDate: "{performanceDetail.start_date.date}", + maxDate: "{performanceDetail.end_date.date}", + onSelect: function(selectedDate, inst) { + // Get data for the selected date + dateData = inventory[selectedDate]; + $('#GLMeventInvID_' + ticket.id).val(dateData.id); + doQuantSelection(ticket.id, dateData.id, dateData.available, dateData.tooLate); + } // Date Selection + + }); // Date Picker + + + } + + }); // each ticket + + function doQuantSelection(id, invId, available, tooLate) { + + // Build the ticket quant options + var ticketQuants = ''; + var selectMax = available; + if (selectMax > 50) { + selectMax = 50; + } + + if (tooLate) { + $('#GLMticketQuantContainer_' + id).html(ticketTooLate); + } else { + + // note that the braced lte below is needed to inject a less-than-or-equal-to operator without having flexy chew on it. + for (var i = 1; i {lte:h} (selectMax*1); i++) { + ticketQuants = ticketQuants.concat(''); + } + + // Populate the ticket quantity container + tmpQuantSel = ticketQuantSelection.replace(/\[id\]/g, id); + $('#GLMticketQuantContainer_' + id).html(tmpQuantSel.replace(/\[ticket-quants\]/g, ticketQuants)); + } + + } + + $('#GLMselectButton').click(function() { + + // Check for a selected ticket + var ticketSelected = false; + $('.glmTicketQuant').each(function( index ) { + if ($(this).val() != '') { + ticketSelected = true; + } + }); + + if (ticketSelected) { + selectButtonPressed = true; + setBlocker(); + $('#GLMselectForm').submit(); + } else { + alert('Please select a {term.ticket.norm} quantity.') + return false; + } + + }); + + function setBlocker() { + $('#glmReloadBlocker').show(); + } + + }); + + + \ No newline at end of file diff --git a/views/front/tickets/Shop/ticketOpt.html b/views/front/tickets/Shop/ticketOpt.html new file mode 100644 index 0000000..5acf967 --- /dev/null +++ b/views/front/tickets/Shop/ticketOpt.html @@ -0,0 +1,273 @@ + + + + + +
    + +
    +
    Ticket Selection
    + + +
    + +
    {ticketOptText:h}
    + {if:reason} +
    +
    We're sorry, we had a problem with your request:
    +
      + {foreach:reason,r} +
    • {r:h}
    • + {end:} +
    +
    + {end:} +

    You have selected

    + +
    +
    +
    +
    {performanceDetail.name}
    +
    +
    +
    {term.prop.cap}: {performanceDetail.member_name}
    + + +
    +
    +
    +
    +
    {sectionDetail.name}
    +
    +
    + +
    +
    +
    +
    +
    {ticketDetail.name}
    +
    +
    + {if:!ticketDetail.date_specific.value} +
    Use any date {if:ticketDetail.start_date.timestamp} from {ticketDetail.start_date.date} to {ticketDetail.end_date.date}{end:}
    + {end:} + {if:!ticketDetail.time_specific.value} +
    Use any time
    + {else:} +
    Time: {ticketDetail.ticket_time.time}
    + {end:} + {if:!ticketDetail.unlimted_use.value} + + {else:} +
    Each {term.ticket.norm} may be used an unlimited number of times
    + {end:} +
    {ticketDetail.descr:h}
    +
    +
    +
    + +

    Please select from the following

    +
    +
    +
    +
    +
    +
    +
    +
    Select desired date:
    +
    +
    (click in field to set date)
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    Select Quantity:
    +
    +
    (please select date first)
    +
    +
    +
    +
    + {if:reason}
    (disabled - please see above)
    {else:}
    {term.nav.add_to_cart}
    {end:} +
    + +{startScript:h} + + // Whether ticket has date specific inventory + var dateSpecific = {ticketDetail.date_specific.value} + 0; + + // Dates for inventory data + var dates = {inventoryJSON:h}; + + $(document).ready(function(){ + + // DatePicker action + function avail(date) { + m = (date.getMonth()+1); + if (m < 10) { + m = '0' + m; + } + d = date.getDate(); + if (d < 10) { + d = '0' + d; + } + y = date.getFullYear(); + mdy = m + '/' + d + '/' + y; + if (dates[mdy]) { + return [true,"","Available"]; + } else { + return [false,"","Not Available"]; + } + } + var dateData = false; + + var ticketQuantSelection = '\ + \ + '; + var ticketTooLate = '\ +

    \ + Sorry, too late to select these {term.ticket.plur} on-line.\ + {term.ticket.plur_cap} must be purchased at least {detail.performance.purch_leadtime} hours prior to the {term.performance.norm}.\ + Please select another date or time.\ +

    \ + '; + var selectedInv; + var ticketQuants; + var addButtonPushed = false; + + // Start by counting the number of dates to see if we have only 1 + var dateCount = 0; +// if (dateSpecific) { + $.each(dates, function(index, date) { + dateCount = dateCount + 1; + dateData = date; + }); +// } + // if there's no date specific tickets + if (!dateSpecific) { + // Populate date input field + $('#GLMeventDateSelectBlock').html(''); + doQuantSelection(); + // if there's only one date, then display that and move on. + } else if (!dateSpecific || dateCount == 1) { + // populate date input field + $('#GLMeventDate').val(dateData['date']); + $('#GLMtickets').html('
    Date:
    ' + dateData['date'] + '
    '); + + doQuantSelection(); + } else { + // Use the date picker to select a date + dateData = false; + $("#GLMeventDate").datepicker({ + beforeShowDay: avail, + dateFormat: "mm/dd/yy", + minDate: "{performanceDetail.start_date.date}", + maxDate: "{performanceDetail.end_date.date}", + onSelect: function(selectedDate, inst) { + // Update input message + $('#GLMdateMessage').html('
    '); + + // Get data for the selected date + dateData = dates[selectedDate]; + doQuantSelection(); + } // Date Selection + + }); // Date Picker + + } + + function doQuantSelection() { + // Build the ticket quant options + ticketQuants = ''; + var selectMax = dateData['available']; + if (selectMax > 50) { + selectMax = 50; + } + var tooLate = dateData['tooLate']; + if (tooLate) { + $('#GLMticketQuantContainer').html(ticketTooLate); + } else { + // note that the braced lte below is needed to inject a less-than-or-equal-to operator without having flexy chew on it. + for (var i = 1; i {lte:h} (selectMax*1); i++) { + ticketQuants = ticketQuants.concat(''); + } + + // Populate the ticket quantity container + $('#GLMticketQuantContainer').html(ticketQuantSelection.replace(/\[ticket-quants\]/g, ticketQuants)); + } +// doAddToCartSetup(); + } + +// function doAddToCartSetup() { + // Add to cart action + $('#GLMaddToCart').click(function() { + if (addButtonPushed) { + return; + } + var reason = ''; + // Check date + if (dateData) { + selectedInv = dateData.id; + } else { + reason = reason.concat('* You need to select a date first.\n'); + } + // Check quantity + var selectedQuant = (parseInt($('#glmQuantSelector').val()) + 0); + if (selectedQuant == 0) { + reason = reason.concat('* You need to select a quantity first.\n'); + } + // Check if there's a reason we can't add this to the cart yet + if (reason != '') { + alert(reason); + return; + } + // Adding to cart + addButtonPushed = true; + $("#GLMeventDate").datepicker('disable'); + $('#glmQuantSelector').prop('disabled', 'disabled'); + setBlocker(); + // Submit to cart + window.location = "{baseSCRIPT}&Action=Shop_cart&cart=add&PerformanceID={performanceDetail.id}&SectionID={sectionDetail.id}&TicketID={ticketDetail.id}&ticket_inv=" + selectedInv + "&quant=" + selectedQuant; + + }); +// } + // Code to kick off the geolocation-display feature + $("#locationMap").geolocate({ + lat: "#lat", + lng: "#lon", + mapOptions: { + disableDefaultUI: false, + mapTypeControl: true, + mapTypeId: "roadmap", + zoom: 12 + }, + markerOptions: { + draggable: false, + title: "This is your selected location" + } + }); + // Navigation buttons + $('#GLMnavCart').click(function() { // Add to Cart + window.location = '{baseSCRIPT}&Action=Shop_cart'; + }); + $('#GLMnavSelectEvent').on('click', function() { // Return to Event Selection + window.location = '{startURL:h}'; + }); + + function setBlocker() { + $('#glmReloadBlocker').show(); + } + + }); + + \ No newline at end of file diff --git a/views/front/tickets/Shop/ticketSelect.html b/views/front/tickets/Shop/ticketSelect.html new file mode 100644 index 0000000..290249b --- /dev/null +++ b/views/front/tickets/Shop/ticketSelect.html @@ -0,0 +1,310 @@ + + + +
    + +
    +
    {term.ticket.cap} Selection
    + +
    + {term.nav.show_selected} + {if:!option.ticket_selection.start_at_cart} + {term.nav.select_more} + {end:} +
    +
    + +
    {ticketText:h}
    +{if:reason} +
    +
    We're sorry, we had a problem with your request:
    +
      + {foreach:reason,r} +
    • {r:h}
    • + {end:} +
    +
    +{end:} +

    You have selected

    + + + +{foreach:sections,s} +
    +
    + + +
    + {if:performanceDetail.image} +
    + {end:} +
    + +
    +
    {performanceDetail.member_name:h}

    +
    {performanceDetail.name:h}
    +
    +
    +
    + {if:!oneSectionOnly} + {s.sectionDetail.name}
    + {end:} + +
    + + {if:performanceDetail.descr} + {performanceDetail.descr:h} + {end:} +
    +
    +
    +
    +
    + +

    Please select from the following

    +
    +
    + + + + + {foreach:s.ticketsData,x} +
    + {if:option.ticket_selection.include_options_in_ticket_list} +
    +
    +
    Price: 
    +
    +
    {x.price}
    +
    +
    +
    +
    Select date: 
    +
    +
    + + +
    +
    +
    +
    +
    Quant: 
    +
    +
    (select date)
    +
    +
    +
    + {end:} +
    + {if:option.ticket_selection.include_options_in_ticket_list} +
    {x.title}
    + {else:} +
    + {x.name} +
    + {end:} +
    +
    + {if:x.descr} +

    {x.descr:h}

    + {end:} +

    + {if:!x.date_specific.value} + Use any date{if:x.start_date.timestamp} from {x.start_date.date} to {x.end_date.date}{end:}{if:!x.time_specific.value}, {end:} + {end:} + {if:!x.time_specific.value} + Use any time of day, + {else:} + Time: {x.ticket_time.time}, + {end:} + {if:x.unlimted_use.value} + Each {term.ticket.norm} may be used an unlimited number of times + {else:} + + {end:} +

    +
    +
    +
    +
    + {end:} + +
    +
    + +{end:} + +
    + +{if:option.ticket_selection.include_options_in_ticket_list} + + {startScript:h} + + var addButtonPushed = false; + + // Dates for inventory data + var tickets = {ticketsJSON:h}; + + var ticketQuantSelection = '\ + \ + '; + + var ticketTooLate = '\ +

    \ + Sorry, too late to select these {term.ticket.plur} on-line.\ + {term.ticket.plur_cap} must be purchased at least [hours] hours prior to the {term.performance.norm}.\ + Please select another date or time.\ +

    \ + '; + + + $(document).ready(function(){ + + // for each ticket + $.each(tickets, function(index, ticket) { + + var inventory = ticket.inventory; + + // Build date data array and count dates for this ticket + var dateCount = 0; + var dateData = false + $.each(inventory, function(index, date) { + + // Count the number of dates + dateCount++; + + // If this is the first one, store it in case it's the only one + dateData = date; + + }); // each date + + // if there's no date specific tickets + if (!ticket.dateSpecific) { + + // Populate date input field + $('#GLMeventDateSelect_' + ticket.id).html(''); + doQuantSelection(ticket.id, dateData.id, dateData.available, ticket.tooLate); + + // if there's only one date, then display that and move on. + } else if (!ticket.dateSpecific || dateCount == 1) { + + // populate date input field + $('#GLMeventDateSelect_' + ticket.id).html(' \ +
    Date Available: 
    \ +
    \ +
    \ + ' + dateData.ticket_date.date + ' \ + \ +
    \ +
    '); + + doQuantSelection(ticket.id, dateData.id, dateData.available, ticket.tooLate); + + } else { + + // DatePicker action + function avail(date) { + m = (date.getMonth()+1); + if (m < 10) { + m = '0' + m; + } + d = date.getDate(); + if (d < 10) { + d = '0' + d; + } + y = date.getFullYear(); + mdy = m + '/' + d + '/' + y; + if (inventory[mdy]) { + return [true,"","Available"]; + } else { + return [false,"","Not Available"]; + } + } + + // Use the date picker to select a date + if($('#GLMeventDateInput_' + ticket.id).length > 0) { + $('#GLMeventDateInput_' + ticket.id).datepicker({ + beforeShowDay: avail, + dateFormat: "mm/dd/yy", + minDate: ticket.startDate, + maxDate: ticket.endDate, + onSelect: function(selectedDate, inst) { + // Get data for the selected date + dateData = inventory[selectedDate]; + $('#GLMeventInvID_' + ticket.id).val(dateData.id); + doQuantSelection(ticket.id, dateData.id, dateData.available, ticket.tooLate); + } // Date Selection + + }); // Date Picker + } + + } + + }); // each ticket + + function doQuantSelection(id, invId, available, tooLate) { + + // Build the ticket quant options + var ticketQuants = ''; + var selectMax = available; + if (selectMax > 50) { + selectMax = 50; + } + + if (tooLate) { + $('#GLMticketQuantContainer_' + id).html(ticketTooLate.replace(/\[hours\]/g, {performanceDetail.purch_leadtime})); + } else { + // note that the braced lte below is needed to inject a less-than-or-equal-to operator without having flexy chew on it. + for (var i = 1; i {lte:h} (selectMax*1); i++) { + ticketQuants = ticketQuants.concat(''); + } + + // Populate the ticket quantity container + tmpQuantSel = ticketQuantSelection.replace(/\[id\]/g, id); + $('#GLMticketQuantContainer_' + id).html(tmpQuantSel.replace(/\[ticket-quants\]/g, ticketQuants)); + } + + } + + var selectButtonPressed = false; + + $('#GLMselectButton').click(function() { + + // Prevent multiple submissions + if (selectButtonPressed == true) { + return; + } + + // Check for a selected ticket + var ticketSelected = false; + $('.glmTicketQuant').each(function( index ) { + if ($(this).val() != '') { + ticketSelected = true; + } + }); + + if (ticketSelected) { + selectButtonPressed = true; + setBlocker(); + $('#GLMselectForm').submit(); + } else { + alert('Please select a {term.ticket.norm} quantity.') + return false; + } + + }); + + function setBlocker() { + $('#glmReloadBlocker').show(); + } + + + }); + +{end:} + \ No newline at end of file diff --git a/views/front/tickets/foot.html b/views/front/tickets/foot.html new file mode 100644 index 0000000..36eb69f --- /dev/null +++ b/views/front/tickets/foot.html @@ -0,0 +1,9 @@ + +{if:option.development} +

    + Running on Development Server: + + Reset Session + +

    +{end:} \ No newline at end of file diff --git a/views/front/tickets/head.html b/views/front/tickets/head.html new file mode 100644 index 0000000..2b09b3e --- /dev/null +++ b/views/front/tickets/head.html @@ -0,0 +1,38 @@ + +{startScript:h} + // Pass some reference parameters to JAVAScript + var baseSiteURL = '{baseURL}'; + var baseAppURL = '{baseAppURL}'; + +{if:!jQueryLoaded} + +{end:} +{if:!jQueryUiLoaded} + + +{end:} + + + +{if:customCssFile} + + +{end:} +{if:frontDebug} + +
    +{end:} +{startScript:h} + var disp_setting="toolbar=no,location=no,directories=no,menubar=no,scrollbars=yes,width=1000, height=700, left=100, top=25"; + {if:frontDebug} + debugWindowFront = window.open("{baseURL}index.php?Action=Debug_update","emDebugWindowFront",disp_setting); + {end:} + + +
    +
    Updating your information
    Please wait ...
    +
    + + {if:adminUser} +

    Purchasing By Admin User

    + {end:} diff --git a/views/front/tickets/index.html b/views/front/tickets/index.html new file mode 100644 index 0000000..fca55f0 --- /dev/null +++ b/views/front/tickets/index.html @@ -0,0 +1,34 @@ + + + + + + + + + + +

    PLEASE NOTE:

    + +

    + There is no general access to this site. + All access to this site should be through an appropriate link. + If you arrived here by mistake (or exploring), nothing but this message will be displayed. + If you have any concerns about this site, please contact Gaslight Media. +

    + +

    + Gaslight Media
    + 120 East Lake Street
    + Petoskey, MI 49770
    +  
    + Phone: 231-487-0692
    + E-Mail: info@gaslightmedia.com
    + Web: http://www.gaslightmedia.com +

    + + + + + + diff --git a/web/admin/icons/calendar.png b/web/admin/icons/calendar.png new file mode 100644 index 0000000000000000000000000000000000000000..658913852d60fc6ca8557568d26b8e93e7d56525 GIT binary patch literal 675 zcmV;U0$lxxP)w!? zFisFv!T|cmRtW;1f$>$s0G>^*GP-h`H-mzTP&3`b(d;hDCL-{+T2LSiJi1S%34OTG znWn~v^Brk?FQB#MFuosf?qnt!t(A%g#tAAA`tV{p&t%~)6GMus628BV?|aP6=Lr0O zrxPn=6Fy3{fE84gngF`mQ;ZG4p#ul`mYb)mJw@Q%q_eddamvg>kv)yI#B0M!3sxev z!1s9dp#Z>KE{BK5@W%p1Kt!2cEYj2vBiUHDJ-HCTS{r%b!`Wj=!r&Tb+LFBfRN!=5 zl7aC&Ul)Foh{s4J>JU)^p9+C-Q44MR8(8|WK})8dx#e}T%`v`wFOp3_q9I1QsXihN zJVaEgK9Y|1KAJgEb`m$%VXVVh!8pM>`_Eli`}OBJfVb0i{tF{QT8%v&>u>-7002ov JPDHLkV1feuD8K*! literal 0 HcmV?d00001 diff --git a/web/admin/icons/information.png b/web/admin/icons/information.png new file mode 100644 index 0000000000000000000000000000000000000000..12cd1aef900803abba99b26920337ec01ad5c267 GIT binary patch literal 778 zcmV+l1NHogP)BVme|mWaqy4$_pJm?y9KM{-*hp?1+Ey3e-CEDooTa!B;e(Q>TSF?bj>5At13y1p zriN3w3x~5SfZj{@J4M{kp{?=M_Lh2bV+5LH)Q)5W!-ePA$RgE1@5f1cyHki0Y}JyVEYZF(LD$xXlt$7A5CgE@ zpV-&l%vf;=5kZ2-2gi@Y6J&=cuwt>!vJ^#(&n|LcZyUzi6Duj$$hJ1s*HD-#;k-w@ zpdrwAuoDG_N2bvb07G$Zk*?Hc)JLtW4yqOnic_$zO7NZ#l>Fm){;fE?b$IbOaX2fe z0la4g0Dfw2xk7Wi7NapVD8YMPCZu?A1QCK*67dgsvRKBLFtrM>?$%&_lD1882mzdO zWPdw5KWw6IT`m1b_8=lS5jt8D3=RDa=&jWzR-)S@56WMslZ~mKu1)-wpXB>rNBQ>N zU#K`#1B&v|_AQK;7I~B}OdGiUT9LX>f0xm6<;LeP!=vFjPsUQF*wCJ*dO)4YBypgdiuF!=i@6Zyi7F|q#K zz?tlSZULa@t1D?$e;f@b36&N!V2mjOHw|*iHtsh1EzPArg^Q zIZrOk#rNsfjaSbMAL;<4h;Z=jvu8dzyz8N&Nb7=z03ZUw?9z%8KQEa6yM5=kUnka& z3?FJk2}L7q>na=T#;<7U*P91xfF`;`6%pVgWgRy0?1ZryL@%z52=-!fGXWGEn4M351L4<+7eDgwo|moqXT+s1&Kmn>-uQQ8mL7XY)w5Zk*(g+<3Y3tmkR!bL zOUKaUtj_pX26sH+=Iorwu}MGd`_%O-_sS}8VpG#fJA)Fcs#ezwtZf?q?Ac70mDv`rVs{$od?VPKeqf<-kUjNtS6ecB*mq<&M97K^6IVsDO zt2$Ru!b+>2S<}_H>$RcInusU_8PMNdf(W{sNlJ3FkrwMJPeBPO#d}Y^a{9TH(#{Y) l0D?dWAV4eUJX#h`!2gmISk&ZKd4B)^002ovPDHLkV1g&sd|Lnj literal 0 HcmV?d00001 diff --git a/web/admin/tickets/documentation/VenueAdminGuide.pdf b/web/admin/tickets/documentation/VenueAdminGuide.pdf new file mode 100644 index 0000000000000000000000000000000000000000..2daf7aa5fb1540871cfe2abf58dcb260e6c42324 GIT binary patch literal 395350 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%0DMIwECY->g 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 z

    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%0DWAw&!>h+sb-3JR5TgQ#^xcc?l1aLHL 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

    bYsiu%L;E`TX z2&9Bx93y8A)-@;m4G@uab&C`J`HR>u|A0<#FqBOAb7P$0U}#Rl-w6?Uc4%d6$($Ab zmGjhz<|T3|5mzHsWd5qvbYUVXy;i4E@(R`b&W4=m)b=`^ZowQ5<|I5IjY>os!$sND zoX8}@ExBeq&^+2qnrWV6$?7@b#ft+=x|fjQB_m4+S|ThVODJ=-ISNbqdwR#nn&+qs z`50b*7dv8c_E&^XQ=Q^uEohr|CvT&FW%j>>9krY$a3yqB+nCWe>OiP9L_*Q9KIp|p zQ=Kt#uD${4MiR5lAP_*Ay750K9n+^C*=~?Z<@|gn@@%&19Bt%0AEP|(UT;Zn%&)rD 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 ez#yPGD_1uw7dLFm28

    Loading, Please Wait...
    '); + $('#'+container).show(duration); + + // Build the URL and call it with AJAX + url = appAdminURL + "&Action=" + action; + if (params) { + url = url + '&' + params; + + } + + $.post( url, + '', + function(data) { + // Populate the container with the results + $('#'+container).html(data); + restartOnTabSelect(); + } + ); + + } + f_loadAction = loadAction; + + // Replace the contents of a div + function replaceContents(data, destination) { + destination.html(data); + $(window).scrollTop($(destination).position().top-50); + } + f_replaceContents = replaceContents; + + /* + * General Slider Operations + */ + + // Slider area actions + $('.emSlider').on('click', null, function() { + + // Get the ID of the area to slide from the emSliderId="" parameter in the div tag. + var sliderId = $(this).attr('emSliderId'); + + // If the slider is currently open - close it, otherwise open it. + if ($('#'+sliderId).is(':visible')) { + $('#'+sliderId).hide(duration); + } else { + $('#'+sliderId).show(duration); + } + }); + // Startup by closing all areas that are supposed to be closed by default + $('.emSliderClosed').hide(duration); + + /* + * Tab Operations + */ + + function tabSelect() { + + // Get Tab Group Name + var tabGroup = $(this).attr('emTabGroup'); + + // Get last selected tab ID + var lastTab = $('.'+tabGroup+'.emTabSelected').attr('emTabId'); + + // Get the new tab ID + var newTab = $(this).attr('emTabId'); + + // Get destination container ID +// ? var container = false; + var container = $(this).attr('emContainerId'); + + // Get any parmeters for the loadAction() AJAX call + var params = $(this).attr('emTabParams'); + + // If they didn't click the already selected tab + // if (lastTab != newTab) { + + // Assign the clicked object to a parameter for use in the function + var selectedTab = $(this); + + // If there was an already selected tab then hide old and processe new tab + if (lastTab) { + + // Slide up the previously selected section + $('#'+container).hide(duration, function() { + + // If there's a destination container, then get content + if (container) { + loadAction(newTab, container, params); + } + + // Make last tab not selected and now a link + $('.'+tabGroup+'.emTabSelected').removeClass('emTabSelected'); + + // Mark new tab as selected and not a link + selectedTab.addClass('emTabSelected'); + + // Open the new tab's block + $('#'+newTab).show(duration); + + + }); + + // Otherwise if there's no old tab, just process the new one + } else { + + // If there's a destination container, then get content + if (container) { + loadAction(newTab, container, params); + } + + // Mark new tab as selected and not a link + selectedTab.addClass('emTabSelected'); + + // Open the new tab's block + $('#'+newTab).show(duration); + + } + + } + f_tabSelect = tabSelect; + + function restartOnTabSelect() + { + $('.emTab').off('click', f_tabSelect); + $('.emTab').on('click', f_tabSelect); + } + f_restartOnTabSelect = restartOnTabSelect; + restartOnTabSelect(); + + /* + * CKEditor Actions + */ + + CKEDITOR.config.toolbar_EventManagement = + [ + ['Font','FontSize','Bold','Italic'], + ['Cut','Copy','PasteText','-','Undo','Redo'], + ['NewPage', 'Preview'], + '/', + ['NumberedList','BulletedList','-','Outdent','Indent'], + ['JustifyLeft','JustifyCenter','JustifyRight','JustifyBlock'], + ['TextColor'], + ['Link','Unlink'], + ['Table','Find','Replace','-','RemoveFormat','Source'] + ] ; + + // Build a specific CKeditor + function buildCkeditor(f) { + // Get field ID + fieldId = f.attr('id'); + + // Create the editor + if (f.is("textarea")) { + // Only try to replace the textarea if the + // CKEditor is compatible w/ the browser. + if (CKEDITOR.env.isCompatible) { + CKEDITOR.replace(fieldId, { + toolbar : 'EventManagement', + // width : 570, + height : 100 + }); + } + } + } + f_buildCkeditor = buildCkeditor; + + // Remove a specific CKeditor + function removeCkeditor(f) { + // Get field ID + fieldId = f.attr('id'); + var instance = CKEDITOR.instances[fieldId]; + var data = instance.getData(); + instance.destroy(true); + f.text(data); + } + f_removeCkeditor = removeCkeditor; + + // If option.admin_debug has been set, create debug window + if(debugEnabled) { + var disp_setting="toolbar=no,location=no,directories=no,menubar=no,scrollbars=yes,width=" + debugWidth + ", height=700, left=100, top=25"; + debugWindow = window.open(appAdminURL + "&Action=Debug_start","emDebugWindow",disp_setting); + } + + + /* + * Check for user timeout + */ + + var inactivityTime = 86400000; // Number of milliseconds to user timeout + + // If there's no activity for 86,400 seconds (1 day) do something + var activityTimeout = setTimeout(inActive, inactivityTime); + + function resetActive(){ + $(document.body).attr('class', 'active'); + clearTimeout(activityTimeout); + activityTimeout = setTimeout(inActive, inactivityTime); + } + + // No activity do something. + function inActive(){ + $(document.body).html('

    User timeout ...

    Please select "Event Management" to start.

    '); + } + + // Check for mousemove, could add other events here such as checking for key presses ect. + $(document).bind('mousemove', function(){resetActive()}); + +}); diff --git a/web/front/FoundationStandAlone/EventManagement.css b/web/front/FoundationStandAlone/EventManagement.css new file mode 100755 index 0000000..54b845d --- /dev/null +++ b/web/front/FoundationStandAlone/EventManagement.css @@ -0,0 +1,594 @@ +/* Additional styles for Event Management front-end */ + +/* These are verified for use with the Foundation layouts */ + +/* Styles to over-ride Foundation styles mudged by site styling. */ +.h2Tickets { + color: #B5383E; + display: block; + margin-bottom: .5em; + font-family: TimesNewRoman,"Times New Roman",Times,Baskerville,Georgia,serif; + font-size: 1.8em; + line-height: 110%; + font-weight: bold; +} +.h3Tickets { + font-size: 1.2em !important; + font-weight: bold !important; +} +.h3Tickets:hover { + color: #B5383E !important; +} +.buttonTickets { + color: white !important; + font-size: 1.3em !important; + padding: .2em 1em .2em 1em !important; + margin: 0 .2em .2em .2em !important; +} +.buttonTicketsGo { + color: white !important; + background-color: #00BF00; + font-size: 1.3em !important; + padding: .2em 1em .2em 1em !important; + margin: 0 .2em .2em .2em !important; +} +.buttonTicketsGo:hover { + background-color: #00AF00; +} + +/* Anything below needs to be verified if used with the Foundation layouts */ + +#GLMpageIntro { + margin: 1em 0 1em 0; +} +.glmBlock { + display: block; + width: 100%; + overflow: hidden; + margin: 0 0 10px 0; + padding: 5px; + border: 1px solid #CFCFCF; + background: rgba(0,0,0,0.05); +} +.glmBlockContent { + margin: 0 0 0em 0; + clear: both; + width: 100%; +} +.glmBlockContentLeft { + display: block; + float: left; + overflow: hidden; +} +.glmBlockContentRight { + display: block; + float: right; + width: 40%; + overflow: hidden; + margin-bottom: 10px; + margin-left: 5%; + min-width: 120px; +} +.glmBlockContentIndent { + display: block; + margin-left: 3em; +} +.glmCartVenueDescr, .glmCartEventDescr { + font-size: 0.8em; + margin: 0 0 2.2em 0 +} +.glmCartVenueDescr, .glmCartEventDescr { + margin: 0 0 15px 0 +} +.glmCartSelect { + width: 4em; +} +.glmCartBlock.totals .glmCartWide { + width: 100%; + padding-top: 10px; +} +.glmCartBlock { + display: block; + width: 100%; + overflow: hidden; + margin: 0 0 1em 0; + padding: 10px; + border: 1px solid #CFCFCF; + background: rgba(0,0,0,0.05); +} +.glmCartBlock.totals { + display: block; + width: 100%; + overflow: hidden; + margin: 0 0 10px 0; + padding: 0; + border: 0; + background: none; +} +.glmCartBlockSmallTitle { + font-size: 16px; + line-height: 22px; + font-family: "Lora","Times New Roman",Times,serif; +} +.glmCartBlock input[type="textarea"] { + display: block; + float: left; + clear: left; + width: 100%; +} +.glmEventDateInput { + width: 80px; +} +.glmCartBlock.totals .glmCartBlockTitle { + border-bottom: 1px solid #CCC; +} +#GLMcontent { + padding: 0; + margin: 0 auto +} +#GLMevent, #GLMtickets, #GLMvenue { + /* max-width: 500px; */ + margin: 0 auto 1em auto +} +#GLMnavigation:after { + content: ""; + display: table; + clear: both +} +.glmNavItem { + float: right; + padding: 3px 10px; + width: auto; + display: block; + overflow: hidden; + background: #900; + border: 1px solid #900; + border-radius: 8px; + cursor: pointer; + text-transform: uppercase; +} +a.glmNavItem { + color: #FFF; + font-weight: bold; + text-shadow: none; +} +div.glmNavItem { + color: #FFF; + font-weight: bold; + text-shadow: none; +} +.glmNavItem.cart { + background: #040267; + border: 1px solid #040267; +} +.glmNavItemWide { + display: block; + width: 400px; + overflow: hidden; + margin: 12px 0 0 0; + padding: 8px 0; + background: #900; + border: 1px solid #900; + border-radius: 8px; + color: #FFF; + text-align: center; + vertical-align: middle; + font-size: 18px; + font-weight: bold; + font-family: "Times New Roman", Times, serif; + cursor: pointer; +} +.glmSelectItem { + padding: 5px; + margin: 0; + width: 150px; + border-left: 1px solid #e3e3e3; + cursor: pointer; + border: 1px solid #e3e3e3; + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + -ms-border-radius: 6px; + -o-border-radius: 6px; + border-radius: 6px; + text-align: center; + font-weight: 600; + font-shadow: 0 1px #fff; + font-size: 0.85em; + background: #fcfcfc; + -webkit-background-clip: padding; + -moz-background-clip: padding; + background-clip: padding-box; +} +#GLMcheckout .glmNavItem, #GLMticketCart .glmNavItem { + width: 33.3333% +} +#GLMeventDates, #GLMvenueLocation, #GLMvenueDetail, #GLMvenueSectionMap { + margin: 0 0 15px 0 +} +.glmPrompt { + font-weight: 600; + font-size: 1.1em +} +.glmTicketDescr { + font-size: 0.85em +} +.glmTicketAvailable { + margin: 5px 0; + font-weight: 600 +} +.glmSectionTickets { + margin: 15px 0 +} +.glmTicketName { + font-size: 1.35em; + font-weight: 600 +} +.glmTicketDateInput { + width: 7em !important; + display: inline !important; +} +.glmTicketQuantInput { + width: 4em !important; + display: inline !important; +} +.glmTicketCcnameInput { + width: 32em !important; +} +.glmTicketCcInput { + width: 12em !important; +} +.glmSectionSelector { + border: 1px solid #e3e3e3; + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + -ms-border-radius: 6px; + -o-border-radius: 6px; + border-radius: 6px; + cursor: pointer; + background-color: #f8f8f8; + padding: 8px 15px; + margin: 5px 0; + font-size: 1.15em; + font-weight: 600; + display: inline-block; + font-shadow: 0 1px #fff +} +.glmSectionSelector:active { + -webkit-box-shadow: inset 0 0 8px #dbdbdb; + -moz-box-shadow: inset 0 0 8px #dbdbdb; + box-shadow: inset 0 0 8px #dbdbdb +} +#GLMticketsSummary { + font-weight: 600; + font-size: 1.35em; + margin-top: 30px +} +.glmTicketsSelect { + clear: both; + margin: 1em; +} +.glmTicketsSelectPrompt { + font-size: 1em; + font-weight: 600; + line-height: 125%; + float: left; + padding-right: .2em; +} +.glmTicketsSelectValueWrapper { + float: right; + width: 150px; + text-align: right; +} +.glmTicketsSelectValue { + float: right; + width: 40%; + text-align: right; +} +#glmQuantSelector { + float: right; + text-align: right; + width: 100px; + height: 28px; +} +#GLMpolicy { + font-size: 0.85em; + font-style: italic; +/* margin-bottom: 15px; */ +} +.glmTicketPrice { + font-weight: 600; + margin: 15px 0 5px 0; + font-size: 1.25em +} +#GLMreason { + border: 1px solid #333; + padding: 1em; +} +.GLMreasonTitle { + color: red; +} +.GLMreasonList { +} +.GLMmapWindow { + width: 100%; + height: 140px; + border: 1px solid #CCC; +} +.glmDescr { +} +.glmCartFailedInput { + background: #FFaBa9; + padding: .2em; +} +.glmCartRequired { + color: red; +} +/* CHECKOUT STUFF */ +.glmCartFormLine { + clear: both; +} +.glmCartFormPrompt { + width: 30%; + float: left; + text-align: right; + font-weight: 600; + font-size: 1.1em; + padding-right: .5em; +} +.glmCartFormInput { + padding-left: 1em; + width: 70%; + float: left; + margin-bottom: .5em; +} +.glmCartFormInput span { + display: block; + width: 100%; + overflow: hidden; +} +/* Forms */ +.glmCartForm { + display: block; + width: 100%; + overflow: hidden; + padding: 10px; + background: #F5F5F5; + margin: 0 0 10px 0; + font-size: 12px; + border: 1px solid #CCC; + color: #656565; +} +.glmCartForm input[type="text"] { + display: block; + float: left; + clear: left; + width: 300px; +} +.glmCartForm select { + display: block; + float: left; + clear: left; + width: 200px; +} +.glmCartPayment { + margin: 2em 0 0 0 +} +.glmInput { + float: right; +} +/* Mobile */ +@media screen and (max-width:768px) { + .glmBlockContentRight { + float: left; + width: 100%; + margin-left: 0; + margin-right: 0; + margin-top: 10px; + margin-bottom: 10px; + } + .glmBlockContentLeft { + display: inline; + float: left; + width: 100%; + } + .glmBlockContentLeft div { + clear: none !important; + } + /* Mobile Forms */ + +} +/* Small Mobile */ +@media screen and (max-width:599px) { + .GLMmapWindow { + height: 130px; + } + .glmCartFormPrompt { + display: block; + width: 100%; + overflow: hidden; + text-align: left; + } + .glmCartFormInput { + margin-left: 0; + padding-left: 0; + } + #GLMpageTitle { + width: 50%; + } + .glmCartHeader { + float: left; + clear: none; + width: 50%; + overflow: hidden; + + margin-bottom: 20px; + } + .glmCartHeader .glmCartText { + display: block; + width: 100%; + overflow: hidden; + border-bottom: 1px solid #CCC; + height: 30px; + } + .glmCartValues { + float: left; + clear: none; + width: 50%; + overflow: hidden; + margin-bottom: 20px; + } + .glmCartValues .glmCartText { + display: block; + width: 100%; + overflow: hidden; + border-bottom: 1px solid #CCC; + height: 30px; + } + .glmCartSubTotals .glmCartTable .glmCartHeader { + float: right; + width: 66%; + } + .glmCartSubTotals .glmCartTable .glmCartHeader .glmCartText { + width: 42%; + margin-right: 0; + margin-left: 8%; + height: auto; + text-align: right; + } + .glmCartSubTotals .glmCartTable .glmCartValues { + float: right; + clear: right; + width: 66%; + } + .glmCartSubTotals .glmCartTable .glmCartValues .glmCartText { + width: 42%; + margin-right: 0; + margin-left: 8%; + border-bottom: 0; + height: auto; + text-align: right; + } + .glmCartTable.totals { + padding-left: 0; + padding-right: 0; + } + .glmCartTable.totals .glmCartHeader { + float: right; + width: 100%; + margin-bottom: 0; + } + .glmCartTable.totals .glmCartHeader .glmCartText { + width: 28%; + margin-right: 0; + margin-left: 5%; + border-bottom: 1px solid #CCC; + height: auto; + text-align: right; + } + .glmCartTable.totals .glmCartValues { + float: right; + width: 100%; + } + .glmCartTable.totals .glmCartValues .glmCartText { + width: 28%; + margin-right: 0; + margin-left: 5%; + border-bottom: 0; + height: auto; + text-align: right; + } + .glmTicketsSelectValueWrapper { + float: left; + width: 150px; + clear: left; + margin-top: 10px; + } + .glmBlockLeft { + width: 100%; + } + .glmCartEventDescrMobile { + display: inline; + } + .glmCartEventDescr { + display: none; + } +} +/* MidSmall Mobile */ +@media screen and (max-width:449px) { + #GLMpageTitle { + font-size: 16px; + line-height: 20px; + } + .glmBlockName { + font-size: 14px; + line-height: 18px; + } + .glmCartFormInput { + width: 100%; + } + .glmCartForm input[type="text"] { + width: 100%; + } + .glmCartForm select { + width:100%; + } + .glmNavItemWide { + width: 100%; + } + .glmNavItem.add { + width: 100%; + text-align: center; + } + #GLMcheckoutBtn { + width: 100%; + text-align: center; + } + +} +/* XSmall Mobile */ +@media screen and (max-width:399px) { + .glmNavItem.chooser { + display: block; + width: 100%; + overflow: hidden; + margin-top: 10px; + text-align: center; + } +} + +#glmReloadBlocker { + display: none; + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + background-color : transparent; + text-align: center; + z-index: 1000; +} +#glmReloadBlocker div { + height: auto; + width: 250px; + padding: 10px; + background: #eee; + position: fixed; + border-radius: 10px; + border: 2px solid #666; + color: red; + font-size: 1.1em; + line-height: 150%; + + margin: -150px 0 0 -150px; + left: 55%; + top: 60%; + + box-shadow: 10px 10px 5px #888888; +} +#glmDevelopmentNotice { + padding: 5px; + border: 1px solid black; + width: auto; + clear: both; + margin-top: 4em; +} diff --git a/web/front/FoundationStandAlone/EventManagement.js b/web/front/FoundationStandAlone/EventManagement.js new file mode 100755 index 0000000..34e8596 --- /dev/null +++ b/web/front/FoundationStandAlone/EventManagement.js @@ -0,0 +1,94 @@ +/* + * Event Management Front-End Area JAVAScript - TicketsFoundation interface + */ + +var f_loadAction = false; +var f_replaceContents = false; +var duration = 0; + +// jQuery Section +$(document).ready(function(){ + + /* + * Data Setup Section + */ + + var siteURL = flex_baseURL; + var appURL = flex_baseAppURL; + + /* + * Load an action to a div with the specified id where id is also Action to be run + */ + function loadAction(id, container, params) { + + // Display loading message + $('#'+container).html('
    Loading, Please Wait...
    '); + $('#'+container).show(duration); + + // Build the URL and call it with AJAX + url = appURL + "?Action=" + id; + if (params) { + url = url + '&' + params; + } + $.post( url, + '', + function(data) { + // Populate the container with the results + $('#'+container).html(data); + restartOnTabSelect(); + } + ); + + } + f_loadAction = loadAction; + + // Replace the contents of a div + function replaceContents(data, destination) { + destination.html(data); + } + f_replaceContents = replaceContents; + + /* + * General Slider Operations + */ + + // Slider area actions + $('.glmSectionSelector').on('click', null, function() { + + // Get the ID of the area to slide from the emSliderId="" parameter in the div tag. + var sliderId = $(this).attr('emSliderId'); + + // If the slider is currently open - close it, otherwise open it. + if ($('#'+sliderId).is(':visible')) { + $('#'+sliderId).hide(duration); + } else { + $('#'+sliderId).show(duration); + } + }); + // Startup by closing all areas that are supposed to be closed by default + $('.glmSectionTickets').hide(duration); + + /* + * Check for user timeout + */ + var inactivityTime = 1800000; // Number of milliseconds to user timeout + + // If theres no activity for 5 seconds do something + var activityTimeout = setTimeout(inActive, inactivityTime); + + function resetActive(){ + $(document.body).attr('class', 'active'); + clearTimeout(activityTimeout); + activityTimeout = setTimeout(inActive, inactivityTime); + } + + // No activity do something. + function inActive(){ + alert("Your user session has timed out. Click OK to continue."); + window.location.href = siteURL; + } + + // Check for mousemove, could add other events here such as checking for key presses ect. + $(document).bind('mousemove', function(){resetActive()}); + +}); diff --git a/web/front/FoundationStandAlone/assets/get_adobe_reader.png b/web/front/FoundationStandAlone/assets/get_adobe_reader.png new file mode 100755 index 0000000000000000000000000000000000000000..f53add875db304eb6f0186be56f0b53de82b5d8f GIT binary patch literal 2597 zcmV+=3flFFP)FDXiA0?%wrM(^`&d$zcVq{raTEfA>s1zB!yuE=64#h1qrVJ6PIX%64eRvcWv>qeb zASRiZndRi7lMoe^2@bOi5~--Ekrf%D93hgBk=51Jx3;!OMMm!0 z+ng{or>3T!4;0td*V))O@$u*9=VM@C<KR{;X+>+ALP_5S|;%E`%< zl$DGY8Py;r$8&bj&(L-U3!b5)s8mmgomITAoKF`;U6cw86RwG zZDS4)i5MHl$H$^1DY%7)Y!DNtD=_KD$l$uW%*@QNuCL|6!-*3XFCDCn@LR6yuFc>m%1r0P|U)PIK(o z<;#oX<40GmD&OqyUl-^*BTgo>dO2rbbntMMN~L`-EqnUub9@}nYU5QsI`gFn`CcF8 zQQhMBQ9CbL;CXnsx>iNZ0}=9zmmH|h&MP0!L*?Q2BHj~&_v2*_pC6+-JX^|Jc|b&- zIaf7n)+|-YAkRZIsuO0rGV z+ZXq#@_ut@%a$#NzOwNsPSBOV`=@ucL);Kh}S z$U`!W6Lgyq@7Z5pK{~`k<Y_+Z3#uCIOyDvKiyBF7WFG58*#yGO82G zTR4^Qa<2k}r-albTuquC0N>@nB&6wgDW4D>5U(c^zz4wLH)0caCHVea*KUV?(dn^t0m&ht7<+K5qPc=5Y1E9~dGzPc_ z)uNM2K8=~^qumFccmoWcI0XRSmdpok0AR8-HiUx;-D3bcax68E<;9W6FwQEA8Y?Ki zvnyuZx(nxy7RGe#JvV3OoLh@xV`GK(iWK<(;G#3I+B^Ug$0#*#K@F=lsHMEcOpKL%djV=*jSYa@#YXJ;8BU25*8iST`8>;S>Kb9xsV@2ut<>8p4 zukMP@o}WHHE$!`*>EB;H_segWd&V|9^6iD>v$=>@4FjF(elzQ0hO>%Uz$QVsqQp;! zJ5v3$6rfc14y@6%e4rZwoE#&Q0FcU^hU1DnPc8 zugc;|4-c}mBX39iY|)vR*x2S~zP%3Z6y-+5TLJKlW=F1K2%w4E2uzvjh_U?{b!wYR z4*-}K4oA4AQgu?BY5+i)RAIn8J%F(j4C`Bi5}`96+|+9(Tn#TPxxBo>yrQG!(Zv@X zFb?Ue$n!Yj@3%agn}zm{v-&dQAmQn`q)?qZ05IL4)G~^0=+&}}me%FYF$}X4aygb| zRZz;cp3r$C-X&DL3%IBmZZ=$18@W&Q6Z1%%y^5nR+MHXBS6*vvsU1jm#D6Fb?ZHW3lcwZO=`eI%SBfz&weIw!Mj6-vYx5 z6|kvDn=04U0}S%R-DB3SfD&COK2df~nX=vh30zZ6t-=J#wfuK)Sn-nyc^644Z*~<% z_ZOx)5S&n*O?SJG@Yble0eqybsn#f22Hkq8nl!eH&XYkgw<=DMOyK&53J-8x^2$132)=}>!O@o1!vMx<2~ zhvxb}x@*@&<4J{7@irTd>O|&Y6_Gh1+jtz`9g3r9JjB88`J*`RmKV~zOl)?Xy*fvHIW7|;eUASH%tm|u;-`vx00000NkvXX Hu0mjfz561% literal 0 HcmV?d00001 diff --git a/web/front/FoundationStandAlone/assets/paypal_but6.gif b/web/front/FoundationStandAlone/assets/paypal_but6.gif new file mode 100755 index 0000000000000000000000000000000000000000..5da5a520da3967c966b4aa4bd9f0fcdeba928312 GIT binary patch literal 4774 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 literal 0 HcmV?d00001 diff --git a/web/front/FoundationStandAlone/assets/pdficon_large.png b/web/front/FoundationStandAlone/assets/pdficon_large.png new file mode 100755 index 0000000000000000000000000000000000000000..c42f1550ea273c570a1bdd2f57769fa8166224d7 GIT binary patch literal 1397 zcmV-*1&aEKP)dbVG7wVRUJ4ZXi@?ZDjyCFEKGM zFgD;wjClY60338hSaefwW^{L9a%BKPWN%_+AVz6&Wp{6KYjYq&Q#En5<2C>Q1kOoB zK~z|U<(FM-lT{eUe{cJ~ux?#j$8;a=3)x2oDMO=B83WM^6$v562_{6yjK+)Ik;skU z1qLo4UO3T2mIW+ zrF9}z=R)xGrL*|`eymojucf7>^3b6}6UoNOL1B}IsGjkR z$knki48y?d^-^0~Yin+9z6~r(CPF%1wn8kDOtYNZ?{ouj|JDFMZ)@W9?hXKcKXsO_ z-56&h*N+`%^}apm!l1zQ90TpA0r+v-E&%i-bE6SZ6ovNoc1A}>Q51!$sw!MA z*SiA)0~cy)YEA*d6cU1PoB@1ZT8sOm1F`md!#A1eyT#4#z6W5qvy0)*u7tT^AqWY9 zBuV7v=8~PAO-@b@x~_BW+BI5RTTOPmeLtW8Nc#$(5_x7NVHYz|^89Kh`ufox9>-j` z7twjA>ld=JvQSkOP16X4LIeT}sY%kAa60kz_F;0^=Nvl|3l?B9nUExj zMGf_6NMx;a&MDwOi9iI2AQF?`d^;}znSKvcd%fO)WTK+zEUCimuwejeu3SR4+mqgb zXqlCjRRat@k_g;Bc$feZE80%rzdudi2YWM)K-%Y*YPU1ny4TC#k)teYejj_ClQrkg z;C^{46RwS{*t-XSd)<8~b{j<-){$4|T)2Rl^}!=Y5e_>=TQ<>i;4tIv4t&08d_6bu zytxyBM0QyzMH}k5-tr|ITaQrk!n%Lf%8@At>nU2l zmi#&=iyU@5mpi%jbsHnUcHkQxL9yFtym*#^RV$HYxds@_Gyv7AstQ$AMIaCm_dR3c zLi29%2{zHz@QMfqgE7-IEoPxmNQ6Qmq3gQPbzS^5IVHm3u!uw=0;q<09)ToDOx)<@ zOyk>VULV+Pym+i7KygfSTlFqs}anD)k0Bg)^$B05v3wbSD)dl0S5nd9!Tb!i!>P)oQUS~ zJt_gJ*=*hhl+K$WIYs~#=JDqgSOR1}A^|Ee1qA*EAjBLvt*8Qp00000NkvXXu0mjf DW5;%t literal 0 HcmV?d00001 diff --git a/web/front/Gaslight/EventManagement.css b/web/front/Gaslight/EventManagement.css new file mode 100644 index 0000000..9eef48a --- /dev/null +++ b/web/front/Gaslight/EventManagement.css @@ -0,0 +1,916 @@ +/* Additional styles for Event Management front-end */ +#GLMHeader { + display: block; + width: 100%; + overflow: hidden; + margin: 0 0 5px 0; + padding: 0; + border-bottom: 1px solid #CCC; +} +#GLMpageTitle { + color: #040267; + float: left; + font-family: "Lora","Times New Roman",Times,serif; + font-size: 20px; + line-height: 24px; + font-weight: normal; + margin: 0 0 10px; + padding: 0 0 5px 0; + width: 70%; + /*background: rgba(0,0,0,0.1);*/ +} +#GLMpageIntro { + margin: 1em 0 1em 0; +} +#GLMpageIntro p{ + font-size: 1rem; + font-family: "Open Sans", sans-serif; +} +.glmBold { + font-weight: 600; +} +.glmBlock { + display: block; + width: 100%; + overflow: hidden; + margin: 0 0 10px 0; + padding: 5px; + border: 1px solid #CFCFCF; + background: rgba(0,0,0,0.05); +} +.glmBlockList { + margin-top: 10px; + clear: both; +} +.glmBlockHeader, .glmBlockHeadder { + display: block; + width: 100%; + overflow: hidden; + margin: 0 0 5px 0; +} +.glmBlockName { + display: inline; + font-size: 24px; + line-height: 22px; + color: #043867; +/* font-family: "Lora","Times New Roman",Times,serif;*/ + font-family: "Open Sans", sans-serif; +} +.glmBlockName a{ + font-size: 18px; + color: #043867; +} +.glmBlockRightCol { + float: right; +} +.glmBlockContent { + margin: 0 0 0em 0; + clear: both; + width: 100%; + font-family: "Open Sans", sans-serif; +} +.glmTicketQuant{ + width: 45px; + height: 30px; +} +.glmTicketQuant option{ + font-size: 15px; +} +@media (min-width: 768px){ + .glmBlockContentRight img{ + float: right; + } + .glmBlock:not(:first-child) .glmBlockContentRight .glmBlockContent{ + clear: none; + /* width: 10%;*/ + /* float: left;*/ + } + .glmBlock:not(:first-child) .glmBlockContentRight .glmBlockContent .glmTicketsSelectValue{ + width: 10%; + margin-right: 10px; + } + .glmBlock:not(:first-child) .glmBlockContentRight .glmTicketsSelectPrompt{ + /* float: left;*/ + padding: 0; + margin-right: 3px; + } + .glmBlock:not(:first-child) .glmBlockContentRight .glmTicketsSelectValue{ + width: 20%; + float: left; + } + .glmBlock:not(:first-child) .glmBlockContentRight .glmInput{ + /* float: left;*/ + } + .glmBlock:not(:first-child) .glmBlockContentLeft { + display: block; + float: left; +/* width:55%;*/ + width: 33%; + overflow: hidden; + } + .glmBlock:not(:first-child) .glmBlockContentRight{ + display: block; + float: right; +/* width: 40%;*/ + width: 64%; + overflow: hidden; + margin-bottom: 10px; + margin-left: 1%; + min-width: 120px; + } + .glmBlock .glmBlockContentLeft.startContent, .glmCartBlock .glmBlockContentLeft.cartContent{ + display: block; + float: left; +/* width:55%;*/ + width: 50%; + overflow: hidden; + } + .glmBlock .glmBlockContentRight.startImage, .glmCartBlock .glmBlockContentRight.cartImage{ + display: block; + float: right; +/* width: 40%;*/ + width: 45%; + overflow: hidden; + margin-bottom: 10px; + margin-left: 5%; + min-width: 120px; + } + .glmBlock:not(:first-child) .glmBlockContentRight .glmBlockContent:nth-child(2) .glmTicketsSelectValue{ + + width: 18% !important; + } +} +@media (min-width: 992px){ + div[class^="GLMeventDateSelect"]{ + + } + .glmBlock:not(:first-child) .glmBlockContentRight .glmBlockContent .glmTicketsSelectValue{ + width: 8%; + margin-right: 10px; + } + + .glmBlock:not(:first-child) .glmBlockContentRight .glmBlockContent:nth-child(2) .glmTicketsSelectValue{ + + width: 14% !important; + } + + .glmBlock:not(:first-child) .glmBlockContentLeft:not(.startContent) { + display: block; + float: left; +/* width:55%;*/ + width: 35%; + overflow: hidden; + } + .glmBlock:not(:first-child) .glmBlockContentRight:not(.startImage) { + display: block; + float: right; +/* width: 40%;*/ + width: 60%; + overflow: hidden; + margin-bottom: 10px; + margin-left: 5%; + min-width: 120px; + } +} +@media (min-width: 1200px){ + .glmBlock:not(:first-child) .glmBlockContentRight .glmBlockContent:nth-child(2) .glmTicketsSelectValue{ + + width: 12% !important; + } +} +.glmBlockContent p{ + font-family: "Open Sans", sans-serif; +} +.glmBlockContentLeft { + display: block; + float: left; + width:70%; + overflow: hidden; +} +.glmBlockContentRight { + display: block; + float: right; + width: 20%; + overflow: hidden; + margin-bottom: 10px; + margin-left: 5%; + min-width: 120px; +} +.glmBlockContentIndent { + display: block; + margin-left: 3em; +} +.glmSection { +} +.glmSection .glmSectionName { +} +.glmSection .glmSectionBold { + font-size: 1.1em; + font-weight: 600; +} +.glmSectionName { + font-size: 1.1em; + font-weight: 600; + margin: 1em 0 0 0; +} +#GLMeventDescr, #GLMvenueDescr, .glmCartVenueDescr, .glmCartEventDescr { + font-size: 0.8em; + margin: 0 0 2.2em 0 +} +.glmCartEventDescrMobile { + display: none; +} +.glmCartVenueDescr, .glmCartEventDescr:not(.promoDescr) { + margin: 0 0 15px 0; +/* visibility: hidden;*/ + display: none; +} + +.glmCartEvents { +} +.glmCartEvent { +} +.glmCartSelect { + width: 4em; +} +a.glmNavItem{ + margin-bottom: 10px; +} +.glmCartEventTitle { + font-size: 20px; + line-height: 22px; +/* font-family: "Lora","Times New Roman",Times,serif;*/ + font-family: "Open Sans", sans-serif; + color: #043867; + margin-bottom: 5px; +} +.glmCartEventInfo { + margin-top: .5em; + clear: both; +} +.glmCartEventInfoLeft { + float: left; + padding-right: 100px; +} +.glmCartHeader { + font-size: 1.1em; + font-weight: 600; + clear: both; +} +.glmCartHeader .glmCartText { + font-weight: bold; + border-bottom: 1px solid #CCC; +} +.glmCartValues { + clear: both; +} +.glmCartTable { + display: block; + width: 100%; + overflow: hidden; + margin: 10px 0 0 0; + padding: 10px; + border: 1px solid #CFCFCF; + background: rgba(0,0,0,0.05); +} +.glmCartTable.totals { + display: block; + width: 100%; + overflow: hidden; + margin: 10px 0 0 0; + padding: 10px 0 10px 20px; + border: 0; + background: none; +} +.glmCartTable.sub { + padding-top: 0; + padding-bottom: 0; +} +.glmCartNumb { + width: 20%; + float: left; + align: right; +} +.glmCartText { + display: block; + width: 17%; + margin-right: 3%; + float: left; + padding: 2px 0 0 0; +} + +.glmGrandTotals { + float: right; + color: #900; + font-weight: 600; + font-size: 1.1em; +} + +.glmCartTable.totals .glmCartText { + display: block; + width: 30%; + margin-right: 3%; + float: right; + padding: 2px 0 0 0; +} +.glmCartTable.totals .glmCartHeader .glmCartText { + color: #900; +} +.glmCartTable.totals .glmCartText.grand { + margin-right: 0; + padding-right: 0; +} +.glmCartTotal { + width: 30%; + float: left; +} +.glmCartWide { + width: 40%; + float: left; +} +.glmCartBlock.totals .glmCartWide { + width: 100%; + padding-top: 10px; +} +.glmCartTotal { + width:20%; + font-weight: 600; + font-size: 1.1em; +} +.glmCartSubTotals { + margin-top: 10px; + clear: both; +} +.glmCartSubTotals .glmCartTable { + background: none; + border: 0; +} +.glmCartSubTotals .glmCartTable .glmCartHeader { + float: right; + width: 40%; +} +.glmCartSubTotals .glmCartTable .glmCartHeader .glmCartText { + width: 42%; + margin-right: 8%; + height: auto; + text-align: left; +} +.glmCartSubTotals .glmCartTable .glmCartValues { + float: right; + clear: right; + width: 40%; +} +.glmCartSubTotals .glmCartTable .glmCartValues .glmCartText { + width: 42%; + margin-right: 8%; + border-bottom: 0; + height: auto; + text-align: left; +} +.glmCartTotals { + margin-top: 10px; +} +.glmCartBlock { + display: block; + width: 100%; + overflow: hidden; + margin: 0 0 1em 0; + padding: 10px; + border: 1px solid #CFCFCF; + background: rgba(0,0,0,0.05); +} +.glmCartBlock.totals { + display: block; + width: 100%; + overflow: hidden; + margin: 0 0 10px 0; + padding: 0; + border: 0; + background: none; +} +.glmCartBlockTitle { + font-size: 22px; + line-height: 28px; + font-family: "Lora","Times New Roman",Times,serif; + margin: 0 0 0 0; +} +.glmCartBlockSmallTitle { + font-size: 16px; + line-height: 22px; + font-family: "Lora","Times New Roman",Times,serif; +} +.glmCartBlock input[type="textarea"] { + display: block; + float: left; + clear: left; + width: 100%; +} +.glmEventDateInput { + width: 80px; +} +.glmCartBlock.totals .glmCartBlockTitle { + border-bottom: 1px solid #CCC; +} +.glmCartBlockSubTitle { + margin-top: 1em; + font-size: 1.1em; + font-weight: 600; + margin-bottom: .5em; +} +.glmCartBlockSubTitleValue { + +} +.glmCartBlockText { +} +.glmCartBlockDates { + clear: both; +} +.glmCartBlockDate { + margin-top: .5em; +} +.glmSpecialRequests { + margin: 0 0 3em 0; +} +#GLMcontent { + padding: 0; + margin: 0 auto +} +#GLMcontent>* { +/* padding: 0 15px; */ +} +#GLMevent, #GLMtickets, #GLMvenue { + /* max-width: 500px; */ + margin: 0 auto 1em auto +} +#GLMnavigation:after { + content: ""; + display: table; + clear: both +} +.glmNavItemInactive { + float: right; + padding: 3px 10px; + width: auto; + display: block; + overflow: hidden; + background: #ddd; + border: 1px solid #aaa; + border-radius: 8px; + cursor: pointer; + text-transform: uppercase; + text-align: center; +} +.glmNavItem { + float: right; + padding: 3px 10px; + width: auto; + display: block; + overflow: hidden; + background: #cc6535; + border: 1px solid #cc6535; + border-radius: 8px; + cursor: pointer; + text-transform: uppercase; +} +a.glmNavItem { + color: #FFF; + font-weight: bold; + text-shadow: none; +} +div.glmNavItem { + color: #FFF; + font-weight: bold; + text-shadow: none; +} +.glmNavItem.cart { + background: #043867; + border: 1px solid #043867; +} +#category h1{ + font-size: 24px; + color: #3a8bb6; + font-family: "Open Sans", sans-serif; + +} +.glmNavItemWide { + display: block; + width: 400px; + overflow: hidden; + margin: 12px 0 0 0; + padding: 8px 0; + background: #900; + border: 1px solid #900; + border-radius: 8px; + color: #FFF; + text-align: center; + vertical-align: middle; + font-size: 18px; + font-weight: bold; + font-family: "Times New Roman", Times, serif; + cursor: pointer; +} +.glmSelectItem { + padding: 5px; + margin: 0; + width: 150px; + border-left: 1px solid #e3e3e3; + cursor: pointer; + border: 1px solid #e3e3e3; + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + -ms-border-radius: 6px; + -o-border-radius: 6px; + border-radius: 6px; + text-align: center; + font-weight: 600; + font-shadow: 0 1px #fff; + font-size: 0.85em; + background: #fcfcfc; + -webkit-background-clip: padding; + -moz-background-clip: padding; + background-clip: padding-box; +} +#GLMcheckout .glmNavItem, #GLMticketCart .glmNavItem { + width: 33.3333% +} +#GLMeventDates, #GLMvenueLocation, #GLMvenueDetail, #GLMvenueSectionMap { + margin: 0 0 15px 0 +} +.glmPrompt { + font-weight: 600; + font-size: 1.1em +} +.glmTicketDescr { + font-size: 0.85em +} +.glmTicketAvailable { + margin: 5px 0; + font-weight: 600 +} +.glmSectionTickets { + margin: 15px 0 +} +.glmTicketName { + font-size: 1.35em; + font-weight: 600 +} +.glmSectionSelector { + border: 1px solid #e3e3e3; + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + -ms-border-radius: 6px; + -o-border-radius: 6px; + border-radius: 6px; + cursor: pointer; + background-color: #f8f8f8; + padding: 8px 15px; + margin: 5px 0; + font-size: 1.15em; + font-weight: 600; + display: inline-block; + font-shadow: 0 1px #fff +} +.glmSectionSelector:active { + -webkit-box-shadow: inset 0 0 8px #dbdbdb; + -moz-box-shadow: inset 0 0 8px #dbdbdb; + box-shadow: inset 0 0 8px #dbdbdb +} +#GLMticketsSummary { + font-weight: 600; + font-size: 1.35em; + margin-top: 30px +} +.glmTicketsSelect { + clear: both; + margin: 1em; +} +.glmTicketsSelectPrompt { + font-size: 1em; + font-weight: 600; + line-height: 125%; + float: left; + padding-right: .2em; +} +.glmTicketsSelectValueWrapper { + float: right; + width: 150px; + text-align: right; +} +.glmTicketsSelectValue { + float: right; + width: 40%; + text-align: right; +} +#glmQuantSelector { + float: right; + text-align: right; + width: 100px; + height: 28px; +} +#GLMpolicy { + font-size: 0.85em; + font-style: italic; +/* margin-bottom: 15px; */ +} +.glmTicketPrice { + font-weight: 600; + margin: 15px 0 5px 0; + font-size: 1.25em +} +#GLMreason { + border: 1px solid #333; + padding: 1em; +} +.GLMreasonTitle { + color: red; +} +.GLMreasonList { +} +.GLMmapWindow { + width: 100%; + height: 140px; + border: 1px solid #CCC; +} +.glmDescr { + font-family: "Open Sans", sans-serif; + line-height: 1.3; +} +.glmCartFailedInput { + background: #FFaBa9; + padding: .2em; +} +.glmCartRequired { + color: red; +} +/* CHECKOUT STUFF */ +.glmCartFormLine { + clear: both; +} +.glmCartFormPrompt { + width: 30%; + float: left; + text-align: right; + font-weight: 600; + font-size: 1.1em; + padding-right: .5em; +} +.glmCartFormInput { + padding-left: 1em; + width: 70%; + float: left; + margin-bottom: .5em; +} +.glmCartFormInput span { + display: block; + width: 100%; + overflow: hidden; +} +/* Forms */ +.glmCartForm { + display: block; + width: 100%; + overflow: hidden; + padding: 10px; + background: #F5F5F5; + margin: 0 0 10px 0; + font-size: 12px; + border: 1px solid #CCC; + color: #656565; +} +.glmCartForm input[type="text"] { + display: block; + float: left; + clear: left; + width: 300px; +} +.glmCartForm select { + display: block; + float: left; + clear: left; + width: 200px; +} +.glmCartPayment { + margin: 2em 0 0 0 +} +.glmInput { + float: right; +} +/* Mobile */ +@media screen and (max-width:768px) { + .glmBlockContentRight { + float: left; + width: 100%; + margin-left: 0; + margin-right: 0; + margin-top: 10px; + margin-bottom: 10px; + } + .glmBlockContentRight img{ + max-width: 100%; + } + .glmBlockContentLeft { + display: inline; + float: left; + width: 100%; + } + .glmBlockContentLeft div { + clear: none !important; + } + /* Mobile Forms */ + +} +/* Small Mobile */ +@media screen and (max-width:599px) { + .GLMmapWindow { + height: 130px; + } + .glmCartFormPrompt { + display: block; + width: 100%; + overflow: hidden; + text-align: left; + } + .glmCartFormInput { + margin-left: 0; + padding-left: 0; + } + #GLMpageTitle { + width: 50%; + } + .glmCartHeader { + float: left; + clear: none; + width: 50%; + overflow: hidden; + + margin-bottom: 20px; + } + .glmCartHeader .glmCartText { + display: block; + width: 100%; + overflow: hidden; + border-bottom: 1px solid #CCC; + height: 30px; + } + .glmCartValues { + float: left; + clear: none; + width: 50%; + overflow: hidden; + margin-bottom: 20px; + } + .glmCartValues .glmCartText { + display: block; + width: 100%; + overflow: hidden; + border-bottom: 1px solid #CCC; + height: 30px; + } + .glmCartSubTotals .glmCartTable .glmCartHeader { + float: right; + width: 66%; + } + .glmCartSubTotals .glmCartTable .glmCartHeader .glmCartText { + width: 42%; + margin-right: 0; + margin-left: 8%; + height: auto; + text-align: right; + } + .glmCartSubTotals .glmCartTable .glmCartValues { + float: right; + clear: right; + width: 66%; + } + .glmCartSubTotals .glmCartTable .glmCartValues .glmCartText { + width: 42%; + margin-right: 0; + margin-left: 8%; + border-bottom: 0; + height: auto; + text-align: right; + } + .glmCartTable.totals { + padding-left: 0; + padding-right: 0; + } + .glmCartTable.totals .glmCartHeader { + float: right; + width: 100%; + margin-bottom: 0; + } + .glmCartTable.totals .glmCartHeader .glmCartText { + width: 28%; + margin-right: 0; + margin-left: 5%; + border-bottom: 1px solid #CCC; + height: auto; + text-align: right; + } + .glmCartTable.totals .glmCartValues { + float: right; + width: 100%; + } + .glmCartTable.totals .glmCartValues .glmCartText { + width: 28%; + margin-right: 0; + margin-left: 5%; + border-bottom: 0; + height: auto; + text-align: right; + } + .glmTicketsSelectValueWrapper { + float: left; + width: 150px; + clear: left; + margin-top: 10px; + } + .glmBlockLeft { + width: 100%; + } + .glmCartEventDescrMobile { + display: inline; + } + .glmCartEventDescr { + display: none; + } +} +/* MidSmall Mobile */ +@media screen and (max-width:449px) { + #GLMpageTitle { + font-size: 16px; + line-height: 20px; + } + .glmBlockName { + font-size: 16px; + line-height: 18px; + } + .glmCartFormInput { + width: 100%; + } + .glmCartForm input[type="text"] { + width: 100%; + } + .glmCartForm select { + width:100%; + } + .glmNavItemWide { + width: 100%; + } + .glmNavItem.add { + width: 100%; + text-align: center; + } + #GLMcheckoutBtn { + width: 100%; + text-align: center; + } + +} +/* XSmall Mobile */ +@media screen and (max-width:399px) { + .glmNavItem.chooser { + display: block; + width: 100%; + overflow: hidden; + margin-top: 10px; + text-align: center; + } +} + +#glmReloadBlocker { + display: none; + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + background-color : transparent; + text-align: center; + z-index: 1000; +} +#glmReloadBlocker div { + height: auto; + width: 300px; + padding: 10px; + background: #eee; + position: fixed; + border-radius: 10px; + border: 2px solid #666; + color: red; + font-size: 1.3em; + line-height: 150%; + + margin: -150px 0 0 -150px; + left: 50%; + top: 60%; + + box-shadow: 10px 10px 5px #888888; +} +#glmDevelopmentNotice { + padding: 5px; + border: 1px solid black; + width: auto; + clear: both; + margin-top: 4em; +} diff --git a/web/front/Gaslight/EventManagement.js b/web/front/Gaslight/EventManagement.js new file mode 100644 index 0000000..b837b57 --- /dev/null +++ b/web/front/Gaslight/EventManagement.js @@ -0,0 +1,107 @@ +/* + * Event Management Front-End Area JAVAScript - Tickets interface + */ + +var f_loadAction = false; +var f_replaceContents = false; +var duration = 0; + +// jQuery Section +$(document).ready(function(){ + + /* + * Data Setup Section + */ + + var siteURL = baseSiteURL; + var appURL = baseAppURL; + + /* + * Load an action to a div with the specified id where id is also Action to be run + */ + function loadAction(id, container, params) { + + // Display loading message + $('#'+container).html('
    Loading, Please Wait...
    '); + $('#'+container).show(duration); + + // Build the URL and call it with AJAX + url = appURL + "?Action=" + id; + if (params) { + url = url + '&' + params; + } + $.post( url, + '', + function(data) { + // Populate the container with the results + $('#'+container).html(data); + restartOnTabSelect(); + } + ); + + } + f_loadAction = loadAction; + + // Replace the contents of a div + function replaceContents(data, destination) { + destination.html(data); + } + f_replaceContents = replaceContents; + + /* + * General Slider Operations + */ + + // Slider area actions + $('.glmSectionSelector').on('click', null, function() { + + // Get the ID of the area to slide from the emSliderId="" parameter in the div tag. + var sliderId = $(this).attr('emSliderId'); + + // If the slider is currently open - close it, otherwise open it. + if ($('#'+sliderId).is(':visible')) { + $('#'+sliderId).hide(duration); + } else { + $('#'+sliderId).show(duration); + } + }); + // Startup by closing all areas that are supposed to be closed by default + $('.glmSectionTickets').hide(duration); + + /* + * Check for user timeout + */ + var inactivityTime = 1800000; // Number of milliseconds to user timeout + + // If theres no activity for 5 seconds do something + var activityTimeout = setTimeout(inActive, inactivityTime); + + function resetActive(){ + $(document.body).attr('class', 'active'); + clearTimeout(activityTimeout); + activityTimeout = setTimeout(inActive, inactivityTime); + } + + // No activity do something. + function inActive(){ + alert("Your user session has timed out. Click OK to continue."); + window.location.href = siteURL; + } + + // Check for mousemove, could add other events here such as checking for key presses ect. + $(document).bind('mousemove', function(){resetActive()}); + +// var use_any_time = "Use any time of day,"; +// var glmDescr = $('.glmDescr').children('p'); +// var selectBtn = $('#GLMselectButton'); +// var shopBtn = $('.glmNavItem:nth-child(2)'); +// +// shopBtn.html("Purchase Tickets"); +// selectBtn.html("Add to Cart"); +// +// $.each(glmDescr, function(){ +// var text = $(this).text().replace(use_any_time, ''); +// $(this).text(text); +// }); + +}); diff --git a/web/front/Gaslight/assets/paypal_but6.gif b/web/front/Gaslight/assets/paypal_but6.gif new file mode 100644 index 0000000000000000000000000000000000000000..5da5a520da3967c966b4aa4bd9f0fcdeba928312 GIT binary patch literal 4774 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 literal 0 HcmV?d00001 diff --git a/web/front/MMM/EventManagement.css b/web/front/MMM/EventManagement.css new file mode 100644 index 0000000..9eef48a --- /dev/null +++ b/web/front/MMM/EventManagement.css @@ -0,0 +1,916 @@ +/* Additional styles for Event Management front-end */ +#GLMHeader { + display: block; + width: 100%; + overflow: hidden; + margin: 0 0 5px 0; + padding: 0; + border-bottom: 1px solid #CCC; +} +#GLMpageTitle { + color: #040267; + float: left; + font-family: "Lora","Times New Roman",Times,serif; + font-size: 20px; + line-height: 24px; + font-weight: normal; + margin: 0 0 10px; + padding: 0 0 5px 0; + width: 70%; + /*background: rgba(0,0,0,0.1);*/ +} +#GLMpageIntro { + margin: 1em 0 1em 0; +} +#GLMpageIntro p{ + font-size: 1rem; + font-family: "Open Sans", sans-serif; +} +.glmBold { + font-weight: 600; +} +.glmBlock { + display: block; + width: 100%; + overflow: hidden; + margin: 0 0 10px 0; + padding: 5px; + border: 1px solid #CFCFCF; + background: rgba(0,0,0,0.05); +} +.glmBlockList { + margin-top: 10px; + clear: both; +} +.glmBlockHeader, .glmBlockHeadder { + display: block; + width: 100%; + overflow: hidden; + margin: 0 0 5px 0; +} +.glmBlockName { + display: inline; + font-size: 24px; + line-height: 22px; + color: #043867; +/* font-family: "Lora","Times New Roman",Times,serif;*/ + font-family: "Open Sans", sans-serif; +} +.glmBlockName a{ + font-size: 18px; + color: #043867; +} +.glmBlockRightCol { + float: right; +} +.glmBlockContent { + margin: 0 0 0em 0; + clear: both; + width: 100%; + font-family: "Open Sans", sans-serif; +} +.glmTicketQuant{ + width: 45px; + height: 30px; +} +.glmTicketQuant option{ + font-size: 15px; +} +@media (min-width: 768px){ + .glmBlockContentRight img{ + float: right; + } + .glmBlock:not(:first-child) .glmBlockContentRight .glmBlockContent{ + clear: none; + /* width: 10%;*/ + /* float: left;*/ + } + .glmBlock:not(:first-child) .glmBlockContentRight .glmBlockContent .glmTicketsSelectValue{ + width: 10%; + margin-right: 10px; + } + .glmBlock:not(:first-child) .glmBlockContentRight .glmTicketsSelectPrompt{ + /* float: left;*/ + padding: 0; + margin-right: 3px; + } + .glmBlock:not(:first-child) .glmBlockContentRight .glmTicketsSelectValue{ + width: 20%; + float: left; + } + .glmBlock:not(:first-child) .glmBlockContentRight .glmInput{ + /* float: left;*/ + } + .glmBlock:not(:first-child) .glmBlockContentLeft { + display: block; + float: left; +/* width:55%;*/ + width: 33%; + overflow: hidden; + } + .glmBlock:not(:first-child) .glmBlockContentRight{ + display: block; + float: right; +/* width: 40%;*/ + width: 64%; + overflow: hidden; + margin-bottom: 10px; + margin-left: 1%; + min-width: 120px; + } + .glmBlock .glmBlockContentLeft.startContent, .glmCartBlock .glmBlockContentLeft.cartContent{ + display: block; + float: left; +/* width:55%;*/ + width: 50%; + overflow: hidden; + } + .glmBlock .glmBlockContentRight.startImage, .glmCartBlock .glmBlockContentRight.cartImage{ + display: block; + float: right; +/* width: 40%;*/ + width: 45%; + overflow: hidden; + margin-bottom: 10px; + margin-left: 5%; + min-width: 120px; + } + .glmBlock:not(:first-child) .glmBlockContentRight .glmBlockContent:nth-child(2) .glmTicketsSelectValue{ + + width: 18% !important; + } +} +@media (min-width: 992px){ + div[class^="GLMeventDateSelect"]{ + + } + .glmBlock:not(:first-child) .glmBlockContentRight .glmBlockContent .glmTicketsSelectValue{ + width: 8%; + margin-right: 10px; + } + + .glmBlock:not(:first-child) .glmBlockContentRight .glmBlockContent:nth-child(2) .glmTicketsSelectValue{ + + width: 14% !important; + } + + .glmBlock:not(:first-child) .glmBlockContentLeft:not(.startContent) { + display: block; + float: left; +/* width:55%;*/ + width: 35%; + overflow: hidden; + } + .glmBlock:not(:first-child) .glmBlockContentRight:not(.startImage) { + display: block; + float: right; +/* width: 40%;*/ + width: 60%; + overflow: hidden; + margin-bottom: 10px; + margin-left: 5%; + min-width: 120px; + } +} +@media (min-width: 1200px){ + .glmBlock:not(:first-child) .glmBlockContentRight .glmBlockContent:nth-child(2) .glmTicketsSelectValue{ + + width: 12% !important; + } +} +.glmBlockContent p{ + font-family: "Open Sans", sans-serif; +} +.glmBlockContentLeft { + display: block; + float: left; + width:70%; + overflow: hidden; +} +.glmBlockContentRight { + display: block; + float: right; + width: 20%; + overflow: hidden; + margin-bottom: 10px; + margin-left: 5%; + min-width: 120px; +} +.glmBlockContentIndent { + display: block; + margin-left: 3em; +} +.glmSection { +} +.glmSection .glmSectionName { +} +.glmSection .glmSectionBold { + font-size: 1.1em; + font-weight: 600; +} +.glmSectionName { + font-size: 1.1em; + font-weight: 600; + margin: 1em 0 0 0; +} +#GLMeventDescr, #GLMvenueDescr, .glmCartVenueDescr, .glmCartEventDescr { + font-size: 0.8em; + margin: 0 0 2.2em 0 +} +.glmCartEventDescrMobile { + display: none; +} +.glmCartVenueDescr, .glmCartEventDescr:not(.promoDescr) { + margin: 0 0 15px 0; +/* visibility: hidden;*/ + display: none; +} + +.glmCartEvents { +} +.glmCartEvent { +} +.glmCartSelect { + width: 4em; +} +a.glmNavItem{ + margin-bottom: 10px; +} +.glmCartEventTitle { + font-size: 20px; + line-height: 22px; +/* font-family: "Lora","Times New Roman",Times,serif;*/ + font-family: "Open Sans", sans-serif; + color: #043867; + margin-bottom: 5px; +} +.glmCartEventInfo { + margin-top: .5em; + clear: both; +} +.glmCartEventInfoLeft { + float: left; + padding-right: 100px; +} +.glmCartHeader { + font-size: 1.1em; + font-weight: 600; + clear: both; +} +.glmCartHeader .glmCartText { + font-weight: bold; + border-bottom: 1px solid #CCC; +} +.glmCartValues { + clear: both; +} +.glmCartTable { + display: block; + width: 100%; + overflow: hidden; + margin: 10px 0 0 0; + padding: 10px; + border: 1px solid #CFCFCF; + background: rgba(0,0,0,0.05); +} +.glmCartTable.totals { + display: block; + width: 100%; + overflow: hidden; + margin: 10px 0 0 0; + padding: 10px 0 10px 20px; + border: 0; + background: none; +} +.glmCartTable.sub { + padding-top: 0; + padding-bottom: 0; +} +.glmCartNumb { + width: 20%; + float: left; + align: right; +} +.glmCartText { + display: block; + width: 17%; + margin-right: 3%; + float: left; + padding: 2px 0 0 0; +} + +.glmGrandTotals { + float: right; + color: #900; + font-weight: 600; + font-size: 1.1em; +} + +.glmCartTable.totals .glmCartText { + display: block; + width: 30%; + margin-right: 3%; + float: right; + padding: 2px 0 0 0; +} +.glmCartTable.totals .glmCartHeader .glmCartText { + color: #900; +} +.glmCartTable.totals .glmCartText.grand { + margin-right: 0; + padding-right: 0; +} +.glmCartTotal { + width: 30%; + float: left; +} +.glmCartWide { + width: 40%; + float: left; +} +.glmCartBlock.totals .glmCartWide { + width: 100%; + padding-top: 10px; +} +.glmCartTotal { + width:20%; + font-weight: 600; + font-size: 1.1em; +} +.glmCartSubTotals { + margin-top: 10px; + clear: both; +} +.glmCartSubTotals .glmCartTable { + background: none; + border: 0; +} +.glmCartSubTotals .glmCartTable .glmCartHeader { + float: right; + width: 40%; +} +.glmCartSubTotals .glmCartTable .glmCartHeader .glmCartText { + width: 42%; + margin-right: 8%; + height: auto; + text-align: left; +} +.glmCartSubTotals .glmCartTable .glmCartValues { + float: right; + clear: right; + width: 40%; +} +.glmCartSubTotals .glmCartTable .glmCartValues .glmCartText { + width: 42%; + margin-right: 8%; + border-bottom: 0; + height: auto; + text-align: left; +} +.glmCartTotals { + margin-top: 10px; +} +.glmCartBlock { + display: block; + width: 100%; + overflow: hidden; + margin: 0 0 1em 0; + padding: 10px; + border: 1px solid #CFCFCF; + background: rgba(0,0,0,0.05); +} +.glmCartBlock.totals { + display: block; + width: 100%; + overflow: hidden; + margin: 0 0 10px 0; + padding: 0; + border: 0; + background: none; +} +.glmCartBlockTitle { + font-size: 22px; + line-height: 28px; + font-family: "Lora","Times New Roman",Times,serif; + margin: 0 0 0 0; +} +.glmCartBlockSmallTitle { + font-size: 16px; + line-height: 22px; + font-family: "Lora","Times New Roman",Times,serif; +} +.glmCartBlock input[type="textarea"] { + display: block; + float: left; + clear: left; + width: 100%; +} +.glmEventDateInput { + width: 80px; +} +.glmCartBlock.totals .glmCartBlockTitle { + border-bottom: 1px solid #CCC; +} +.glmCartBlockSubTitle { + margin-top: 1em; + font-size: 1.1em; + font-weight: 600; + margin-bottom: .5em; +} +.glmCartBlockSubTitleValue { + +} +.glmCartBlockText { +} +.glmCartBlockDates { + clear: both; +} +.glmCartBlockDate { + margin-top: .5em; +} +.glmSpecialRequests { + margin: 0 0 3em 0; +} +#GLMcontent { + padding: 0; + margin: 0 auto +} +#GLMcontent>* { +/* padding: 0 15px; */ +} +#GLMevent, #GLMtickets, #GLMvenue { + /* max-width: 500px; */ + margin: 0 auto 1em auto +} +#GLMnavigation:after { + content: ""; + display: table; + clear: both +} +.glmNavItemInactive { + float: right; + padding: 3px 10px; + width: auto; + display: block; + overflow: hidden; + background: #ddd; + border: 1px solid #aaa; + border-radius: 8px; + cursor: pointer; + text-transform: uppercase; + text-align: center; +} +.glmNavItem { + float: right; + padding: 3px 10px; + width: auto; + display: block; + overflow: hidden; + background: #cc6535; + border: 1px solid #cc6535; + border-radius: 8px; + cursor: pointer; + text-transform: uppercase; +} +a.glmNavItem { + color: #FFF; + font-weight: bold; + text-shadow: none; +} +div.glmNavItem { + color: #FFF; + font-weight: bold; + text-shadow: none; +} +.glmNavItem.cart { + background: #043867; + border: 1px solid #043867; +} +#category h1{ + font-size: 24px; + color: #3a8bb6; + font-family: "Open Sans", sans-serif; + +} +.glmNavItemWide { + display: block; + width: 400px; + overflow: hidden; + margin: 12px 0 0 0; + padding: 8px 0; + background: #900; + border: 1px solid #900; + border-radius: 8px; + color: #FFF; + text-align: center; + vertical-align: middle; + font-size: 18px; + font-weight: bold; + font-family: "Times New Roman", Times, serif; + cursor: pointer; +} +.glmSelectItem { + padding: 5px; + margin: 0; + width: 150px; + border-left: 1px solid #e3e3e3; + cursor: pointer; + border: 1px solid #e3e3e3; + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + -ms-border-radius: 6px; + -o-border-radius: 6px; + border-radius: 6px; + text-align: center; + font-weight: 600; + font-shadow: 0 1px #fff; + font-size: 0.85em; + background: #fcfcfc; + -webkit-background-clip: padding; + -moz-background-clip: padding; + background-clip: padding-box; +} +#GLMcheckout .glmNavItem, #GLMticketCart .glmNavItem { + width: 33.3333% +} +#GLMeventDates, #GLMvenueLocation, #GLMvenueDetail, #GLMvenueSectionMap { + margin: 0 0 15px 0 +} +.glmPrompt { + font-weight: 600; + font-size: 1.1em +} +.glmTicketDescr { + font-size: 0.85em +} +.glmTicketAvailable { + margin: 5px 0; + font-weight: 600 +} +.glmSectionTickets { + margin: 15px 0 +} +.glmTicketName { + font-size: 1.35em; + font-weight: 600 +} +.glmSectionSelector { + border: 1px solid #e3e3e3; + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + -ms-border-radius: 6px; + -o-border-radius: 6px; + border-radius: 6px; + cursor: pointer; + background-color: #f8f8f8; + padding: 8px 15px; + margin: 5px 0; + font-size: 1.15em; + font-weight: 600; + display: inline-block; + font-shadow: 0 1px #fff +} +.glmSectionSelector:active { + -webkit-box-shadow: inset 0 0 8px #dbdbdb; + -moz-box-shadow: inset 0 0 8px #dbdbdb; + box-shadow: inset 0 0 8px #dbdbdb +} +#GLMticketsSummary { + font-weight: 600; + font-size: 1.35em; + margin-top: 30px +} +.glmTicketsSelect { + clear: both; + margin: 1em; +} +.glmTicketsSelectPrompt { + font-size: 1em; + font-weight: 600; + line-height: 125%; + float: left; + padding-right: .2em; +} +.glmTicketsSelectValueWrapper { + float: right; + width: 150px; + text-align: right; +} +.glmTicketsSelectValue { + float: right; + width: 40%; + text-align: right; +} +#glmQuantSelector { + float: right; + text-align: right; + width: 100px; + height: 28px; +} +#GLMpolicy { + font-size: 0.85em; + font-style: italic; +/* margin-bottom: 15px; */ +} +.glmTicketPrice { + font-weight: 600; + margin: 15px 0 5px 0; + font-size: 1.25em +} +#GLMreason { + border: 1px solid #333; + padding: 1em; +} +.GLMreasonTitle { + color: red; +} +.GLMreasonList { +} +.GLMmapWindow { + width: 100%; + height: 140px; + border: 1px solid #CCC; +} +.glmDescr { + font-family: "Open Sans", sans-serif; + line-height: 1.3; +} +.glmCartFailedInput { + background: #FFaBa9; + padding: .2em; +} +.glmCartRequired { + color: red; +} +/* CHECKOUT STUFF */ +.glmCartFormLine { + clear: both; +} +.glmCartFormPrompt { + width: 30%; + float: left; + text-align: right; + font-weight: 600; + font-size: 1.1em; + padding-right: .5em; +} +.glmCartFormInput { + padding-left: 1em; + width: 70%; + float: left; + margin-bottom: .5em; +} +.glmCartFormInput span { + display: block; + width: 100%; + overflow: hidden; +} +/* Forms */ +.glmCartForm { + display: block; + width: 100%; + overflow: hidden; + padding: 10px; + background: #F5F5F5; + margin: 0 0 10px 0; + font-size: 12px; + border: 1px solid #CCC; + color: #656565; +} +.glmCartForm input[type="text"] { + display: block; + float: left; + clear: left; + width: 300px; +} +.glmCartForm select { + display: block; + float: left; + clear: left; + width: 200px; +} +.glmCartPayment { + margin: 2em 0 0 0 +} +.glmInput { + float: right; +} +/* Mobile */ +@media screen and (max-width:768px) { + .glmBlockContentRight { + float: left; + width: 100%; + margin-left: 0; + margin-right: 0; + margin-top: 10px; + margin-bottom: 10px; + } + .glmBlockContentRight img{ + max-width: 100%; + } + .glmBlockContentLeft { + display: inline; + float: left; + width: 100%; + } + .glmBlockContentLeft div { + clear: none !important; + } + /* Mobile Forms */ + +} +/* Small Mobile */ +@media screen and (max-width:599px) { + .GLMmapWindow { + height: 130px; + } + .glmCartFormPrompt { + display: block; + width: 100%; + overflow: hidden; + text-align: left; + } + .glmCartFormInput { + margin-left: 0; + padding-left: 0; + } + #GLMpageTitle { + width: 50%; + } + .glmCartHeader { + float: left; + clear: none; + width: 50%; + overflow: hidden; + + margin-bottom: 20px; + } + .glmCartHeader .glmCartText { + display: block; + width: 100%; + overflow: hidden; + border-bottom: 1px solid #CCC; + height: 30px; + } + .glmCartValues { + float: left; + clear: none; + width: 50%; + overflow: hidden; + margin-bottom: 20px; + } + .glmCartValues .glmCartText { + display: block; + width: 100%; + overflow: hidden; + border-bottom: 1px solid #CCC; + height: 30px; + } + .glmCartSubTotals .glmCartTable .glmCartHeader { + float: right; + width: 66%; + } + .glmCartSubTotals .glmCartTable .glmCartHeader .glmCartText { + width: 42%; + margin-right: 0; + margin-left: 8%; + height: auto; + text-align: right; + } + .glmCartSubTotals .glmCartTable .glmCartValues { + float: right; + clear: right; + width: 66%; + } + .glmCartSubTotals .glmCartTable .glmCartValues .glmCartText { + width: 42%; + margin-right: 0; + margin-left: 8%; + border-bottom: 0; + height: auto; + text-align: right; + } + .glmCartTable.totals { + padding-left: 0; + padding-right: 0; + } + .glmCartTable.totals .glmCartHeader { + float: right; + width: 100%; + margin-bottom: 0; + } + .glmCartTable.totals .glmCartHeader .glmCartText { + width: 28%; + margin-right: 0; + margin-left: 5%; + border-bottom: 1px solid #CCC; + height: auto; + text-align: right; + } + .glmCartTable.totals .glmCartValues { + float: right; + width: 100%; + } + .glmCartTable.totals .glmCartValues .glmCartText { + width: 28%; + margin-right: 0; + margin-left: 5%; + border-bottom: 0; + height: auto; + text-align: right; + } + .glmTicketsSelectValueWrapper { + float: left; + width: 150px; + clear: left; + margin-top: 10px; + } + .glmBlockLeft { + width: 100%; + } + .glmCartEventDescrMobile { + display: inline; + } + .glmCartEventDescr { + display: none; + } +} +/* MidSmall Mobile */ +@media screen and (max-width:449px) { + #GLMpageTitle { + font-size: 16px; + line-height: 20px; + } + .glmBlockName { + font-size: 16px; + line-height: 18px; + } + .glmCartFormInput { + width: 100%; + } + .glmCartForm input[type="text"] { + width: 100%; + } + .glmCartForm select { + width:100%; + } + .glmNavItemWide { + width: 100%; + } + .glmNavItem.add { + width: 100%; + text-align: center; + } + #GLMcheckoutBtn { + width: 100%; + text-align: center; + } + +} +/* XSmall Mobile */ +@media screen and (max-width:399px) { + .glmNavItem.chooser { + display: block; + width: 100%; + overflow: hidden; + margin-top: 10px; + text-align: center; + } +} + +#glmReloadBlocker { + display: none; + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + background-color : transparent; + text-align: center; + z-index: 1000; +} +#glmReloadBlocker div { + height: auto; + width: 300px; + padding: 10px; + background: #eee; + position: fixed; + border-radius: 10px; + border: 2px solid #666; + color: red; + font-size: 1.3em; + line-height: 150%; + + margin: -150px 0 0 -150px; + left: 50%; + top: 60%; + + box-shadow: 10px 10px 5px #888888; +} +#glmDevelopmentNotice { + padding: 5px; + border: 1px solid black; + width: auto; + clear: both; + margin-top: 4em; +} diff --git a/web/front/MMM/EventManagement.js b/web/front/MMM/EventManagement.js new file mode 100644 index 0000000..b837b57 --- /dev/null +++ b/web/front/MMM/EventManagement.js @@ -0,0 +1,107 @@ +/* + * Event Management Front-End Area JAVAScript - Tickets interface + */ + +var f_loadAction = false; +var f_replaceContents = false; +var duration = 0; + +// jQuery Section +$(document).ready(function(){ + + /* + * Data Setup Section + */ + + var siteURL = baseSiteURL; + var appURL = baseAppURL; + + /* + * Load an action to a div with the specified id where id is also Action to be run + */ + function loadAction(id, container, params) { + + // Display loading message + $('#'+container).html('
    Loading, Please Wait...
    '); + $('#'+container).show(duration); + + // Build the URL and call it with AJAX + url = appURL + "?Action=" + id; + if (params) { + url = url + '&' + params; + } + $.post( url, + '', + function(data) { + // Populate the container with the results + $('#'+container).html(data); + restartOnTabSelect(); + } + ); + + } + f_loadAction = loadAction; + + // Replace the contents of a div + function replaceContents(data, destination) { + destination.html(data); + } + f_replaceContents = replaceContents; + + /* + * General Slider Operations + */ + + // Slider area actions + $('.glmSectionSelector').on('click', null, function() { + + // Get the ID of the area to slide from the emSliderId="" parameter in the div tag. + var sliderId = $(this).attr('emSliderId'); + + // If the slider is currently open - close it, otherwise open it. + if ($('#'+sliderId).is(':visible')) { + $('#'+sliderId).hide(duration); + } else { + $('#'+sliderId).show(duration); + } + }); + // Startup by closing all areas that are supposed to be closed by default + $('.glmSectionTickets').hide(duration); + + /* + * Check for user timeout + */ + var inactivityTime = 1800000; // Number of milliseconds to user timeout + + // If theres no activity for 5 seconds do something + var activityTimeout = setTimeout(inActive, inactivityTime); + + function resetActive(){ + $(document.body).attr('class', 'active'); + clearTimeout(activityTimeout); + activityTimeout = setTimeout(inActive, inactivityTime); + } + + // No activity do something. + function inActive(){ + alert("Your user session has timed out. Click OK to continue."); + window.location.href = siteURL; + } + + // Check for mousemove, could add other events here such as checking for key presses ect. + $(document).bind('mousemove', function(){resetActive()}); + +// var use_any_time = "Use any time of day,"; +// var glmDescr = $('.glmDescr').children('p'); +// var selectBtn = $('#GLMselectButton'); +// var shopBtn = $('.glmNavItem:nth-child(2)'); +// +// shopBtn.html("Purchase Tickets"); +// selectBtn.html("Add to Cart"); +// +// $.each(glmDescr, function(){ +// var text = $(this).text().replace(use_any_time, ''); +// $(this).text(text); +// }); + +}); diff --git a/web/front/MMM/assets/paypal_but6.gif b/web/front/MMM/assets/paypal_but6.gif new file mode 100644 index 0000000000000000000000000000000000000000..5da5a520da3967c966b4aa4bd9f0fcdeba928312 GIT binary patch literal 4774 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 literal 0 HcmV?d00001 diff --git a/web/front/PointerBoat/EventManagement.css b/web/front/PointerBoat/EventManagement.css new file mode 100644 index 0000000..9eef48a --- /dev/null +++ b/web/front/PointerBoat/EventManagement.css @@ -0,0 +1,916 @@ +/* Additional styles for Event Management front-end */ +#GLMHeader { + display: block; + width: 100%; + overflow: hidden; + margin: 0 0 5px 0; + padding: 0; + border-bottom: 1px solid #CCC; +} +#GLMpageTitle { + color: #040267; + float: left; + font-family: "Lora","Times New Roman",Times,serif; + font-size: 20px; + line-height: 24px; + font-weight: normal; + margin: 0 0 10px; + padding: 0 0 5px 0; + width: 70%; + /*background: rgba(0,0,0,0.1);*/ +} +#GLMpageIntro { + margin: 1em 0 1em 0; +} +#GLMpageIntro p{ + font-size: 1rem; + font-family: "Open Sans", sans-serif; +} +.glmBold { + font-weight: 600; +} +.glmBlock { + display: block; + width: 100%; + overflow: hidden; + margin: 0 0 10px 0; + padding: 5px; + border: 1px solid #CFCFCF; + background: rgba(0,0,0,0.05); +} +.glmBlockList { + margin-top: 10px; + clear: both; +} +.glmBlockHeader, .glmBlockHeadder { + display: block; + width: 100%; + overflow: hidden; + margin: 0 0 5px 0; +} +.glmBlockName { + display: inline; + font-size: 24px; + line-height: 22px; + color: #043867; +/* font-family: "Lora","Times New Roman",Times,serif;*/ + font-family: "Open Sans", sans-serif; +} +.glmBlockName a{ + font-size: 18px; + color: #043867; +} +.glmBlockRightCol { + float: right; +} +.glmBlockContent { + margin: 0 0 0em 0; + clear: both; + width: 100%; + font-family: "Open Sans", sans-serif; +} +.glmTicketQuant{ + width: 45px; + height: 30px; +} +.glmTicketQuant option{ + font-size: 15px; +} +@media (min-width: 768px){ + .glmBlockContentRight img{ + float: right; + } + .glmBlock:not(:first-child) .glmBlockContentRight .glmBlockContent{ + clear: none; + /* width: 10%;*/ + /* float: left;*/ + } + .glmBlock:not(:first-child) .glmBlockContentRight .glmBlockContent .glmTicketsSelectValue{ + width: 10%; + margin-right: 10px; + } + .glmBlock:not(:first-child) .glmBlockContentRight .glmTicketsSelectPrompt{ + /* float: left;*/ + padding: 0; + margin-right: 3px; + } + .glmBlock:not(:first-child) .glmBlockContentRight .glmTicketsSelectValue{ + width: 20%; + float: left; + } + .glmBlock:not(:first-child) .glmBlockContentRight .glmInput{ + /* float: left;*/ + } + .glmBlock:not(:first-child) .glmBlockContentLeft { + display: block; + float: left; +/* width:55%;*/ + width: 33%; + overflow: hidden; + } + .glmBlock:not(:first-child) .glmBlockContentRight{ + display: block; + float: right; +/* width: 40%;*/ + width: 64%; + overflow: hidden; + margin-bottom: 10px; + margin-left: 1%; + min-width: 120px; + } + .glmBlock .glmBlockContentLeft.startContent, .glmCartBlock .glmBlockContentLeft.cartContent{ + display: block; + float: left; +/* width:55%;*/ + width: 50%; + overflow: hidden; + } + .glmBlock .glmBlockContentRight.startImage, .glmCartBlock .glmBlockContentRight.cartImage{ + display: block; + float: right; +/* width: 40%;*/ + width: 45%; + overflow: hidden; + margin-bottom: 10px; + margin-left: 5%; + min-width: 120px; + } + .glmBlock:not(:first-child) .glmBlockContentRight .glmBlockContent:nth-child(2) .glmTicketsSelectValue{ + + width: 18% !important; + } +} +@media (min-width: 992px){ + div[class^="GLMeventDateSelect"]{ + + } + .glmBlock:not(:first-child) .glmBlockContentRight .glmBlockContent .glmTicketsSelectValue{ + width: 8%; + margin-right: 10px; + } + + .glmBlock:not(:first-child) .glmBlockContentRight .glmBlockContent:nth-child(2) .glmTicketsSelectValue{ + + width: 14% !important; + } + + .glmBlock:not(:first-child) .glmBlockContentLeft:not(.startContent) { + display: block; + float: left; +/* width:55%;*/ + width: 35%; + overflow: hidden; + } + .glmBlock:not(:first-child) .glmBlockContentRight:not(.startImage) { + display: block; + float: right; +/* width: 40%;*/ + width: 60%; + overflow: hidden; + margin-bottom: 10px; + margin-left: 5%; + min-width: 120px; + } +} +@media (min-width: 1200px){ + .glmBlock:not(:first-child) .glmBlockContentRight .glmBlockContent:nth-child(2) .glmTicketsSelectValue{ + + width: 12% !important; + } +} +.glmBlockContent p{ + font-family: "Open Sans", sans-serif; +} +.glmBlockContentLeft { + display: block; + float: left; + width:70%; + overflow: hidden; +} +.glmBlockContentRight { + display: block; + float: right; + width: 20%; + overflow: hidden; + margin-bottom: 10px; + margin-left: 5%; + min-width: 120px; +} +.glmBlockContentIndent { + display: block; + margin-left: 3em; +} +.glmSection { +} +.glmSection .glmSectionName { +} +.glmSection .glmSectionBold { + font-size: 1.1em; + font-weight: 600; +} +.glmSectionName { + font-size: 1.1em; + font-weight: 600; + margin: 1em 0 0 0; +} +#GLMeventDescr, #GLMvenueDescr, .glmCartVenueDescr, .glmCartEventDescr { + font-size: 0.8em; + margin: 0 0 2.2em 0 +} +.glmCartEventDescrMobile { + display: none; +} +.glmCartVenueDescr, .glmCartEventDescr:not(.promoDescr) { + margin: 0 0 15px 0; +/* visibility: hidden;*/ + display: none; +} + +.glmCartEvents { +} +.glmCartEvent { +} +.glmCartSelect { + width: 4em; +} +a.glmNavItem{ + margin-bottom: 10px; +} +.glmCartEventTitle { + font-size: 20px; + line-height: 22px; +/* font-family: "Lora","Times New Roman",Times,serif;*/ + font-family: "Open Sans", sans-serif; + color: #043867; + margin-bottom: 5px; +} +.glmCartEventInfo { + margin-top: .5em; + clear: both; +} +.glmCartEventInfoLeft { + float: left; + padding-right: 100px; +} +.glmCartHeader { + font-size: 1.1em; + font-weight: 600; + clear: both; +} +.glmCartHeader .glmCartText { + font-weight: bold; + border-bottom: 1px solid #CCC; +} +.glmCartValues { + clear: both; +} +.glmCartTable { + display: block; + width: 100%; + overflow: hidden; + margin: 10px 0 0 0; + padding: 10px; + border: 1px solid #CFCFCF; + background: rgba(0,0,0,0.05); +} +.glmCartTable.totals { + display: block; + width: 100%; + overflow: hidden; + margin: 10px 0 0 0; + padding: 10px 0 10px 20px; + border: 0; + background: none; +} +.glmCartTable.sub { + padding-top: 0; + padding-bottom: 0; +} +.glmCartNumb { + width: 20%; + float: left; + align: right; +} +.glmCartText { + display: block; + width: 17%; + margin-right: 3%; + float: left; + padding: 2px 0 0 0; +} + +.glmGrandTotals { + float: right; + color: #900; + font-weight: 600; + font-size: 1.1em; +} + +.glmCartTable.totals .glmCartText { + display: block; + width: 30%; + margin-right: 3%; + float: right; + padding: 2px 0 0 0; +} +.glmCartTable.totals .glmCartHeader .glmCartText { + color: #900; +} +.glmCartTable.totals .glmCartText.grand { + margin-right: 0; + padding-right: 0; +} +.glmCartTotal { + width: 30%; + float: left; +} +.glmCartWide { + width: 40%; + float: left; +} +.glmCartBlock.totals .glmCartWide { + width: 100%; + padding-top: 10px; +} +.glmCartTotal { + width:20%; + font-weight: 600; + font-size: 1.1em; +} +.glmCartSubTotals { + margin-top: 10px; + clear: both; +} +.glmCartSubTotals .glmCartTable { + background: none; + border: 0; +} +.glmCartSubTotals .glmCartTable .glmCartHeader { + float: right; + width: 40%; +} +.glmCartSubTotals .glmCartTable .glmCartHeader .glmCartText { + width: 42%; + margin-right: 8%; + height: auto; + text-align: left; +} +.glmCartSubTotals .glmCartTable .glmCartValues { + float: right; + clear: right; + width: 40%; +} +.glmCartSubTotals .glmCartTable .glmCartValues .glmCartText { + width: 42%; + margin-right: 8%; + border-bottom: 0; + height: auto; + text-align: left; +} +.glmCartTotals { + margin-top: 10px; +} +.glmCartBlock { + display: block; + width: 100%; + overflow: hidden; + margin: 0 0 1em 0; + padding: 10px; + border: 1px solid #CFCFCF; + background: rgba(0,0,0,0.05); +} +.glmCartBlock.totals { + display: block; + width: 100%; + overflow: hidden; + margin: 0 0 10px 0; + padding: 0; + border: 0; + background: none; +} +.glmCartBlockTitle { + font-size: 22px; + line-height: 28px; + font-family: "Lora","Times New Roman",Times,serif; + margin: 0 0 0 0; +} +.glmCartBlockSmallTitle { + font-size: 16px; + line-height: 22px; + font-family: "Lora","Times New Roman",Times,serif; +} +.glmCartBlock input[type="textarea"] { + display: block; + float: left; + clear: left; + width: 100%; +} +.glmEventDateInput { + width: 80px; +} +.glmCartBlock.totals .glmCartBlockTitle { + border-bottom: 1px solid #CCC; +} +.glmCartBlockSubTitle { + margin-top: 1em; + font-size: 1.1em; + font-weight: 600; + margin-bottom: .5em; +} +.glmCartBlockSubTitleValue { + +} +.glmCartBlockText { +} +.glmCartBlockDates { + clear: both; +} +.glmCartBlockDate { + margin-top: .5em; +} +.glmSpecialRequests { + margin: 0 0 3em 0; +} +#GLMcontent { + padding: 0; + margin: 0 auto +} +#GLMcontent>* { +/* padding: 0 15px; */ +} +#GLMevent, #GLMtickets, #GLMvenue { + /* max-width: 500px; */ + margin: 0 auto 1em auto +} +#GLMnavigation:after { + content: ""; + display: table; + clear: both +} +.glmNavItemInactive { + float: right; + padding: 3px 10px; + width: auto; + display: block; + overflow: hidden; + background: #ddd; + border: 1px solid #aaa; + border-radius: 8px; + cursor: pointer; + text-transform: uppercase; + text-align: center; +} +.glmNavItem { + float: right; + padding: 3px 10px; + width: auto; + display: block; + overflow: hidden; + background: #cc6535; + border: 1px solid #cc6535; + border-radius: 8px; + cursor: pointer; + text-transform: uppercase; +} +a.glmNavItem { + color: #FFF; + font-weight: bold; + text-shadow: none; +} +div.glmNavItem { + color: #FFF; + font-weight: bold; + text-shadow: none; +} +.glmNavItem.cart { + background: #043867; + border: 1px solid #043867; +} +#category h1{ + font-size: 24px; + color: #3a8bb6; + font-family: "Open Sans", sans-serif; + +} +.glmNavItemWide { + display: block; + width: 400px; + overflow: hidden; + margin: 12px 0 0 0; + padding: 8px 0; + background: #900; + border: 1px solid #900; + border-radius: 8px; + color: #FFF; + text-align: center; + vertical-align: middle; + font-size: 18px; + font-weight: bold; + font-family: "Times New Roman", Times, serif; + cursor: pointer; +} +.glmSelectItem { + padding: 5px; + margin: 0; + width: 150px; + border-left: 1px solid #e3e3e3; + cursor: pointer; + border: 1px solid #e3e3e3; + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + -ms-border-radius: 6px; + -o-border-radius: 6px; + border-radius: 6px; + text-align: center; + font-weight: 600; + font-shadow: 0 1px #fff; + font-size: 0.85em; + background: #fcfcfc; + -webkit-background-clip: padding; + -moz-background-clip: padding; + background-clip: padding-box; +} +#GLMcheckout .glmNavItem, #GLMticketCart .glmNavItem { + width: 33.3333% +} +#GLMeventDates, #GLMvenueLocation, #GLMvenueDetail, #GLMvenueSectionMap { + margin: 0 0 15px 0 +} +.glmPrompt { + font-weight: 600; + font-size: 1.1em +} +.glmTicketDescr { + font-size: 0.85em +} +.glmTicketAvailable { + margin: 5px 0; + font-weight: 600 +} +.glmSectionTickets { + margin: 15px 0 +} +.glmTicketName { + font-size: 1.35em; + font-weight: 600 +} +.glmSectionSelector { + border: 1px solid #e3e3e3; + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + -ms-border-radius: 6px; + -o-border-radius: 6px; + border-radius: 6px; + cursor: pointer; + background-color: #f8f8f8; + padding: 8px 15px; + margin: 5px 0; + font-size: 1.15em; + font-weight: 600; + display: inline-block; + font-shadow: 0 1px #fff +} +.glmSectionSelector:active { + -webkit-box-shadow: inset 0 0 8px #dbdbdb; + -moz-box-shadow: inset 0 0 8px #dbdbdb; + box-shadow: inset 0 0 8px #dbdbdb +} +#GLMticketsSummary { + font-weight: 600; + font-size: 1.35em; + margin-top: 30px +} +.glmTicketsSelect { + clear: both; + margin: 1em; +} +.glmTicketsSelectPrompt { + font-size: 1em; + font-weight: 600; + line-height: 125%; + float: left; + padding-right: .2em; +} +.glmTicketsSelectValueWrapper { + float: right; + width: 150px; + text-align: right; +} +.glmTicketsSelectValue { + float: right; + width: 40%; + text-align: right; +} +#glmQuantSelector { + float: right; + text-align: right; + width: 100px; + height: 28px; +} +#GLMpolicy { + font-size: 0.85em; + font-style: italic; +/* margin-bottom: 15px; */ +} +.glmTicketPrice { + font-weight: 600; + margin: 15px 0 5px 0; + font-size: 1.25em +} +#GLMreason { + border: 1px solid #333; + padding: 1em; +} +.GLMreasonTitle { + color: red; +} +.GLMreasonList { +} +.GLMmapWindow { + width: 100%; + height: 140px; + border: 1px solid #CCC; +} +.glmDescr { + font-family: "Open Sans", sans-serif; + line-height: 1.3; +} +.glmCartFailedInput { + background: #FFaBa9; + padding: .2em; +} +.glmCartRequired { + color: red; +} +/* CHECKOUT STUFF */ +.glmCartFormLine { + clear: both; +} +.glmCartFormPrompt { + width: 30%; + float: left; + text-align: right; + font-weight: 600; + font-size: 1.1em; + padding-right: .5em; +} +.glmCartFormInput { + padding-left: 1em; + width: 70%; + float: left; + margin-bottom: .5em; +} +.glmCartFormInput span { + display: block; + width: 100%; + overflow: hidden; +} +/* Forms */ +.glmCartForm { + display: block; + width: 100%; + overflow: hidden; + padding: 10px; + background: #F5F5F5; + margin: 0 0 10px 0; + font-size: 12px; + border: 1px solid #CCC; + color: #656565; +} +.glmCartForm input[type="text"] { + display: block; + float: left; + clear: left; + width: 300px; +} +.glmCartForm select { + display: block; + float: left; + clear: left; + width: 200px; +} +.glmCartPayment { + margin: 2em 0 0 0 +} +.glmInput { + float: right; +} +/* Mobile */ +@media screen and (max-width:768px) { + .glmBlockContentRight { + float: left; + width: 100%; + margin-left: 0; + margin-right: 0; + margin-top: 10px; + margin-bottom: 10px; + } + .glmBlockContentRight img{ + max-width: 100%; + } + .glmBlockContentLeft { + display: inline; + float: left; + width: 100%; + } + .glmBlockContentLeft div { + clear: none !important; + } + /* Mobile Forms */ + +} +/* Small Mobile */ +@media screen and (max-width:599px) { + .GLMmapWindow { + height: 130px; + } + .glmCartFormPrompt { + display: block; + width: 100%; + overflow: hidden; + text-align: left; + } + .glmCartFormInput { + margin-left: 0; + padding-left: 0; + } + #GLMpageTitle { + width: 50%; + } + .glmCartHeader { + float: left; + clear: none; + width: 50%; + overflow: hidden; + + margin-bottom: 20px; + } + .glmCartHeader .glmCartText { + display: block; + width: 100%; + overflow: hidden; + border-bottom: 1px solid #CCC; + height: 30px; + } + .glmCartValues { + float: left; + clear: none; + width: 50%; + overflow: hidden; + margin-bottom: 20px; + } + .glmCartValues .glmCartText { + display: block; + width: 100%; + overflow: hidden; + border-bottom: 1px solid #CCC; + height: 30px; + } + .glmCartSubTotals .glmCartTable .glmCartHeader { + float: right; + width: 66%; + } + .glmCartSubTotals .glmCartTable .glmCartHeader .glmCartText { + width: 42%; + margin-right: 0; + margin-left: 8%; + height: auto; + text-align: right; + } + .glmCartSubTotals .glmCartTable .glmCartValues { + float: right; + clear: right; + width: 66%; + } + .glmCartSubTotals .glmCartTable .glmCartValues .glmCartText { + width: 42%; + margin-right: 0; + margin-left: 8%; + border-bottom: 0; + height: auto; + text-align: right; + } + .glmCartTable.totals { + padding-left: 0; + padding-right: 0; + } + .glmCartTable.totals .glmCartHeader { + float: right; + width: 100%; + margin-bottom: 0; + } + .glmCartTable.totals .glmCartHeader .glmCartText { + width: 28%; + margin-right: 0; + margin-left: 5%; + border-bottom: 1px solid #CCC; + height: auto; + text-align: right; + } + .glmCartTable.totals .glmCartValues { + float: right; + width: 100%; + } + .glmCartTable.totals .glmCartValues .glmCartText { + width: 28%; + margin-right: 0; + margin-left: 5%; + border-bottom: 0; + height: auto; + text-align: right; + } + .glmTicketsSelectValueWrapper { + float: left; + width: 150px; + clear: left; + margin-top: 10px; + } + .glmBlockLeft { + width: 100%; + } + .glmCartEventDescrMobile { + display: inline; + } + .glmCartEventDescr { + display: none; + } +} +/* MidSmall Mobile */ +@media screen and (max-width:449px) { + #GLMpageTitle { + font-size: 16px; + line-height: 20px; + } + .glmBlockName { + font-size: 16px; + line-height: 18px; + } + .glmCartFormInput { + width: 100%; + } + .glmCartForm input[type="text"] { + width: 100%; + } + .glmCartForm select { + width:100%; + } + .glmNavItemWide { + width: 100%; + } + .glmNavItem.add { + width: 100%; + text-align: center; + } + #GLMcheckoutBtn { + width: 100%; + text-align: center; + } + +} +/* XSmall Mobile */ +@media screen and (max-width:399px) { + .glmNavItem.chooser { + display: block; + width: 100%; + overflow: hidden; + margin-top: 10px; + text-align: center; + } +} + +#glmReloadBlocker { + display: none; + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + background-color : transparent; + text-align: center; + z-index: 1000; +} +#glmReloadBlocker div { + height: auto; + width: 300px; + padding: 10px; + background: #eee; + position: fixed; + border-radius: 10px; + border: 2px solid #666; + color: red; + font-size: 1.3em; + line-height: 150%; + + margin: -150px 0 0 -150px; + left: 50%; + top: 60%; + + box-shadow: 10px 10px 5px #888888; +} +#glmDevelopmentNotice { + padding: 5px; + border: 1px solid black; + width: auto; + clear: both; + margin-top: 4em; +} diff --git a/web/front/PointerBoat/EventManagement.js b/web/front/PointerBoat/EventManagement.js new file mode 100644 index 0000000..b837b57 --- /dev/null +++ b/web/front/PointerBoat/EventManagement.js @@ -0,0 +1,107 @@ +/* + * Event Management Front-End Area JAVAScript - Tickets interface + */ + +var f_loadAction = false; +var f_replaceContents = false; +var duration = 0; + +// jQuery Section +$(document).ready(function(){ + + /* + * Data Setup Section + */ + + var siteURL = baseSiteURL; + var appURL = baseAppURL; + + /* + * Load an action to a div with the specified id where id is also Action to be run + */ + function loadAction(id, container, params) { + + // Display loading message + $('#'+container).html('
    Loading, Please Wait...
    '); + $('#'+container).show(duration); + + // Build the URL and call it with AJAX + url = appURL + "?Action=" + id; + if (params) { + url = url + '&' + params; + } + $.post( url, + '', + function(data) { + // Populate the container with the results + $('#'+container).html(data); + restartOnTabSelect(); + } + ); + + } + f_loadAction = loadAction; + + // Replace the contents of a div + function replaceContents(data, destination) { + destination.html(data); + } + f_replaceContents = replaceContents; + + /* + * General Slider Operations + */ + + // Slider area actions + $('.glmSectionSelector').on('click', null, function() { + + // Get the ID of the area to slide from the emSliderId="" parameter in the div tag. + var sliderId = $(this).attr('emSliderId'); + + // If the slider is currently open - close it, otherwise open it. + if ($('#'+sliderId).is(':visible')) { + $('#'+sliderId).hide(duration); + } else { + $('#'+sliderId).show(duration); + } + }); + // Startup by closing all areas that are supposed to be closed by default + $('.glmSectionTickets').hide(duration); + + /* + * Check for user timeout + */ + var inactivityTime = 1800000; // Number of milliseconds to user timeout + + // If theres no activity for 5 seconds do something + var activityTimeout = setTimeout(inActive, inactivityTime); + + function resetActive(){ + $(document.body).attr('class', 'active'); + clearTimeout(activityTimeout); + activityTimeout = setTimeout(inActive, inactivityTime); + } + + // No activity do something. + function inActive(){ + alert("Your user session has timed out. Click OK to continue."); + window.location.href = siteURL; + } + + // Check for mousemove, could add other events here such as checking for key presses ect. + $(document).bind('mousemove', function(){resetActive()}); + +// var use_any_time = "Use any time of day,"; +// var glmDescr = $('.glmDescr').children('p'); +// var selectBtn = $('#GLMselectButton'); +// var shopBtn = $('.glmNavItem:nth-child(2)'); +// +// shopBtn.html("Purchase Tickets"); +// selectBtn.html("Add to Cart"); +// +// $.each(glmDescr, function(){ +// var text = $(this).text().replace(use_any_time, ''); +// $(this).text(text); +// }); + +}); diff --git a/web/front/PointerBoat/assets/paypal_but6.gif b/web/front/PointerBoat/assets/paypal_but6.gif new file mode 100644 index 0000000000000000000000000000000000000000..5da5a520da3967c966b4aa4bd9f0fcdeba928312 GIT binary patch literal 4774 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 literal 0 HcmV?d00001 diff --git a/web/front/SaultSteMarie/EventManagement.css b/web/front/SaultSteMarie/EventManagement.css new file mode 100644 index 0000000..9eef48a --- /dev/null +++ b/web/front/SaultSteMarie/EventManagement.css @@ -0,0 +1,916 @@ +/* Additional styles for Event Management front-end */ +#GLMHeader { + display: block; + width: 100%; + overflow: hidden; + margin: 0 0 5px 0; + padding: 0; + border-bottom: 1px solid #CCC; +} +#GLMpageTitle { + color: #040267; + float: left; + font-family: "Lora","Times New Roman",Times,serif; + font-size: 20px; + line-height: 24px; + font-weight: normal; + margin: 0 0 10px; + padding: 0 0 5px 0; + width: 70%; + /*background: rgba(0,0,0,0.1);*/ +} +#GLMpageIntro { + margin: 1em 0 1em 0; +} +#GLMpageIntro p{ + font-size: 1rem; + font-family: "Open Sans", sans-serif; +} +.glmBold { + font-weight: 600; +} +.glmBlock { + display: block; + width: 100%; + overflow: hidden; + margin: 0 0 10px 0; + padding: 5px; + border: 1px solid #CFCFCF; + background: rgba(0,0,0,0.05); +} +.glmBlockList { + margin-top: 10px; + clear: both; +} +.glmBlockHeader, .glmBlockHeadder { + display: block; + width: 100%; + overflow: hidden; + margin: 0 0 5px 0; +} +.glmBlockName { + display: inline; + font-size: 24px; + line-height: 22px; + color: #043867; +/* font-family: "Lora","Times New Roman",Times,serif;*/ + font-family: "Open Sans", sans-serif; +} +.glmBlockName a{ + font-size: 18px; + color: #043867; +} +.glmBlockRightCol { + float: right; +} +.glmBlockContent { + margin: 0 0 0em 0; + clear: both; + width: 100%; + font-family: "Open Sans", sans-serif; +} +.glmTicketQuant{ + width: 45px; + height: 30px; +} +.glmTicketQuant option{ + font-size: 15px; +} +@media (min-width: 768px){ + .glmBlockContentRight img{ + float: right; + } + .glmBlock:not(:first-child) .glmBlockContentRight .glmBlockContent{ + clear: none; + /* width: 10%;*/ + /* float: left;*/ + } + .glmBlock:not(:first-child) .glmBlockContentRight .glmBlockContent .glmTicketsSelectValue{ + width: 10%; + margin-right: 10px; + } + .glmBlock:not(:first-child) .glmBlockContentRight .glmTicketsSelectPrompt{ + /* float: left;*/ + padding: 0; + margin-right: 3px; + } + .glmBlock:not(:first-child) .glmBlockContentRight .glmTicketsSelectValue{ + width: 20%; + float: left; + } + .glmBlock:not(:first-child) .glmBlockContentRight .glmInput{ + /* float: left;*/ + } + .glmBlock:not(:first-child) .glmBlockContentLeft { + display: block; + float: left; +/* width:55%;*/ + width: 33%; + overflow: hidden; + } + .glmBlock:not(:first-child) .glmBlockContentRight{ + display: block; + float: right; +/* width: 40%;*/ + width: 64%; + overflow: hidden; + margin-bottom: 10px; + margin-left: 1%; + min-width: 120px; + } + .glmBlock .glmBlockContentLeft.startContent, .glmCartBlock .glmBlockContentLeft.cartContent{ + display: block; + float: left; +/* width:55%;*/ + width: 50%; + overflow: hidden; + } + .glmBlock .glmBlockContentRight.startImage, .glmCartBlock .glmBlockContentRight.cartImage{ + display: block; + float: right; +/* width: 40%;*/ + width: 45%; + overflow: hidden; + margin-bottom: 10px; + margin-left: 5%; + min-width: 120px; + } + .glmBlock:not(:first-child) .glmBlockContentRight .glmBlockContent:nth-child(2) .glmTicketsSelectValue{ + + width: 18% !important; + } +} +@media (min-width: 992px){ + div[class^="GLMeventDateSelect"]{ + + } + .glmBlock:not(:first-child) .glmBlockContentRight .glmBlockContent .glmTicketsSelectValue{ + width: 8%; + margin-right: 10px; + } + + .glmBlock:not(:first-child) .glmBlockContentRight .glmBlockContent:nth-child(2) .glmTicketsSelectValue{ + + width: 14% !important; + } + + .glmBlock:not(:first-child) .glmBlockContentLeft:not(.startContent) { + display: block; + float: left; +/* width:55%;*/ + width: 35%; + overflow: hidden; + } + .glmBlock:not(:first-child) .glmBlockContentRight:not(.startImage) { + display: block; + float: right; +/* width: 40%;*/ + width: 60%; + overflow: hidden; + margin-bottom: 10px; + margin-left: 5%; + min-width: 120px; + } +} +@media (min-width: 1200px){ + .glmBlock:not(:first-child) .glmBlockContentRight .glmBlockContent:nth-child(2) .glmTicketsSelectValue{ + + width: 12% !important; + } +} +.glmBlockContent p{ + font-family: "Open Sans", sans-serif; +} +.glmBlockContentLeft { + display: block; + float: left; + width:70%; + overflow: hidden; +} +.glmBlockContentRight { + display: block; + float: right; + width: 20%; + overflow: hidden; + margin-bottom: 10px; + margin-left: 5%; + min-width: 120px; +} +.glmBlockContentIndent { + display: block; + margin-left: 3em; +} +.glmSection { +} +.glmSection .glmSectionName { +} +.glmSection .glmSectionBold { + font-size: 1.1em; + font-weight: 600; +} +.glmSectionName { + font-size: 1.1em; + font-weight: 600; + margin: 1em 0 0 0; +} +#GLMeventDescr, #GLMvenueDescr, .glmCartVenueDescr, .glmCartEventDescr { + font-size: 0.8em; + margin: 0 0 2.2em 0 +} +.glmCartEventDescrMobile { + display: none; +} +.glmCartVenueDescr, .glmCartEventDescr:not(.promoDescr) { + margin: 0 0 15px 0; +/* visibility: hidden;*/ + display: none; +} + +.glmCartEvents { +} +.glmCartEvent { +} +.glmCartSelect { + width: 4em; +} +a.glmNavItem{ + margin-bottom: 10px; +} +.glmCartEventTitle { + font-size: 20px; + line-height: 22px; +/* font-family: "Lora","Times New Roman",Times,serif;*/ + font-family: "Open Sans", sans-serif; + color: #043867; + margin-bottom: 5px; +} +.glmCartEventInfo { + margin-top: .5em; + clear: both; +} +.glmCartEventInfoLeft { + float: left; + padding-right: 100px; +} +.glmCartHeader { + font-size: 1.1em; + font-weight: 600; + clear: both; +} +.glmCartHeader .glmCartText { + font-weight: bold; + border-bottom: 1px solid #CCC; +} +.glmCartValues { + clear: both; +} +.glmCartTable { + display: block; + width: 100%; + overflow: hidden; + margin: 10px 0 0 0; + padding: 10px; + border: 1px solid #CFCFCF; + background: rgba(0,0,0,0.05); +} +.glmCartTable.totals { + display: block; + width: 100%; + overflow: hidden; + margin: 10px 0 0 0; + padding: 10px 0 10px 20px; + border: 0; + background: none; +} +.glmCartTable.sub { + padding-top: 0; + padding-bottom: 0; +} +.glmCartNumb { + width: 20%; + float: left; + align: right; +} +.glmCartText { + display: block; + width: 17%; + margin-right: 3%; + float: left; + padding: 2px 0 0 0; +} + +.glmGrandTotals { + float: right; + color: #900; + font-weight: 600; + font-size: 1.1em; +} + +.glmCartTable.totals .glmCartText { + display: block; + width: 30%; + margin-right: 3%; + float: right; + padding: 2px 0 0 0; +} +.glmCartTable.totals .glmCartHeader .glmCartText { + color: #900; +} +.glmCartTable.totals .glmCartText.grand { + margin-right: 0; + padding-right: 0; +} +.glmCartTotal { + width: 30%; + float: left; +} +.glmCartWide { + width: 40%; + float: left; +} +.glmCartBlock.totals .glmCartWide { + width: 100%; + padding-top: 10px; +} +.glmCartTotal { + width:20%; + font-weight: 600; + font-size: 1.1em; +} +.glmCartSubTotals { + margin-top: 10px; + clear: both; +} +.glmCartSubTotals .glmCartTable { + background: none; + border: 0; +} +.glmCartSubTotals .glmCartTable .glmCartHeader { + float: right; + width: 40%; +} +.glmCartSubTotals .glmCartTable .glmCartHeader .glmCartText { + width: 42%; + margin-right: 8%; + height: auto; + text-align: left; +} +.glmCartSubTotals .glmCartTable .glmCartValues { + float: right; + clear: right; + width: 40%; +} +.glmCartSubTotals .glmCartTable .glmCartValues .glmCartText { + width: 42%; + margin-right: 8%; + border-bottom: 0; + height: auto; + text-align: left; +} +.glmCartTotals { + margin-top: 10px; +} +.glmCartBlock { + display: block; + width: 100%; + overflow: hidden; + margin: 0 0 1em 0; + padding: 10px; + border: 1px solid #CFCFCF; + background: rgba(0,0,0,0.05); +} +.glmCartBlock.totals { + display: block; + width: 100%; + overflow: hidden; + margin: 0 0 10px 0; + padding: 0; + border: 0; + background: none; +} +.glmCartBlockTitle { + font-size: 22px; + line-height: 28px; + font-family: "Lora","Times New Roman",Times,serif; + margin: 0 0 0 0; +} +.glmCartBlockSmallTitle { + font-size: 16px; + line-height: 22px; + font-family: "Lora","Times New Roman",Times,serif; +} +.glmCartBlock input[type="textarea"] { + display: block; + float: left; + clear: left; + width: 100%; +} +.glmEventDateInput { + width: 80px; +} +.glmCartBlock.totals .glmCartBlockTitle { + border-bottom: 1px solid #CCC; +} +.glmCartBlockSubTitle { + margin-top: 1em; + font-size: 1.1em; + font-weight: 600; + margin-bottom: .5em; +} +.glmCartBlockSubTitleValue { + +} +.glmCartBlockText { +} +.glmCartBlockDates { + clear: both; +} +.glmCartBlockDate { + margin-top: .5em; +} +.glmSpecialRequests { + margin: 0 0 3em 0; +} +#GLMcontent { + padding: 0; + margin: 0 auto +} +#GLMcontent>* { +/* padding: 0 15px; */ +} +#GLMevent, #GLMtickets, #GLMvenue { + /* max-width: 500px; */ + margin: 0 auto 1em auto +} +#GLMnavigation:after { + content: ""; + display: table; + clear: both +} +.glmNavItemInactive { + float: right; + padding: 3px 10px; + width: auto; + display: block; + overflow: hidden; + background: #ddd; + border: 1px solid #aaa; + border-radius: 8px; + cursor: pointer; + text-transform: uppercase; + text-align: center; +} +.glmNavItem { + float: right; + padding: 3px 10px; + width: auto; + display: block; + overflow: hidden; + background: #cc6535; + border: 1px solid #cc6535; + border-radius: 8px; + cursor: pointer; + text-transform: uppercase; +} +a.glmNavItem { + color: #FFF; + font-weight: bold; + text-shadow: none; +} +div.glmNavItem { + color: #FFF; + font-weight: bold; + text-shadow: none; +} +.glmNavItem.cart { + background: #043867; + border: 1px solid #043867; +} +#category h1{ + font-size: 24px; + color: #3a8bb6; + font-family: "Open Sans", sans-serif; + +} +.glmNavItemWide { + display: block; + width: 400px; + overflow: hidden; + margin: 12px 0 0 0; + padding: 8px 0; + background: #900; + border: 1px solid #900; + border-radius: 8px; + color: #FFF; + text-align: center; + vertical-align: middle; + font-size: 18px; + font-weight: bold; + font-family: "Times New Roman", Times, serif; + cursor: pointer; +} +.glmSelectItem { + padding: 5px; + margin: 0; + width: 150px; + border-left: 1px solid #e3e3e3; + cursor: pointer; + border: 1px solid #e3e3e3; + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + -ms-border-radius: 6px; + -o-border-radius: 6px; + border-radius: 6px; + text-align: center; + font-weight: 600; + font-shadow: 0 1px #fff; + font-size: 0.85em; + background: #fcfcfc; + -webkit-background-clip: padding; + -moz-background-clip: padding; + background-clip: padding-box; +} +#GLMcheckout .glmNavItem, #GLMticketCart .glmNavItem { + width: 33.3333% +} +#GLMeventDates, #GLMvenueLocation, #GLMvenueDetail, #GLMvenueSectionMap { + margin: 0 0 15px 0 +} +.glmPrompt { + font-weight: 600; + font-size: 1.1em +} +.glmTicketDescr { + font-size: 0.85em +} +.glmTicketAvailable { + margin: 5px 0; + font-weight: 600 +} +.glmSectionTickets { + margin: 15px 0 +} +.glmTicketName { + font-size: 1.35em; + font-weight: 600 +} +.glmSectionSelector { + border: 1px solid #e3e3e3; + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + -ms-border-radius: 6px; + -o-border-radius: 6px; + border-radius: 6px; + cursor: pointer; + background-color: #f8f8f8; + padding: 8px 15px; + margin: 5px 0; + font-size: 1.15em; + font-weight: 600; + display: inline-block; + font-shadow: 0 1px #fff +} +.glmSectionSelector:active { + -webkit-box-shadow: inset 0 0 8px #dbdbdb; + -moz-box-shadow: inset 0 0 8px #dbdbdb; + box-shadow: inset 0 0 8px #dbdbdb +} +#GLMticketsSummary { + font-weight: 600; + font-size: 1.35em; + margin-top: 30px +} +.glmTicketsSelect { + clear: both; + margin: 1em; +} +.glmTicketsSelectPrompt { + font-size: 1em; + font-weight: 600; + line-height: 125%; + float: left; + padding-right: .2em; +} +.glmTicketsSelectValueWrapper { + float: right; + width: 150px; + text-align: right; +} +.glmTicketsSelectValue { + float: right; + width: 40%; + text-align: right; +} +#glmQuantSelector { + float: right; + text-align: right; + width: 100px; + height: 28px; +} +#GLMpolicy { + font-size: 0.85em; + font-style: italic; +/* margin-bottom: 15px; */ +} +.glmTicketPrice { + font-weight: 600; + margin: 15px 0 5px 0; + font-size: 1.25em +} +#GLMreason { + border: 1px solid #333; + padding: 1em; +} +.GLMreasonTitle { + color: red; +} +.GLMreasonList { +} +.GLMmapWindow { + width: 100%; + height: 140px; + border: 1px solid #CCC; +} +.glmDescr { + font-family: "Open Sans", sans-serif; + line-height: 1.3; +} +.glmCartFailedInput { + background: #FFaBa9; + padding: .2em; +} +.glmCartRequired { + color: red; +} +/* CHECKOUT STUFF */ +.glmCartFormLine { + clear: both; +} +.glmCartFormPrompt { + width: 30%; + float: left; + text-align: right; + font-weight: 600; + font-size: 1.1em; + padding-right: .5em; +} +.glmCartFormInput { + padding-left: 1em; + width: 70%; + float: left; + margin-bottom: .5em; +} +.glmCartFormInput span { + display: block; + width: 100%; + overflow: hidden; +} +/* Forms */ +.glmCartForm { + display: block; + width: 100%; + overflow: hidden; + padding: 10px; + background: #F5F5F5; + margin: 0 0 10px 0; + font-size: 12px; + border: 1px solid #CCC; + color: #656565; +} +.glmCartForm input[type="text"] { + display: block; + float: left; + clear: left; + width: 300px; +} +.glmCartForm select { + display: block; + float: left; + clear: left; + width: 200px; +} +.glmCartPayment { + margin: 2em 0 0 0 +} +.glmInput { + float: right; +} +/* Mobile */ +@media screen and (max-width:768px) { + .glmBlockContentRight { + float: left; + width: 100%; + margin-left: 0; + margin-right: 0; + margin-top: 10px; + margin-bottom: 10px; + } + .glmBlockContentRight img{ + max-width: 100%; + } + .glmBlockContentLeft { + display: inline; + float: left; + width: 100%; + } + .glmBlockContentLeft div { + clear: none !important; + } + /* Mobile Forms */ + +} +/* Small Mobile */ +@media screen and (max-width:599px) { + .GLMmapWindow { + height: 130px; + } + .glmCartFormPrompt { + display: block; + width: 100%; + overflow: hidden; + text-align: left; + } + .glmCartFormInput { + margin-left: 0; + padding-left: 0; + } + #GLMpageTitle { + width: 50%; + } + .glmCartHeader { + float: left; + clear: none; + width: 50%; + overflow: hidden; + + margin-bottom: 20px; + } + .glmCartHeader .glmCartText { + display: block; + width: 100%; + overflow: hidden; + border-bottom: 1px solid #CCC; + height: 30px; + } + .glmCartValues { + float: left; + clear: none; + width: 50%; + overflow: hidden; + margin-bottom: 20px; + } + .glmCartValues .glmCartText { + display: block; + width: 100%; + overflow: hidden; + border-bottom: 1px solid #CCC; + height: 30px; + } + .glmCartSubTotals .glmCartTable .glmCartHeader { + float: right; + width: 66%; + } + .glmCartSubTotals .glmCartTable .glmCartHeader .glmCartText { + width: 42%; + margin-right: 0; + margin-left: 8%; + height: auto; + text-align: right; + } + .glmCartSubTotals .glmCartTable .glmCartValues { + float: right; + clear: right; + width: 66%; + } + .glmCartSubTotals .glmCartTable .glmCartValues .glmCartText { + width: 42%; + margin-right: 0; + margin-left: 8%; + border-bottom: 0; + height: auto; + text-align: right; + } + .glmCartTable.totals { + padding-left: 0; + padding-right: 0; + } + .glmCartTable.totals .glmCartHeader { + float: right; + width: 100%; + margin-bottom: 0; + } + .glmCartTable.totals .glmCartHeader .glmCartText { + width: 28%; + margin-right: 0; + margin-left: 5%; + border-bottom: 1px solid #CCC; + height: auto; + text-align: right; + } + .glmCartTable.totals .glmCartValues { + float: right; + width: 100%; + } + .glmCartTable.totals .glmCartValues .glmCartText { + width: 28%; + margin-right: 0; + margin-left: 5%; + border-bottom: 0; + height: auto; + text-align: right; + } + .glmTicketsSelectValueWrapper { + float: left; + width: 150px; + clear: left; + margin-top: 10px; + } + .glmBlockLeft { + width: 100%; + } + .glmCartEventDescrMobile { + display: inline; + } + .glmCartEventDescr { + display: none; + } +} +/* MidSmall Mobile */ +@media screen and (max-width:449px) { + #GLMpageTitle { + font-size: 16px; + line-height: 20px; + } + .glmBlockName { + font-size: 16px; + line-height: 18px; + } + .glmCartFormInput { + width: 100%; + } + .glmCartForm input[type="text"] { + width: 100%; + } + .glmCartForm select { + width:100%; + } + .glmNavItemWide { + width: 100%; + } + .glmNavItem.add { + width: 100%; + text-align: center; + } + #GLMcheckoutBtn { + width: 100%; + text-align: center; + } + +} +/* XSmall Mobile */ +@media screen and (max-width:399px) { + .glmNavItem.chooser { + display: block; + width: 100%; + overflow: hidden; + margin-top: 10px; + text-align: center; + } +} + +#glmReloadBlocker { + display: none; + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + background-color : transparent; + text-align: center; + z-index: 1000; +} +#glmReloadBlocker div { + height: auto; + width: 300px; + padding: 10px; + background: #eee; + position: fixed; + border-radius: 10px; + border: 2px solid #666; + color: red; + font-size: 1.3em; + line-height: 150%; + + margin: -150px 0 0 -150px; + left: 50%; + top: 60%; + + box-shadow: 10px 10px 5px #888888; +} +#glmDevelopmentNotice { + padding: 5px; + border: 1px solid black; + width: auto; + clear: both; + margin-top: 4em; +} diff --git a/web/front/SaultSteMarie/EventManagement.js b/web/front/SaultSteMarie/EventManagement.js new file mode 100644 index 0000000..b837b57 --- /dev/null +++ b/web/front/SaultSteMarie/EventManagement.js @@ -0,0 +1,107 @@ +/* + * Event Management Front-End Area JAVAScript - Tickets interface + */ + +var f_loadAction = false; +var f_replaceContents = false; +var duration = 0; + +// jQuery Section +$(document).ready(function(){ + + /* + * Data Setup Section + */ + + var siteURL = baseSiteURL; + var appURL = baseAppURL; + + /* + * Load an action to a div with the specified id where id is also Action to be run + */ + function loadAction(id, container, params) { + + // Display loading message + $('#'+container).html('
    Loading, Please Wait...
    '); + $('#'+container).show(duration); + + // Build the URL and call it with AJAX + url = appURL + "?Action=" + id; + if (params) { + url = url + '&' + params; + } + $.post( url, + '', + function(data) { + // Populate the container with the results + $('#'+container).html(data); + restartOnTabSelect(); + } + ); + + } + f_loadAction = loadAction; + + // Replace the contents of a div + function replaceContents(data, destination) { + destination.html(data); + } + f_replaceContents = replaceContents; + + /* + * General Slider Operations + */ + + // Slider area actions + $('.glmSectionSelector').on('click', null, function() { + + // Get the ID of the area to slide from the emSliderId="" parameter in the div tag. + var sliderId = $(this).attr('emSliderId'); + + // If the slider is currently open - close it, otherwise open it. + if ($('#'+sliderId).is(':visible')) { + $('#'+sliderId).hide(duration); + } else { + $('#'+sliderId).show(duration); + } + }); + // Startup by closing all areas that are supposed to be closed by default + $('.glmSectionTickets').hide(duration); + + /* + * Check for user timeout + */ + var inactivityTime = 1800000; // Number of milliseconds to user timeout + + // If theres no activity for 5 seconds do something + var activityTimeout = setTimeout(inActive, inactivityTime); + + function resetActive(){ + $(document.body).attr('class', 'active'); + clearTimeout(activityTimeout); + activityTimeout = setTimeout(inActive, inactivityTime); + } + + // No activity do something. + function inActive(){ + alert("Your user session has timed out. Click OK to continue."); + window.location.href = siteURL; + } + + // Check for mousemove, could add other events here such as checking for key presses ect. + $(document).bind('mousemove', function(){resetActive()}); + +// var use_any_time = "Use any time of day,"; +// var glmDescr = $('.glmDescr').children('p'); +// var selectBtn = $('#GLMselectButton'); +// var shopBtn = $('.glmNavItem:nth-child(2)'); +// +// shopBtn.html("Purchase Tickets"); +// selectBtn.html("Add to Cart"); +// +// $.each(glmDescr, function(){ +// var text = $(this).text().replace(use_any_time, ''); +// $(this).text(text); +// }); + +}); diff --git a/web/front/SaultSteMarie/assets/paypal_but6.gif b/web/front/SaultSteMarie/assets/paypal_but6.gif new file mode 100644 index 0000000000000000000000000000000000000000..5da5a520da3967c966b4aa4bd9f0fcdeba928312 GIT binary patch literal 4774 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 literal 0 HcmV?d00001 diff --git a/web/front/TicketsFoundation/EventManagement.css b/web/front/TicketsFoundation/EventManagement.css new file mode 100644 index 0000000..5a205d5 --- /dev/null +++ b/web/front/TicketsFoundation/EventManagement.css @@ -0,0 +1,772 @@ +/* Additional styles for Event Management front-end */ +#GLMHeader { + display: block; + width: 100%; + overflow: hidden; + margin: 0 0 5px 0; + padding: 0; + border-bottom: 1px solid #CCC; +} +#GLMpageTitle { + color: #040267; + float: left; + font-family: "Lora","Times New Roman",Times,serif; + font-size: 20px; + line-height: 24px; + font-weight: normal; + margin: 0 0 10px; + padding: 0 0 5px 0; + width: 70%; + /*background: rgba(0,0,0,0.1);*/ +} +#GLMpageIntro { + margin: 1em 0 1em 0; +} +.glmBold { + font-weight: 600; +} +.glmBlock { + display: block; + width: 100%; + overflow: hidden; + margin: 0 0 10px 0; + padding: 5px; + border: 1px solid #CFCFCF; + background: rgba(0,0,0,0.05); +} +.glmBlockList { + margin-top: 10px; + clear: both; +} +.glmBlockHeader, .glmBlockHeadder { + display: block; + width: 100%; + overflow: hidden; + margin: 0 0 5px 0; +} +.glmBlockName { + display: inline; + font-size: 18px; + line-height: 22px; + font-family: "Lora","Times New Roman",Times,serif; +} +.glmBlockRightCol { + float: right; +} +.glmBlockContent { + margin: 0 0 0em 0; + clear: both; + width: 100%; +} +.glmBlockContentLeft { + display: block; + float: left; + overflow: hidden; +} +.glmBlockContentRight { + display: block; + float: right; + width: 40%; + overflow: hidden; + margin-bottom: 10px; + margin-left: 5%; + min-width: 120px; +} +.glmBlockContentIndent { + display: block; + margin-left: 3em; +} +.glmSection { +} +.glmSection .glmSectionName { +} +.glmSection .glmSectionBold { + font-size: 1.1em; + font-weight: 600; +} +.glmSectionName { + font-size: 1.1em; + font-weight: 600; + margin: 1em 0 0 0; +} +#GLMeventDescr, #GLMvenueDescr, .glmCartVenueDescr, .glmCartEventDescr { + font-size: 0.8em; + margin: 0 0 2.2em 0 +} +.glmCartEventDescrMobile { + display: none; +} +.glmCartVenueDescr, .glmCartEventDescr { + margin: 0 0 15px 0 +} +.glmCartEvents { +} +.glmCartEvent { +} +.glmCartSelect { + width: 4em; +} +.glmCartEventTitle { + font-size: 18px; + line-height: 22px; + font-family: "Lora","Times New Roman",Times,serif; +} +.glmCartEventInfo { + margin-top: .5em; + clear: both; +} +.glmCartEventInfoLeft { + float: left; + padding-right: 100px; +} +.glmCartHeader { + font-size: 1.1em; + font-weight: 600; + clear: both; +} +.glmCartHeader .glmCartText { + font-weight: bold; + border-bottom: 1px solid #CCC; +} +.glmCartValues { + clear: both; +} +.glmCartTable { + display: block; + width: 100%; + overflow: hidden; + margin: 10px 0 0 0; + padding: 10px; + border: 1px solid #CFCFCF; + background: rgba(0,0,0,0.05); +} +.glmCartTable.totals { + display: block; + width: 100%; + overflow: hidden; + margin: 10px 0 0 0; + padding: 10px 0 10px 20px; + border: 0; + background: none; +} +.glmCartTable.sub { + padding-top: 0; + padding-bottom: 0; +} +.glmCartNumb { + width: 20%; + float: left; + align: right; +} +.glmCartText { + display: block; + width: 17%; + margin-right: 3%; + float: left; + padding: 2px 0 0 0; +} + +.glmGrandTotals { + float: right; + color: #900; + font-weight: 600; + font-size: 1.1em; +} + +.glmCartTable.totals .glmCartText { + display: block; + width: 30%; + margin-right: 3%; + float: right; + padding: 2px 0 0 0; +} +.glmCartTable.totals .glmCartHeader .glmCartText { + color: #900; +} +.glmCartTable.totals .glmCartText.grand { + margin-right: 0; + padding-right: 0; +} +.glmCartTotal { + width: 30%; + float: left; +} +.glmCartWide { + width: 40%; + float: left; +} +.glmCartBlock.totals .glmCartWide { + width: 100%; + padding-top: 10px; +} +.glmCartTotal { + width:20%; + font-weight: 600; + font-size: 1.1em; +} +.glmCartSubTotals { + margin-top: 10px; + clear: both; +} +.glmCartSubTotals .glmCartTable { + background: none; + border: 0; +} +.glmCartSubTotals .glmCartTable .glmCartHeader { + float: right; + width: 40%; +} +.glmCartSubTotals .glmCartTable .glmCartHeader .glmCartText { + width: 42%; + margin-right: 8%; + height: auto; + text-align: left; +} +.glmCartSubTotals .glmCartTable .glmCartValues { + float: right; + clear: right; + width: 40%; +} +.glmCartSubTotals .glmCartTable .glmCartValues .glmCartText { + width: 42%; + margin-right: 8%; + border-bottom: 0; + height: auto; + text-align: left; +} +.glmCartTotals { + margin-top: 10px; +} +.glmCartBlock { + display: block; + width: 100%; + overflow: hidden; + margin: 0 0 1em 0; + padding: 10px; + border: 1px solid #CFCFCF; + background: rgba(0,0,0,0.05); +} +.glmCartBlock.totals { + display: block; + width: 100%; + overflow: hidden; + margin: 0 0 10px 0; + padding: 0; + border: 0; + background: none; +} +.glmCartBlockTitle { + font-size: 22px; + line-height: 28px; + font-family: "Lora","Times New Roman",Times,serif; + margin: 0 0 0 0; +} +.glmCartBlockSmallTitle { + font-size: 16px; + line-height: 22px; + font-family: "Lora","Times New Roman",Times,serif; +} +.glmCartBlock input[type="textarea"] { + display: block; + float: left; + clear: left; + width: 100%; +} +.glmEventDateInput { + width: 80px; +} +.glmCartBlock.totals .glmCartBlockTitle { + border-bottom: 1px solid #CCC; +} +.glmCartBlockSubTitle { + margin-top: 1em; + font-size: 1.1em; + font-weight: 600; + margin-bottom: .5em; +} +.glmCartBlockSubTitleValue { + +} +.glmCartBlockText { +} +.glmCartBlockDates { + clear: both; +} +.glmCartBlockDate { + margin-top: .5em; +} +.glmSpecialRequests { + margin: 0 0 3em 0; +} +#GLMcontent { + padding: 0; + margin: 0 auto +} +#GLMcontent>* { +/* padding: 0 15px; */ +} +#GLMevent, #GLMtickets, #GLMvenue { + /* max-width: 500px; */ + margin: 0 auto 1em auto +} +#GLMnavigation:after { + content: ""; + display: table; + clear: both +} +.glmNavItemInactive { + float: right; + padding: 3px 10px; + width: auto; + display: block; + overflow: hidden; + background: #ddd; + border: 1px solid #aaa; + border-radius: 8px; + cursor: pointer; + text-transform: uppercase; + text-align: center; +} +.glmNavItem { + float: right; + padding: 3px 10px; + width: auto; + display: block; + overflow: hidden; + background: #900; + border: 1px solid #900; + border-radius: 8px; + cursor: pointer; + text-transform: uppercase; +} +a.glmNavItem { + color: #FFF; + font-weight: bold; + text-shadow: none; +} +div.glmNavItem { + color: #FFF; + font-weight: bold; + text-shadow: none; +} +.glmNavItem.cart { + background: #040267; + border: 1px solid #040267; +} +.glmNavItemWide { + display: block; + width: 400px; + overflow: hidden; + margin: 12px 0 0 0; + padding: 8px 0; + background: #900; + border: 1px solid #900; + border-radius: 8px; + color: #FFF; + text-align: center; + vertical-align: middle; + font-size: 18px; + font-weight: bold; + font-family: "Times New Roman", Times, serif; + cursor: pointer; +} +.glmSelectItem { + padding: 5px; + margin: 0; + width: 150px; + border-left: 1px solid #e3e3e3; + cursor: pointer; + border: 1px solid #e3e3e3; + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + -ms-border-radius: 6px; + -o-border-radius: 6px; + border-radius: 6px; + text-align: center; + font-weight: 600; + font-shadow: 0 1px #fff; + font-size: 0.85em; + background: #fcfcfc; + -webkit-background-clip: padding; + -moz-background-clip: padding; + background-clip: padding-box; +} +#GLMcheckout .glmNavItem, #GLMticketCart .glmNavItem { + width: 33.3333% +} +#GLMeventDates, #GLMvenueLocation, #GLMvenueDetail, #GLMvenueSectionMap { + margin: 0 0 15px 0 +} +.glmPrompt { + font-weight: 600; + font-size: 1.1em +} +.glmTicketDescr { + font-size: 0.85em +} +.glmTicketAvailable { + margin: 5px 0; + font-weight: 600 +} +.glmSectionTickets { + margin: 15px 0 +} +.glmTicketName { + font-size: 1.35em; + font-weight: 600 +} +.glmSectionSelector { + border: 1px solid #e3e3e3; + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + -ms-border-radius: 6px; + -o-border-radius: 6px; + border-radius: 6px; + cursor: pointer; + background-color: #f8f8f8; + padding: 8px 15px; + margin: 5px 0; + font-size: 1.15em; + font-weight: 600; + display: inline-block; + font-shadow: 0 1px #fff +} +.glmSectionSelector:active { + -webkit-box-shadow: inset 0 0 8px #dbdbdb; + -moz-box-shadow: inset 0 0 8px #dbdbdb; + box-shadow: inset 0 0 8px #dbdbdb +} +#GLMticketsSummary { + font-weight: 600; + font-size: 1.35em; + margin-top: 30px +} +.glmTicketsSelect { + clear: both; + margin: 1em; +} +.glmTicketsSelectPrompt { + font-size: 1em; + font-weight: 600; + line-height: 125%; + float: left; + padding-right: .2em; +} +.glmTicketsSelectValueWrapper { + float: right; + width: 150px; + text-align: right; +} +.glmTicketsSelectValue { + float: right; + width: 40%; + text-align: right; +} +#glmQuantSelector { + float: right; + text-align: right; + width: 100px; + height: 28px; +} +#GLMpolicy { + font-size: 0.85em; + font-style: italic; +/* margin-bottom: 15px; */ +} +.glmTicketPrice { + font-weight: 600; + margin: 15px 0 5px 0; + font-size: 1.25em +} +#GLMreason { + border: 1px solid #333; + padding: 1em; +} +.GLMreasonTitle { + color: red; +} +.GLMreasonList { +} +.GLMmapWindow { + width: 100%; + height: 140px; + border: 1px solid #CCC; +} +.glmDescr { +} +.glmCartFailedInput { + background: #FFaBa9; + padding: .2em; +} +.glmCartRequired { + color: red; +} +/* CHECKOUT STUFF */ +.glmCartFormLine { + clear: both; +} +.glmCartFormPrompt { + width: 30%; + float: left; + text-align: right; + font-weight: 600; + font-size: 1.1em; + padding-right: .5em; +} +.glmCartFormInput { + padding-left: 1em; + width: 70%; + float: left; + margin-bottom: .5em; +} +.glmCartFormInput span { + display: block; + width: 100%; + overflow: hidden; +} +/* Forms */ +.glmCartForm { + display: block; + width: 100%; + overflow: hidden; + padding: 10px; + background: #F5F5F5; + margin: 0 0 10px 0; + font-size: 12px; + border: 1px solid #CCC; + color: #656565; +} +.glmCartForm input[type="text"] { + display: block; + float: left; + clear: left; + width: 300px; +} +.glmCartForm select { + display: block; + float: left; + clear: left; + width: 200px; +} +.glmCartPayment { + margin: 2em 0 0 0 +} +.glmInput { + float: right; +} +/* Mobile */ +@media screen and (max-width:768px) { + .glmBlockContentRight { + float: left; + width: 100%; + margin-left: 0; + margin-right: 0; + margin-top: 10px; + margin-bottom: 10px; + } + .glmBlockContentLeft { + display: inline; + float: left; + width: 100%; + } + .glmBlockContentLeft div { + clear: none !important; + } + /* Mobile Forms */ + +} +/* Small Mobile */ +@media screen and (max-width:599px) { + .GLMmapWindow { + height: 130px; + } + .glmCartFormPrompt { + display: block; + width: 100%; + overflow: hidden; + text-align: left; + } + .glmCartFormInput { + margin-left: 0; + padding-left: 0; + } + #GLMpageTitle { + width: 50%; + } + .glmCartHeader { + float: left; + clear: none; + width: 50%; + overflow: hidden; + + margin-bottom: 20px; + } + .glmCartHeader .glmCartText { + display: block; + width: 100%; + overflow: hidden; + border-bottom: 1px solid #CCC; + height: 30px; + } + .glmCartValues { + float: left; + clear: none; + width: 50%; + overflow: hidden; + margin-bottom: 20px; + } + .glmCartValues .glmCartText { + display: block; + width: 100%; + overflow: hidden; + border-bottom: 1px solid #CCC; + height: 30px; + } + .glmCartSubTotals .glmCartTable .glmCartHeader { + float: right; + width: 66%; + } + .glmCartSubTotals .glmCartTable .glmCartHeader .glmCartText { + width: 42%; + margin-right: 0; + margin-left: 8%; + height: auto; + text-align: right; + } + .glmCartSubTotals .glmCartTable .glmCartValues { + float: right; + clear: right; + width: 66%; + } + .glmCartSubTotals .glmCartTable .glmCartValues .glmCartText { + width: 42%; + margin-right: 0; + margin-left: 8%; + border-bottom: 0; + height: auto; + text-align: right; + } + .glmCartTable.totals { + padding-left: 0; + padding-right: 0; + } + .glmCartTable.totals .glmCartHeader { + float: right; + width: 100%; + margin-bottom: 0; + } + .glmCartTable.totals .glmCartHeader .glmCartText { + width: 28%; + margin-right: 0; + margin-left: 5%; + border-bottom: 1px solid #CCC; + height: auto; + text-align: right; + } + .glmCartTable.totals .glmCartValues { + float: right; + width: 100%; + } + .glmCartTable.totals .glmCartValues .glmCartText { + width: 28%; + margin-right: 0; + margin-left: 5%; + border-bottom: 0; + height: auto; + text-align: right; + } + .glmTicketsSelectValueWrapper { + float: left; + width: 150px; + clear: left; + margin-top: 10px; + } + .glmBlockLeft { + width: 100%; + } + .glmCartEventDescrMobile { + display: inline; + } + .glmCartEventDescr { + display: none; + } +} +/* MidSmall Mobile */ +@media screen and (max-width:449px) { + #GLMpageTitle { + font-size: 16px; + line-height: 20px; + } + .glmBlockName { + font-size: 14px; + line-height: 18px; + } + .glmCartFormInput { + width: 100%; + } + .glmCartForm input[type="text"] { + width: 100%; + } + .glmCartForm select { + width:100%; + } + .glmNavItemWide { + width: 100%; + } + .glmNavItem.add { + width: 100%; + text-align: center; + } + #GLMcheckoutBtn { + width: 100%; + text-align: center; + } + +} +/* XSmall Mobile */ +@media screen and (max-width:399px) { + .glmNavItem.chooser { + display: block; + width: 100%; + overflow: hidden; + margin-top: 10px; + text-align: center; + } +} + +#glmReloadBlocker { + display: none; + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + background-color : transparent; + text-align: center; + z-index: 1000; +} +#glmReloadBlocker div { + height: auto; + width: 250px; + padding: 10px; + background: #eee; + position: fixed; + border-radius: 10px; + border: 2px solid #666; + color: red; + font-size: 1.1em; + line-height: 150%; + + margin: -150px 0 0 -150px; + left: 55%; + top: 60%; + + box-shadow: 10px 10px 5px #888888; +} +#glmDevelopmentNotice { + padding: 5px; + border: 1px solid black; + width: auto; + clear: both; + margin-top: 4em; +} diff --git a/web/front/TicketsFoundation/EventManagement.js b/web/front/TicketsFoundation/EventManagement.js new file mode 100644 index 0000000..34e8596 --- /dev/null +++ b/web/front/TicketsFoundation/EventManagement.js @@ -0,0 +1,94 @@ +/* + * Event Management Front-End Area JAVAScript - TicketsFoundation interface + */ + +var f_loadAction = false; +var f_replaceContents = false; +var duration = 0; + +// jQuery Section +$(document).ready(function(){ + + /* + * Data Setup Section + */ + + var siteURL = flex_baseURL; + var appURL = flex_baseAppURL; + + /* + * Load an action to a div with the specified id where id is also Action to be run + */ + function loadAction(id, container, params) { + + // Display loading message + $('#'+container).html('
    Loading, Please Wait...
    '); + $('#'+container).show(duration); + + // Build the URL and call it with AJAX + url = appURL + "?Action=" + id; + if (params) { + url = url + '&' + params; + } + $.post( url, + '', + function(data) { + // Populate the container with the results + $('#'+container).html(data); + restartOnTabSelect(); + } + ); + + } + f_loadAction = loadAction; + + // Replace the contents of a div + function replaceContents(data, destination) { + destination.html(data); + } + f_replaceContents = replaceContents; + + /* + * General Slider Operations + */ + + // Slider area actions + $('.glmSectionSelector').on('click', null, function() { + + // Get the ID of the area to slide from the emSliderId="" parameter in the div tag. + var sliderId = $(this).attr('emSliderId'); + + // If the slider is currently open - close it, otherwise open it. + if ($('#'+sliderId).is(':visible')) { + $('#'+sliderId).hide(duration); + } else { + $('#'+sliderId).show(duration); + } + }); + // Startup by closing all areas that are supposed to be closed by default + $('.glmSectionTickets').hide(duration); + + /* + * Check for user timeout + */ + var inactivityTime = 1800000; // Number of milliseconds to user timeout + + // If theres no activity for 5 seconds do something + var activityTimeout = setTimeout(inActive, inactivityTime); + + function resetActive(){ + $(document.body).attr('class', 'active'); + clearTimeout(activityTimeout); + activityTimeout = setTimeout(inActive, inactivityTime); + } + + // No activity do something. + function inActive(){ + alert("Your user session has timed out. Click OK to continue."); + window.location.href = siteURL; + } + + // Check for mousemove, could add other events here such as checking for key presses ect. + $(document).bind('mousemove', function(){resetActive()}); + +}); diff --git a/web/front/TicketsFoundation/assets/get_adobe_reader.png b/web/front/TicketsFoundation/assets/get_adobe_reader.png new file mode 100644 index 0000000000000000000000000000000000000000..f53add875db304eb6f0186be56f0b53de82b5d8f GIT binary patch literal 2597 zcmV+=3flFFP)FDXiA0?%wrM(^`&d$zcVq{raTEfA>s1zB!yuE=64#h1qrVJ6PIX%64eRvcWv>qeb zASRiZndRi7lMoe^2@bOi5~--Ekrf%D93hgBk=51Jx3;!OMMm!0 z+ng{or>3T!4;0td*V))O@$u*9=VM@C<KR{;X+>+ALP_5S|;%E`%< zl$DGY8Py;r$8&bj&(L-U3!b5)s8mmgomITAoKF`;U6cw86RwG zZDS4)i5MHl$H$^1DY%7)Y!DNtD=_KD$l$uW%*@QNuCL|6!-*3XFCDCn@LR6yuFc>m%1r0P|U)PIK(o z<;#oX<40GmD&OqyUl-^*BTgo>dO2rbbntMMN~L`-EqnUub9@}nYU5QsI`gFn`CcF8 zQQhMBQ9CbL;CXnsx>iNZ0}=9zmmH|h&MP0!L*?Q2BHj~&_v2*_pC6+-JX^|Jc|b&- zIaf7n)+|-YAkRZIsuO0rGV z+ZXq#@_ut@%a$#NzOwNsPSBOV`=@ucL);Kh}S z$U`!W6Lgyq@7Z5pK{~`k<Y_+Z3#uCIOyDvKiyBF7WFG58*#yGO82G zTR4^Qa<2k}r-albTuquC0N>@nB&6wgDW4D>5U(c^zz4wLH)0caCHVea*KUV?(dn^t0m&ht7<+K5qPc=5Y1E9~dGzPc_ z)uNM2K8=~^qumFccmoWcI0XRSmdpok0AR8-HiUx;-D3bcax68E<;9W6FwQEA8Y?Ki zvnyuZx(nxy7RGe#JvV3OoLh@xV`GK(iWK<(;G#3I+B^Ug$0#*#K@F=lsHMEcOpKL%djV=*jSYa@#YXJ;8BU25*8iST`8>;S>Kb9xsV@2ut<>8p4 zukMP@o}WHHE$!`*>EB;H_segWd&V|9^6iD>v$=>@4FjF(elzQ0hO>%Uz$QVsqQp;! zJ5v3$6rfc14y@6%e4rZwoE#&Q0FcU^hU1DnPc8 zugc;|4-c}mBX39iY|)vR*x2S~zP%3Z6y-+5TLJKlW=F1K2%w4E2uzvjh_U?{b!wYR z4*-}K4oA4AQgu?BY5+i)RAIn8J%F(j4C`Bi5}`96+|+9(Tn#TPxxBo>yrQG!(Zv@X zFb?Ue$n!Yj@3%agn}zm{v-&dQAmQn`q)?qZ05IL4)G~^0=+&}}me%FYF$}X4aygb| zRZz;cp3r$C-X&DL3%IBmZZ=$18@W&Q6Z1%%y^5nR+MHXBS6*vvsU1jm#D6Fb?ZHW3lcwZO=`eI%SBfz&weIw!Mj6-vYx5 z6|kvDn=04U0}S%R-DB3SfD&COK2df~nX=vh30zZ6t-=J#wfuK)Sn-nyc^644Z*~<% z_ZOx)5S&n*O?SJG@Yble0eqybsn#f22Hkq8nl!eH&XYkgw<=DMOyK&53J-8x^2$132)=}>!O@o1!vMx<2~ zhvxb}x@*@&<4J{7@irTd>O|&Y6_Gh1+jtz`9g3r9JjB88`J*`RmKV~zOl)?Xy*fvHIW7|;eUASH%tm|u;-`vx00000NkvXX Hu0mjfz561% literal 0 HcmV?d00001 diff --git a/web/front/TicketsFoundation/assets/paypal_but6.gif b/web/front/TicketsFoundation/assets/paypal_but6.gif new file mode 100644 index 0000000000000000000000000000000000000000..5da5a520da3967c966b4aa4bd9f0fcdeba928312 GIT binary patch literal 4774 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 literal 0 HcmV?d00001 diff --git a/web/front/TicketsFoundation/assets/pdficon_large.png b/web/front/TicketsFoundation/assets/pdficon_large.png new file mode 100644 index 0000000000000000000000000000000000000000..c42f1550ea273c570a1bdd2f57769fa8166224d7 GIT binary patch literal 1397 zcmV-*1&aEKP)dbVG7wVRUJ4ZXi@?ZDjyCFEKGM zFgD;wjClY60338hSaefwW^{L9a%BKPWN%_+AVz6&Wp{6KYjYq&Q#En5<2C>Q1kOoB zK~z|U<(FM-lT{eUe{cJ~ux?#j$8;a=3)x2oDMO=B83WM^6$v562_{6yjK+)Ik;skU z1qLo4UO3T2mIW+ zrF9}z=R)xGrL*|`eymojucf7>^3b6}6UoNOL1B}IsGjkR z$knki48y?d^-^0~Yin+9z6~r(CPF%1wn8kDOtYNZ?{ouj|JDFMZ)@W9?hXKcKXsO_ z-56&h*N+`%^}apm!l1zQ90TpA0r+v-E&%i-bE6SZ6ovNoc1A}>Q51!$sw!MA z*SiA)0~cy)YEA*d6cU1PoB@1ZT8sOm1F`md!#A1eyT#4#z6W5qvy0)*u7tT^AqWY9 zBuV7v=8~PAO-@b@x~_BW+BI5RTTOPmeLtW8Nc#$(5_x7NVHYz|^89Kh`ufox9>-j` z7twjA>ld=JvQSkOP16X4LIeT}sY%kAa60kz_F;0^=Nvl|3l?B9nUExj zMGf_6NMx;a&MDwOi9iI2AQF?`d^;}znSKvcd%fO)WTK+zEUCimuwejeu3SR4+mqgb zXqlCjRRat@k_g;Bc$feZE80%rzdudi2YWM)K-%Y*YPU1ny4TC#k)teYejj_ClQrkg z;C^{46RwS{*t-XSd)<8~b{j<-){$4|T)2Rl^}!=Y5e_>=TQ<>i;4tIv4t&08d_6bu zytxyBM0QyzMH}k5-tr|ITaQrk!n%Lf%8@At>nU2l zmi#&=iyU@5mpi%jbsHnUcHkQxL9yFtym*#^RV$HYxds@_Gyv7AstQ$AMIaCm_dR3c zLi29%2{zHz@QMfqgE7-IEoPxmNQ6Qmq3gQPbzS^5IVHm3u!uw=0;q<09)ToDOx)<@ zOyk>VULV+Pym+i7KygfSTlFqs}anD)k0Bg)^$B05v3wbSD)dl0S5nd9!Tb!i!>P)oQUS~ zJt_gJ*=*hhl+K$WIYs~#=JDqgSOR1}A^|Ee1qA*EAjBLvt*8Qp00000NkvXXu0mjf DW5;%t literal 0 HcmV?d00001 diff --git a/web/front/tickets/EventManagement.css b/web/front/tickets/EventManagement.css new file mode 100644 index 0000000..ddb0de0 --- /dev/null +++ b/web/front/tickets/EventManagement.css @@ -0,0 +1,773 @@ +/* Additional styles for Event Management front-end */ +#GLMHeader { + display: block; + width: 100%; + overflow: hidden; + margin: 0 0 5px 0; + padding: 0; + border-bottom: 1px solid #CCC; +} +#GLMpageTitle { + color: #040267; + float: left; + font-family: "Lora","Times New Roman",Times,serif; + font-size: 20px; + line-height: 24px; + font-weight: normal; + margin: 0 0 10px; + padding: 0 0 5px 0; + width: 70%; + /*background: rgba(0,0,0,0.1);*/ +} +#GLMpageIntro { + margin: 1em 0 1em 0; +} +.glmBold { + font-weight: 600; +} +.glmBlock { + display: block; + width: 100%; + overflow: hidden; + margin: 0 0 10px 0; + padding: 5px; + border: 1px solid #CFCFCF; + background: rgba(0,0,0,0.05); +} +.glmBlockList { + margin-top: 10px; + clear: both; +} +.glmBlockHeader, .glmBlockHeadder { + display: block; + width: 100%; + overflow: hidden; + margin: 0 0 5px 0; +} +.glmBlockName { + display: inline; + font-size: 18px; + line-height: 22px; + font-family: "Lora","Times New Roman",Times,serif; +} +.glmBlockRightCol { + float: right; +} +.glmBlockContent { + margin: 0 0 0em 0; + clear: both; + width: 100%; +} +.glmBlockContentLeft { + display: block; + float: left; + width: 70%; + overflow: hidden; +} +.glmBlockContentRight { + display: block; + float: right; + width: 20%; + overflow: hidden; + margin-bottom: 10px; + margin-left: 5%; + min-width: 120px; +} +.glmBlockContentIndent { + display: block; + margin-left: 3em; +} +.glmSection { +} +.glmSection .glmSectionName { +} +.glmSection .glmSectionBold { + font-size: 1.1em; + font-weight: 600; +} +.glmSectionName { + font-size: 1.1em; + font-weight: 600; + margin: 1em 0 0 0; +} +#GLMeventDescr, #GLMvenueDescr, .glmCartVenueDescr, .glmCartEventDescr { + font-size: 0.8em; + margin: 0 0 2.2em 0 +} +.glmCartEventDescrMobile { + display: none; +} +.glmCartVenueDescr, .glmCartEventDescr { + margin: 0 0 15px 0 +} +.glmCartEvents { +} +.glmCartEvent { +} +.glmCartSelect { + width: 4em; +} +.glmCartEventTitle { + font-size: 18px; + line-height: 22px; + font-family: "Lora","Times New Roman",Times,serif; +} +.glmCartEventInfo { + margin-top: .5em; + clear: both; +} +.glmCartEventInfoLeft { + float: left; + padding-right: 100px; +} +.glmCartHeader { + font-size: 1.1em; + font-weight: 600; + clear: both; +} +.glmCartHeader .glmCartText { + font-weight: bold; + border-bottom: 1px solid #CCC; +} +.glmCartValues { + clear: both; +} +.glmCartTable { + display: block; + width: 100%; + overflow: hidden; + margin: 10px 0 0 0; + padding: 10px; + border: 1px solid #CFCFCF; + background: rgba(0,0,0,0.05); +} +.glmCartTable.totals { + display: block; + width: 100%; + overflow: hidden; + margin: 10px 0 0 0; + padding: 10px 0 10px 20px; + border: 0; + background: none; +} +.glmCartTable.sub { + padding-top: 0; + padding-bottom: 0; +} +.glmCartNumb { + width: 20%; + float: left; + align: right; +} +.glmCartText { + display: block; + width: 17%; + margin-right: 3%; + float: left; + padding: 2px 0 0 0; +} + +.glmGrandTotals { + float: right; + color: #900; + font-weight: 600; + font-size: 1.1em; +} + +.glmCartTable.totals .glmCartText { + display: block; + width: 30%; + margin-right: 3%; + float: right; + padding: 2px 0 0 0; +} +.glmCartTable.totals .glmCartHeader .glmCartText { + color: #900; +} +.glmCartTable.totals .glmCartText.grand { + margin-right: 0; + padding-right: 0; +} +.glmCartTotal { + width: 30%; + float: left; +} +.glmCartWide { + width: 40%; + float: left; +} +.glmCartBlock.totals .glmCartWide { + width: 100%; + padding-top: 10px; +} +.glmCartTotal { + width:20%; + font-weight: 600; + font-size: 1.1em; +} +.glmCartSubTotals { + margin-top: 10px; + clear: both; +} +.glmCartSubTotals .glmCartTable { + background: none; + border: 0; +} +.glmCartSubTotals .glmCartTable .glmCartHeader { + float: right; + width: 40%; +} +.glmCartSubTotals .glmCartTable .glmCartHeader .glmCartText { + width: 42%; + margin-right: 8%; + height: auto; + text-align: left; +} +.glmCartSubTotals .glmCartTable .glmCartValues { + float: right; + clear: right; + width: 40%; +} +.glmCartSubTotals .glmCartTable .glmCartValues .glmCartText { + width: 42%; + margin-right: 8%; + border-bottom: 0; + height: auto; + text-align: left; +} +.glmCartTotals { + margin-top: 10px; +} +.glmCartBlock { + display: block; + width: 100%; + overflow: hidden; + margin: 0 0 1em 0; + padding: 10px; + border: 1px solid #CFCFCF; + background: rgba(0,0,0,0.05); +} +.glmCartBlock.totals { + display: block; + width: 100%; + overflow: hidden; + margin: 0 0 10px 0; + padding: 0; + border: 0; + background: none; +} +.glmCartBlockTitle { + font-size: 22px; + line-height: 28px; + font-family: "Lora","Times New Roman",Times,serif; + margin: 0 0 0 0; +} +.glmCartBlockSmallTitle { + font-size: 16px; + line-height: 22px; + font-family: "Lora","Times New Roman",Times,serif; +} +.glmCartBlock input[type="textarea"] { + display: block; + float: left; + clear: left; + width: 100%; +} +.glmEventDateInput { + width: 80px; +} +.glmCartBlock.totals .glmCartBlockTitle { + border-bottom: 1px solid #CCC; +} +.glmCartBlockSubTitle { + margin-top: 1em; + font-size: 1.1em; + font-weight: 600; + margin-bottom: .5em; +} +.glmCartBlockSubTitleValue { + +} +.glmCartBlockText { +} +.glmCartBlockDates { + clear: both; +} +.glmCartBlockDate { + margin-top: .5em; +} +.glmSpecialRequests { + margin: 0 0 3em 0; +} +#GLMcontent { + padding: 0; + margin: 0 auto +} +#GLMcontent>* { +/* padding: 0 15px; */ +} +#GLMevent, #GLMtickets, #GLMvenue { + /* max-width: 500px; */ + margin: 0 auto 1em auto +} +#GLMnavigation:after { + content: ""; + display: table; + clear: both +} +.glmNavItemInactive { + float: right; + padding: 3px 10px; + width: auto; + display: block; + overflow: hidden; + background: #ddd; + border: 1px solid #aaa; + border-radius: 8px; + cursor: pointer; + text-transform: uppercase; + text-align: center; +} +.glmNavItem { + float: right; + padding: 3px 10px; + width: auto; + display: block; + overflow: hidden; + background: #900; + border: 1px solid #900; + border-radius: 8px; + cursor: pointer; + text-transform: uppercase; +} +a.glmNavItem { + color: #FFF; + font-weight: bold; + text-shadow: none; +} +div.glmNavItem { + color: #FFF; + font-weight: bold; + text-shadow: none; +} +.glmNavItem.cart { + background: #040267; + border: 1px solid #040267; +} +.glmNavItemWide { + display: block; + width: 400px; + overflow: hidden; + margin: 12px 0 0 0; + padding: 8px 0; + background: #900; + border: 1px solid #900; + border-radius: 8px; + color: #FFF; + text-align: center; + vertical-align: middle; + font-size: 18px; + font-weight: bold; + font-family: "Times New Roman", Times, serif; + cursor: pointer; +} +.glmSelectItem { + padding: 5px; + margin: 0; + width: 150px; + border-left: 1px solid #e3e3e3; + cursor: pointer; + border: 1px solid #e3e3e3; + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + -ms-border-radius: 6px; + -o-border-radius: 6px; + border-radius: 6px; + text-align: center; + font-weight: 600; + font-shadow: 0 1px #fff; + font-size: 0.85em; + background: #fcfcfc; + -webkit-background-clip: padding; + -moz-background-clip: padding; + background-clip: padding-box; +} +#GLMcheckout .glmNavItem, #GLMticketCart .glmNavItem { + width: 33.3333% +} +#GLMeventDates, #GLMvenueLocation, #GLMvenueDetail, #GLMvenueSectionMap { + margin: 0 0 15px 0 +} +.glmPrompt { + font-weight: 600; + font-size: 1.1em +} +.glmTicketDescr { + font-size: 0.85em +} +.glmTicketAvailable { + margin: 5px 0; + font-weight: 600 +} +.glmSectionTickets { + margin: 15px 0 +} +.glmTicketName { + font-size: 1.35em; + font-weight: 600 +} +.glmSectionSelector { + border: 1px solid #e3e3e3; + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + -ms-border-radius: 6px; + -o-border-radius: 6px; + border-radius: 6px; + cursor: pointer; + background-color: #f8f8f8; + padding: 8px 15px; + margin: 5px 0; + font-size: 1.15em; + font-weight: 600; + display: inline-block; + font-shadow: 0 1px #fff +} +.glmSectionSelector:active { + -webkit-box-shadow: inset 0 0 8px #dbdbdb; + -moz-box-shadow: inset 0 0 8px #dbdbdb; + box-shadow: inset 0 0 8px #dbdbdb +} +#GLMticketsSummary { + font-weight: 600; + font-size: 1.35em; + margin-top: 30px +} +.glmTicketsSelect { + clear: both; + margin: 1em; +} +.glmTicketsSelectPrompt { + font-size: 1em; + font-weight: 600; + line-height: 125%; + float: left; + padding-right: .2em; +} +.glmTicketsSelectValueWrapper { + float: right; + width: 150px; + text-align: right; +} +.glmTicketsSelectValue { + float: right; + width: 40%; + text-align: right; +} +#glmQuantSelector { + float: right; + text-align: right; + width: 100px; + height: 28px; +} +#GLMpolicy { + font-size: 0.85em; + font-style: italic; +/* margin-bottom: 15px; */ +} +.glmTicketPrice { + font-weight: 600; + margin: 15px 0 5px 0; + font-size: 1.25em +} +#GLMreason { + border: 1px solid #333; + padding: 1em; +} +.GLMreasonTitle { + color: red; +} +.GLMreasonList { +} +.GLMmapWindow { + width: 100%; + height: 140px; + border: 1px solid #CCC; +} +.glmDescr { +} +.glmCartFailedInput { + background: #FFaBa9; + padding: .2em; +} +.glmCartRequired { + color: red; +} +/* CHECKOUT STUFF */ +.glmCartFormLine { + clear: both; +} +.glmCartFormPrompt { + width: 30%; + float: left; + text-align: right; + font-weight: 600; + font-size: 1.1em; + padding-right: .5em; +} +.glmCartFormInput { + padding-left: 1em; + width: 70%; + float: left; + margin-bottom: .5em; +} +.glmCartFormInput span { + display: block; + width: 100%; + overflow: hidden; +} +/* Forms */ +.glmCartForm { + display: block; + width: 100%; + overflow: hidden; + padding: 10px; + background: #F5F5F5; + margin: 0 0 10px 0; + font-size: 12px; + border: 1px solid #CCC; + color: #656565; +} +.glmCartForm input[type="text"] { + display: block; + float: left; + clear: left; + width: 300px; +} +.glmCartForm select { + display: block; + float: left; + clear: left; + width: 200px; +} +.glmCartPayment { + margin: 2em 0 0 0 +} +.glmInput { + float: right; +} +/* Mobile */ +@media screen and (max-width:768px) { + .glmBlockContentRight { + float: left; + width: 100%; + margin-left: 0; + margin-right: 0; + margin-top: 10px; + margin-bottom: 10px; + } + .glmBlockContentLeft { + display: inline; + float: left; + width: 100%; + } + .glmBlockContentLeft div { + clear: none !important; + } + /* Mobile Forms */ + +} +/* Small Mobile */ +@media screen and (max-width:599px) { + .GLMmapWindow { + height: 130px; + } + .glmCartFormPrompt { + display: block; + width: 100%; + overflow: hidden; + text-align: left; + } + .glmCartFormInput { + margin-left: 0; + padding-left: 0; + } + #GLMpageTitle { + width: 50%; + } + .glmCartHeader { + float: left; + clear: none; + width: 50%; + overflow: hidden; + + margin-bottom: 20px; + } + .glmCartHeader .glmCartText { + display: block; + width: 100%; + overflow: hidden; + border-bottom: 1px solid #CCC; + height: 30px; + } + .glmCartValues { + float: left; + clear: none; + width: 50%; + overflow: hidden; + margin-bottom: 20px; + } + .glmCartValues .glmCartText { + display: block; + width: 100%; + overflow: hidden; + border-bottom: 1px solid #CCC; + height: 30px; + } + .glmCartSubTotals .glmCartTable .glmCartHeader { + float: right; + width: 66%; + } + .glmCartSubTotals .glmCartTable .glmCartHeader .glmCartText { + width: 42%; + margin-right: 0; + margin-left: 8%; + height: auto; + text-align: right; + } + .glmCartSubTotals .glmCartTable .glmCartValues { + float: right; + clear: right; + width: 66%; + } + .glmCartSubTotals .glmCartTable .glmCartValues .glmCartText { + width: 42%; + margin-right: 0; + margin-left: 8%; + border-bottom: 0; + height: auto; + text-align: right; + } + .glmCartTable.totals { + padding-left: 0; + padding-right: 0; + } + .glmCartTable.totals .glmCartHeader { + float: right; + width: 100%; + margin-bottom: 0; + } + .glmCartTable.totals .glmCartHeader .glmCartText { + width: 28%; + margin-right: 0; + margin-left: 5%; + border-bottom: 1px solid #CCC; + height: auto; + text-align: right; + } + .glmCartTable.totals .glmCartValues { + float: right; + width: 100%; + } + .glmCartTable.totals .glmCartValues .glmCartText { + width: 28%; + margin-right: 0; + margin-left: 5%; + border-bottom: 0; + height: auto; + text-align: right; + } + .glmTicketsSelectValueWrapper { + float: left; + width: 150px; + clear: left; + margin-top: 10px; + } + .glmBlockLeft { + width: 100%; + } + .glmCartEventDescrMobile { + display: inline; + } + .glmCartEventDescr { + display: none; + } +} +/* MidSmall Mobile */ +@media screen and (max-width:449px) { + #GLMpageTitle { + font-size: 16px; + line-height: 20px; + } + .glmBlockName { + font-size: 14px; + line-height: 18px; + } + .glmCartFormInput { + width: 100%; + } + .glmCartForm input[type="text"] { + width: 100%; + } + .glmCartForm select { + width:100%; + } + .glmNavItemWide { + width: 100%; + } + .glmNavItem.add { + width: 100%; + text-align: center; + } + #GLMcheckoutBtn { + width: 100%; + text-align: center; + } + +} +/* XSmall Mobile */ +@media screen and (max-width:399px) { + .glmNavItem.chooser { + display: block; + width: 100%; + overflow: hidden; + margin-top: 10px; + text-align: center; + } +} + +#glmReloadBlocker { + display: none; + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + background-color : transparent; + text-align: center; + z-index: 1000; +} +#glmReloadBlocker div { + height: auto; + width: 300px; + padding: 10px; + background: #eee; + position: fixed; + border-radius: 10px; + border: 2px solid #666; + color: red; + font-size: 1.3em; + line-height: 150%; + + margin: -150px 0 0 -150px; + left: 50%; + top: 60%; + + box-shadow: 10px 10px 5px #888888; +} +#glmDevelopmentNotice { + padding: 5px; + border: 1px solid black; + width: auto; + clear: both; + margin-top: 4em; +} diff --git a/web/front/tickets/EventManagement.js b/web/front/tickets/EventManagement.js new file mode 100644 index 0000000..2344c83 --- /dev/null +++ b/web/front/tickets/EventManagement.js @@ -0,0 +1,94 @@ +/* + * Event Management Front-End Area JAVAScript - Tickets interface + */ + +var f_loadAction = false; +var f_replaceContents = false; +var duration = 0; + +// jQuery Section +$(document).ready(function(){ + + /* + * Data Setup Section + */ + + var siteURL = baseSiteURL; + var appURL = baseAppURL; + + /* + * Load an action to a div with the specified id where id is also Action to be run + */ + function loadAction(id, container, params) { + + // Display loading message + $('#'+container).html('
    Loading, Please Wait...
    '); + $('#'+container).show(duration); + + // Build the URL and call it with AJAX + url = appURL + "?Action=" + id; + if (params) { + url = url + '&' + params; + } + $.post( url, + '', + function(data) { + // Populate the container with the results + $('#'+container).html(data); + restartOnTabSelect(); + } + ); + + } + f_loadAction = loadAction; + + // Replace the contents of a div + function replaceContents(data, destination) { + destination.html(data); + } + f_replaceContents = replaceContents; + + /* + * General Slider Operations + */ + + // Slider area actions + $('.glmSectionSelector').on('click', null, function() { + + // Get the ID of the area to slide from the emSliderId="" parameter in the div tag. + var sliderId = $(this).attr('emSliderId'); + + // If the slider is currently open - close it, otherwise open it. + if ($('#'+sliderId).is(':visible')) { + $('#'+sliderId).hide(duration); + } else { + $('#'+sliderId).show(duration); + } + }); + // Startup by closing all areas that are supposed to be closed by default + $('.glmSectionTickets').hide(duration); + + /* + * Check for user timeout + */ + var inactivityTime = 1800000; // Number of milliseconds to user timeout + + // If theres no activity for 5 seconds do something + var activityTimeout = setTimeout(inActive, inactivityTime); + + function resetActive(){ + $(document.body).attr('class', 'active'); + clearTimeout(activityTimeout); + activityTimeout = setTimeout(inActive, inactivityTime); + } + + // No activity do something. + function inActive(){ + alert("Your user session has timed out. Click OK to continue."); + window.location.href = siteURL; + } + + // Check for mousemove, could add other events here such as checking for key presses ect. + $(document).bind('mousemove', function(){resetActive()}); + +}); diff --git a/web/front/tickets/assets/paypal_but6.gif b/web/front/tickets/assets/paypal_but6.gif new file mode 100644 index 0000000000000000000000000000000000000000..5da5a520da3967c966b4aa4bd9f0fcdeba928312 GIT binary patch literal 4774 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 literal 0 HcmV?d00001 -- 2.17.1