Search by

smsh / ticketing-bridge

alexweng27

SmartShanghai bridge for SolidSource ticketing external identity login.

Package info

github.com/alexw27/smsh-ticketing-bridge

Type:symfony-bundle

pkg:composer/smsh/ticketing-bridge

Statistics

Installs: 4

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

1.0.36 2026-11-06 14:25 UTC

README

Private Symfony bundle for plugging SmartShanghai into the SolidSource ticketing external identity system.

Package name:

"smsh/ticketing-bridge": "*"

What It Provides

  • Integration provider key: smartshanghai
  • Admin integration provider: SmartShanghai
  • External identity provider button for /login and /register
  • Authentication handler for /connect/smartshanghai/check
  • WeChat Scanner sales channel publisher (wechat_scanner) — generates scanner Mini Program QR codes when an event is published
  • WeChat Mini Program QR codes on discount campaigns (admin campaign form)
  • WeChat Mini Program QR codes on event affiliates (admin event → Affiliates, and GET /api/v1/promoter/affiliates/...)
  • WeChat Mini Program QR codes on event access links (admin event → Access links) — consumer MiniProgram pages/ticketingSchedule/ticketingSchedule with access scene
  • WeChat Mini Program QR codes on organizations (admin organization form) — join QR for pages/org/org on the scanner MiniProgram (wechat-scanner)
  • SmartShanghai event listing sync on publish — links SMSH listings via report access token and imports thumbnail
  • POST /api/v1/me/organizations — add the signed-in user to an organization (promoter / scanner membership)
  • POST /api/v1/auth/external/wechat-market/phone — exchange a WeChat getPhoneNumber code for the signed-in user's verified phone
  • WeChat Mini Program subscription messages for communication-flow notification type wechat_subscribe

WeChat Scanner event QR codes

On first event publish, the bridge generates a Mini Program QR for the wechat_scanner sales channel.

  • Credentials: enabled WeChat integration with slug wechat-scanner (System → API / Integrations).
  • Page: pages/scanner/scanner with scene id={eventId}.

WeChat campaign Mini Program QR codes

When a campaign is saved, the bridge generates a Mini Program QR for each targeted event and shows it on the campaign admin form (below the web share QR). Global and venue-only campaigns are skipped until an event (or price-category) target is added.

  • Credentials: WeChat Pay MiniProgram App ID + App Secret by default (same as MiniProgram checkout). Override with SmartShanghai setting MiniProgram WeChat connection slug. Do not use wechat-scanner unless the QR should open the door MiniProgram.
  • Page: pages/smtkEvent/smtkEvent.
  • Scene: id={eventId}&aci={campaignId} (SmartTicket event id and campaign id, e.g. id=5614&aci=99). MiniProgram checkout sends aci as affiliate_campaign_id.

Generation failure is logged and does not block saving the campaign.

WeChat event-affiliate Mini Program QR codes

When an event affiliate is saved, the bridge generates a Mini Program QR and shows it on the affiliate admin form (below the web share QR). The same QR is attached to promoter affiliate JSON as wechat_miniprogram_qr on GET /api/v1/promoter/affiliates/{token} and GET /api/v1/promoter/affiliates/{affiliateId}/{token} (and on create).

  • Credentials: same consumer WeChat MiniProgram as campaign QRs (WeChat Pay by default).
  • Page: pages/smtkEvent/smtkEvent.
  • Scene: id={eventId},ea={affiliateId} (e.g. id=5753,ea=14). WeChat getwxacodeunlimit rejects & in scene, so pairs are comma-separated. MiniProgram checkout sends ea as event_affiliate_id.

Generation failure is logged and does not block saving the affiliate.

WeChat event access-link Mini Program QR codes

When an event access link is saved, the bridge generates a Mini Program QR and shows it on the access-link admin edit form. This opens the SmartShanghai consumer MiniProgram (not the door scanner).

  • Credentials: same consumer WeChat MiniProgram as campaign/affiliate QRs (WeChat Pay by default, e.g. App ID wx7242d750b44505ed).
  • Page: SmartShanghai miniprogram_event_page when set, otherwise pages/ticketingSchedule/ticketingSchedule.
  • Scene: id={eventId},access={slug} (e.g. id=5952,access=vip). WeChat getwxacodeunlimit rejects & and limits scene to 32 characters — keep slugs short. The MiniProgram should load the event API with ?access={slug}.

Generation failure is logged and does not block saving the access link.

WeChat organization Mini Program QR codes

When an organization is opened in admin, the bridge generates a Mini Program QR and shows it on the organization form (below the details form). Scanning it opens the MiniProgram join page so a signed-in user can be added to that organization via POST /api/v1/me/organizations.

  • Credentials: same scanner MiniProgram as event sales-channel QR codes — enabled WeChat integration with slug wechat-scanner.
  • Page: pages/org/org.
  • Scene: id={organizationId} (e.g. id=14).

Generation failure is logged and does not hide the rest of the organization form.

SmartShanghai event listing sync

When an event is published, the bridge:

  1. Creates a promoter report access token (label: SmartShanghai listing sync).
  2. Calls PATCH {api_base_url}/api2/admin/smtk-event-bridge/{event_id}?key={api_token} with { "access_token": "<raw token>" } — {event_id} is the ticketing event id (same as smtk_id on SmartShanghai).
  3. Downloads data.thumbnail_path from the response and sets it as the event thumbnail (admin → Media).

Requires an enabled SmartShanghai integration with api_base_url and api_token. Optional setting Event bridge API path (default /api2/admin/smtk-event-bridge/{event_id}).

Buyer refund cancellation message

