@autobusal/routes-order 1.34.2 → 1.34.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,3 +1,7 @@
1
+ ## 1.34.3 - 2026-08-29
2
+
3
+ - Staff sellers (agent/subagent/operator/employee/admin) get an OPTIONAL passenger email box at checkout, so a counter-sold ticket reaches the passenger instead of only the seller and operator (audit A4-05, owner decision). obtapi already read {type}{i}_email/_notify_email; it now validates them too.
4
+
1
5
  ## 1.34.2 - 2026-08-29
2
6
 
3
7
  - With more than one card gateway available, each Credit Card button carries its processor's name - they used to render byte-identical (audit A0-06).
@@ -442,6 +442,14 @@ const Checkout = ({ values, step1, step2, step3, isPartner, t, onStore, onBack }
442
442
  values={ values }
443
443
  step1={ step1 }
444
444
  fields={ fields }
445
+ /*
446
+ * Claude - 2026-08-29 (audit A4-05, owner decision): only staff
447
+ * are asked. They are the sellers with no billing block - see
448
+ * `gaps` above - so this optional box is the only way a
449
+ * counter-sold ticket reaches the passenger directly instead of
450
+ * landing solely with the agent and the operator.
451
+ */
452
+ askEmail={ UserData !== undefined && ['agent', 'subagent', 'operator', 'employee', 'admin'].includes(UserData.type) }
445
453
  busFrom={ busFrom }
446
454
  busTo={ busTo }
447
455
  saved={ saved }
@@ -15,6 +15,15 @@ interface Props {
15
15
  number: number
16
16
  values?: PersonData
17
17
  fields: string[]
18
+ /**
19
+ * Claude - 2026-08-29 (audit A4-05, owner decision): staff selling at the
20
+ * counter get an OPTIONAL email box per passenger. They are the only
21
+ * sellers with no billing block (an agent or operator writes no
22
+ * orders_contact row), so without it a walk-in customer's ticket reached
23
+ * only the agent and the operator and had to be Re-Sent by hand. Optional
24
+ * on purpose: a counter sale often has no email to give.
25
+ */
26
+ askEmail?: boolean
18
27
  withReturn: boolean
19
28
  busFrom: OccupiedData
20
29
  busTo: OccupiedData
@@ -47,7 +56,7 @@ interface Props {
47
56
  // telegram render ONLY when the route requires them - and are then
48
57
  // required. Name and date of birth stay mandatory always. `fields` is the
49
58
  // union of both legs on a return trip (see Step4).
50
- const Passenger = ({ type, number, values, fields, withReturn, busFrom, busTo, pickedFrom, pickedTo, saved, savedMax, seatsOptional, seatsFee, t, errors, refs, onSeatSelect, onUpdate }: Props): JSX.Element => {
59
+ const Passenger = ({ type, number, values, fields, askEmail, withReturn, busFrom, busTo, pickedFrom, pickedTo, saved, savedMax, seatsOptional, seatsFee, t, errors, refs, onSeatSelect, onUpdate }: Props): JSX.Element => {
51
60
  const name = `${ type }${ number }`;
52
61
 
53
62
  const names = {
@@ -65,7 +74,13 @@ const Passenger = ({ type, number, values, fields, withReturn, busFrom, busTo, p
65
74
  // Edited: Claude - Date: 2026-08-20
66
75
  // "Remember this passenger" - obtapi reads `{type}{i}_save` alongside
67
76
  // the `_fn` / `_pass` fields this form already posts.
68
- save: `${ name }_save`
77
+ save: `${ name }_save`,
78
+
79
+ // the counter-sale email (audit A4-05). obtapi already reads
80
+ // `{type}{i}_email` + `_notify_email` - see Orders\Make\Tickets - it
81
+ // was only the web form that never offered them.
82
+ email: `${ name }_email`,
83
+ notifyEmail: `${ name }_notify_email`
69
84
  };
70
85
 
71
86
  const has = (field: string): boolean => fields.includes(field);
@@ -340,6 +355,31 @@ const Passenger = ({ type, number, values, fields, withReturn, busFrom, busTo, p
340
355
  </div>
341
356
  ) }
342
357
 
358
+ { askEmail && (
359
+ <div className="column">
360
+ <div className="row">
361
+ <label htmlFor={ id(names.email) }>{ t('routes_order.step4.email') }</label>
362
+
363
+ <input
364
+ type="email"
365
+ key={ `${ names.email }-${ applied }` }
366
+ id={ id(names.email) }
367
+ defaultValue={ start(names.email, undefined) }
368
+ { ...refs(names.email, Validate('email|max_length:255', t)) }
369
+ />
370
+
371
+ { Display(errors[names.email]) }
372
+
373
+ { /* the ticket goes to this address as well as to the seller -
374
+ obtapi gates the per-passenger copy on `_notify_email`, so
375
+ an address typed here has to arrive with the flag set */ }
376
+ <input type="hidden" value="1" { ...refs(names.notifyEmail) } />
377
+
378
+ <Notice>{ t('routes_order.step4.email_notice') }</Notice>
379
+ </div>
380
+ </div>
381
+ ) }
382
+
343
383
  { (has('whatsapp') || has('telegram')) && (
344
384
  <div className="column">
345
385
  { has('whatsapp') && (
@@ -8,6 +8,8 @@ interface Props {
8
8
  type: 'adult' | 'child' | 'baby'
9
9
  amount: number
10
10
  fields: string[]
11
+ /** staff sellers are offered an optional passenger email (audit A4-05) */
12
+ askEmail?: boolean
11
13
  withReturn: boolean
12
14
  values?: PersonData
13
15
  busFrom: OccupiedData
@@ -25,7 +27,7 @@ interface Props {
25
27
  onUpdate: (name: string, value: (string | number)) => void
26
28
  }
27
29
 
28
- const Display = ({ type, amount, fields, withReturn, values, busFrom, busTo, pickedFrom, pickedTo, saved, savedMax, seatsOptional, seatsFee, t, errors, refs, onSeatSelect, onUpdate }: Props): JSX.Element[] => {
30
+ const Display = ({ type, amount, fields, askEmail, withReturn, values, busFrom, busTo, pickedFrom, pickedTo, saved, savedMax, seatsOptional, seatsFee, t, errors, refs, onSeatSelect, onUpdate }: Props): JSX.Element[] => {
29
31
  const passengers: JSX.Element[] = [];
30
32
 
31
33
  for (let i = 1; i <= amount; i++) {
@@ -35,6 +37,7 @@ const Display = ({ type, amount, fields, withReturn, values, busFrom, busTo, pic
35
37
  type={ type }
36
38
  number={ i }
37
39
  fields={ fields }
40
+ askEmail={ askEmail }
38
41
  withReturn={ withReturn }
39
42
  values={ values }
40
43
  busFrom={ busFrom }
@@ -11,6 +11,8 @@ interface Props {
11
11
  values?: PersonData
12
12
  step1: RoutesSearchForm
13
13
  fields: string[]
14
+ /** staff sellers are offered an optional passenger email (audit A4-05) */
15
+ askEmail?: boolean
14
16
  busFrom: OccupiedData
15
17
  busTo: OccupiedData
16
18
  /**
@@ -38,7 +40,7 @@ interface Props {
38
40
  onUpdate: (name: string, value: (string | number)) => void
39
41
  }
40
42
 
41
- const Passengers = ({ values, step1, fields, busFrom, busTo, saved, savedMax, seatsOptional, seatsFee, onPickedCount, t, errors, refs, onUpdate }: Props): JSX.Element => {
43
+ const Passengers = ({ values, step1, fields, askEmail, busFrom, busTo, saved, savedMax, seatsOptional, seatsFee, onPickedCount, t, errors, refs, onUpdate }: Props): JSX.Element => {
42
44
  const [ pickedFrom, setPickedFrom ] = useState<number[]>([]);
43
45
  const [ pickedTo, setPickedTo ] = useState<number[]>([]);
44
46
 
@@ -84,6 +86,7 @@ const Passengers = ({ values, step1, fields, busFrom, busTo, saved, savedMax, se
84
86
  type="adult"
85
87
  amount={ step1.adults }
86
88
  fields={ fields }
89
+ askEmail={ askEmail }
87
90
  withReturn={ step1.type === 'return' }
88
91
  values={ values }
89
92
  busFrom={ busFrom }
@@ -105,6 +108,7 @@ const Passengers = ({ values, step1, fields, busFrom, busTo, saved, savedMax, se
105
108
  type="child"
106
109
  amount={ step1.children }
107
110
  fields={ fields }
111
+ askEmail={ askEmail }
108
112
  withReturn={ step1.type === 'return' }
109
113
  values={ values }
110
114
  busFrom={ busFrom }
@@ -126,6 +130,7 @@ const Passengers = ({ values, step1, fields, busFrom, busTo, saved, savedMax, se
126
130
  type="baby"
127
131
  amount={ step1.babies }
128
132
  fields={ fields }
133
+ askEmail={ askEmail }
129
134
  withReturn={ step1.type === 'return' }
130
135
  values={ values }
131
136
  busFrom={ busFrom }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@autobusal/routes-order",
3
- "version": "1.34.2",
3
+ "version": "1.34.3",
4
4
  "author": "Ferjolt Ozuni",
5
5
  "type": "module",
6
6
  "main": "index.ts"