When an admin refund succeeds and Notify buyer is checked (single-order refund or event refund batch), the bridge also tells SmartShanghai to message that buyer.

The call runs only when the order's user has a SmartShanghai external identity. The {user_id} is that identity's provider user id, not the ticketing user id. Guest orders and buyers without a SmartShanghai login are skipped. A failed call is logged and does not fail the refund.

POST {api_base_url}/api2/messages/{user_id}/sendTicketingCancellation?key={api_token}
Content-Type: application/json

{
  "message": "Reason shown to buyers",
  "orderNumber": "A-100",
  "orderUrl": "https://api.smartticket.cn/orders/access/…",
  "orderId": 1126264
}

message is the refund reason note. orderId is the ticketing order id. orderUrl is the public order portal URL. The attempt is stored in log_outbound_message with channel smartshanghai.

WeChat Mini Program subscription messages

Communication-flow notification types with channel wechat_subscribe are sent by WeChatMiniProgramSubscribeMessageSender.

The sender loads the Mini Program access token from the selected WeChat integration (default slug wechat-market) and calls:

POST https://api.weixin.qq.com/cgi-bin/message/subscribe/send?access_token=ACCESS_TOKEN

touser is the buyer openid resolved by the host app (checkout payment metadata, then the WeChat external identity). The template ID and keyword values come from the notification type. The Mini Program must call wx.requestSubscribeMessage for that template before WeChat will deliver it. A rejected send is returned to the host as a failed outbound log and does not fail the rest of the communication flow.

Join the signed-in user to an organization

SmartShanghai promoter and scanner clients can add the current JWT user to an organization:

POST /api/v1/me/organizations
Authorization: Bearer <access-token>
Content-Type: application/json

{"organizationId": 12}

Send one of organizationId / organization_id, slug, or code. The call is idempotent: a user who is already a member gets 200 with alreadyMember: true; a new membership returns 201. Inactive or unknown organizations return 404 with organization_not_found. API keys cannot call this endpoint — it requires a signed-in user (ROLE_USER).

WeChat Market phone number

SmartShanghai MiniProgram clients can send the getPhoneNumber dynamic token after the user agrees:

POST /api/v1/auth/external/wechat-market/phone
Authorization: Bearer <access-token>
Content-Type: application/json

{"code":"<getPhoneNumber code>","access_token":"<optional wechat miniprogram token>"}

code is required (5-minute, single-use WeChat token — not the wx.login() code). access_token is the MiniProgram client-credential token used by phonenumber.getPhoneNumber. When omitted, the bridge fetches one from the enabled WeChat integration with slug wechat-market.

On success the user's phone is replaced with WeChat's verified number and phoneVerifiedAt is stamped. An auth.phone_verified audit event is written.

The host app must import the bundle routes (once per installation):

# config/routes/smsh_ticketing_bridge.yaml
smsh_ticketing_bridge:
    resource: '@SmshTicketingBridgeBundle/config/routes.yaml'

Expected SmartShanghai Flow

  1. User clicks Continue with SmartShanghai.
  2. The ticketing app redirects to the configured SmartShanghai login_url.
  3. The bridge appends callback_url=<absolute /connect/smartshanghai/check URL>.
  4. SmartShanghai authenticates the user and redirects back with a short-lived JWT:
/connect/smartshanghai/check?jwt=<smartshanghai-jwt>

The callback also accepts token=<jwt> or an Authorization: Bearer <jwt> header.

The JWT payload should contain an external user id as either:

  • user_id
  • sub

The bridge decodes the JWT only to read that user id for the verify API path. JWT validity is checked by SmartShanghai's API, not locally.

Integration Settings

Configure these under System -> API / Integrations -> SmartShanghai:

  • login_url: SmartShanghai login URL.
  • api_base_url: SmartShanghai API base URL.
  • api_token: partner API key sent as the key query parameter on every SmartShanghai API call.
  • verify_user_path: optional path, defaults to /api2/ticketing/users/{user_id}.
  • email_match_path: optional path, defaults to /api2/ticketing/users/{user_id}/email-matches.
  • miniprogram_event_page: used for access-link QRs (default pages/ticketingSchedule/ticketingSchedule when empty). Unused for campaign and event-affiliate QRs (those always use pages/smtkEvent/smtkEvent).
  • miniprogram_wechat_connection_slug: optional WeChat integration slug for campaign/affiliate/access-link QRs. Empty uses WeChat Pay MiniProgram credentials.
  • event_bridge_path: optional path, defaults to /api2/admin/smtk-event-bridge/{event_id}.

Verify User API Contract (login)

The bridge calls:

GET {api_base_url}{verify_user_path}?key=<api_token>
Authorization: Bearer <smartshanghai-jwt>

Example default URL:

GET https://smsh.solidsource.software/api2/ticketing/users/123?key=...

Expected successful response:

{
  "valid": true,
  "email": "user@example.com"
}

email is optional. The ticketing app can create a local user with only the linked external identity.

Any non-2xx response or "valid": false rejects login.

Email match API Contract (checkout)

When trusted checkout customer payload is enabled and a SmartShanghai-linked buyer submits customer.email, the bridge asks SmartShanghai whether that email belongs to the linked user. This uses the partner API key only (no client JWT) and returns a boolean — it must not expose the stored email.

POST {api_base_url}{email_match_path}?key=<api_token>
Content-Type: application/json

{"email":"user@example.com"}

Example default URL:

POST https://smsh.solidsource.software/api2/ticketing/users/123/email-matches?key=...

Expected successful response:

{
  "match": true
}

matches: true|false is also accepted. Non-2xx or an unexpected payload fails checkout with customer_email_verification_failed. match: false fails with customer_email_mismatch.