Diff -- /var/www/vhosts/webstls.com/httpdocs/TEMPLATES/webstls_fulfill_order.html
Diff

/var/www/vhosts/webstls.com/httpdocs/TEMPLATES/webstls_fulfill_order.html

added on WebSTLs (webstls.com) at 2026-07-01 22:27:00

Added
+320
lines
Removed
-0
lines
Context
0
unchanged
Blobs
from
to ac343f85c36f
Restore this content →
Unified diff
Naive LCS-based line diff. Additions in emerald, deletions in rose. Both sides decompressed live from BLOB_STORE.
1<!-- Fulfillment detail. Backed by /fulfill_order.cgi. -->
2
3<style>
4 .ord-grid { display:grid; grid-template-columns:2fr 1fr; gap:18px; align-items:start; }
5 \@media (max-width: 1100px) { .ord-grid { grid-template-columns:1fr; } }
6
7 .ord-card { background:var(--col-surface-1); border:1px solid var(--col-border); border-radius:12px; padding:18px; }
8 .ord-card h3 { font-family:var(--font-display,inherit); font-size:14px; text-transform:uppercase; letter-spacing:1.5px; color:var(--col-text-3); margin:0 0 12px; font-weight:700; }
9 .ord-card .stack > * + * { margin-top:10px; }
10
11 .ord-addr { font-size:13px; color:var(--col-text); line-height:1.5; }
12 .ord-addr em { color:var(--col-text-3); }
13
14 .ord-kv { display:grid; grid-template-columns:auto 1fr; column-gap:14px; row-gap:5px; font-size:13px; }
15 .ord-kv dt { color:var(--col-text-3); }
16 .ord-kv dd { margin:0; color:var(--col-text); }
17
18 .ord-item-row { display:grid; grid-template-columns:1fr auto auto; gap:10px; align-items:center; padding:10px 0; border-bottom:1px solid var(--col-border); }
19 .ord-item-row:last-child { border-bottom:none; }
20 .ord-item-name { font-weight:600; color:var(--col-text); font-size:14px; }
21 .ord-item-meta { font-size:11px; color:var(--col-text-3); margin-top:2px; letter-spacing:0.4px; text-transform:uppercase; }
22 .ord-item-actions { display:flex; gap:6px; align-items:center; }
23
24 .ord-status-row { display:flex; gap:8px; align-items:center; flex-wrap:wrap; }
25 .ord-status-row form { display:flex; gap:6px; align-items:center; flex-wrap:wrap; }
26
27 /* Reuse the chip palette from /fulfill.cgi. */
28 .ful-chip { display:inline-flex; align-items:center; padding:3px 10px; border-radius:999px; font-size:11px; font-weight:700; letter-spacing:0.5px; text-transform:uppercase; }
29 .fs-new { background:rgba(96,165,250,0.18); color:#60a5fa; }
30 .fs-processing { background:rgba(167,139,250,0.20); color:#a78bfa; }
31 .fs-printing { background:rgba(251,191,36,0.20); color:#fbbf24; }
32 .fs-printed { background:rgba(251,191,36,0.32); color:#fde68a; }
33 .fs-packed { background:rgba(6,182,212,0.22); color:#22d3ee; }
34 .fs-shipped { background:rgba(34,197,94,0.20); color:#4ade80; }
35 .fs-partially_shipped { background:rgba(34,197,94,0.12); color:#86efac; }
36 .fs-delivered { background:rgba(34,197,94,0.32); color:#86efac; }
37 .fs-completed { background:rgba(156,163,175,0.20); color:#d1d5db; }
38 .fs-on_hold { background:rgba(245,158,11,0.18); color:#fbbf24; }
39 .fs-cancelled { background:rgba(248,113,113,0.18); color:#f87171; }
40 .fs-returned { background:rgba(248,113,113,0.32); color:#fca5a5; }
41 .fs-not_required { background:rgba(156,163,175,0.10); color:var(--col-text-3); }
42
43 .ord-label { display:flex; gap:10px; align-items:flex-start; padding:10px 12px; border:1px solid var(--col-border); border-radius:10px; margin-bottom:8px; background:var(--col-surface-2); }
44 .ord-label.is-voided { opacity:0.55; }
45 .ord-label-main { flex:1; }
46 .ord-label-actions { display:flex; gap:6px; flex-shrink:0; }
47 .ord-label-cost { font-family:var(--font-mono,monospace); font-weight:700; color:var(--col-accent-bright); }
48
49 .ord-note { background:var(--col-surface-2); border-left:3px solid var(--col-accent); padding:8px 12px; border-radius:0 6px 6px 0; font-size:13px; line-height:1.4; }
50 .ord-note + .ord-note { margin-top:6px; }
51 .ord-note-time { font-size:11px; color:var(--col-text-3); margin-top:4px; }
52
53 .ord-est { padding:10px 12px; background:rgba(34,197,94,0.10); border:1px solid rgba(34,197,94,0.3); border-radius:8px; font-size:13px; color:var(--col-text); }
54 .ord-est strong { color:#86efac; }
55
56 .ord-back { color:var(--col-text-3); text-decoration:none; font-size:13px; display:inline-flex; gap:6px; align-items:center; margin-bottom:10px; }
57 .ord-back:hover { color:var(--col-text); }
58</style>
59
60<a href="/fulfill.cgi" class="ord-back">
61 <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" style="width:14px;height:14px"><path d="M19 12H5"/><polyline points="12 19 5 12 12 5"/></svg>
62 Back to all orders
63</a>
64
65<div class="page-head">
66 <div>
67 <span class="page-eyebrow"><span class="dot"></span> Studio &middot; Fulfillment</span>
68 <h1 class="page-title">Order #$order_id <span class="ful-chip $order_status_class" style="font-size:13px;margin-left:8px;vertical-align:middle">$order_status_label</span></h1>
69 <p class="page-subtitle">$buyer_email &middot; Placed $created_at &middot; \$$total $currency</p>
70 </div>
71</div>
72
73[if:$has_flash]
74<div class="banner $flash_kind mb-3">
75 <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="10"/><line x1="12" y1="8" x2="12" y2="12"/></svg>
76 <div class="text-sm fw-600">$flash_msg</div>
77</div>
78[/if]
79
80<!-- Status changer -->
81<div class="ord-card" style="margin-bottom:18px">
82 <div class="ord-status-row">
83 <strong style="font-size:13px;color:var(--col-text)">Order status:</strong>
84 <form method="POST" action="/fulfill_order.cgi">
85 <input type="hidden" name="_act" value="set_status">
86 <input type="hidden" name="order_id" value="$order_id">
87 <select name="new_status" class="select" style="height:36px;min-width:160px">
88 <option value="new">New</option>
89 <option value="processing">Processing</option>
90 <option value="printing">Printing</option>
91 <option value="printed">Printed</option>
92 <option value="packed">Packed</option>
93 <option value="shipped">Shipped</option>
94 <option value="partially_shipped">Partially shipped</option>
95 <option value="delivered">Delivered</option>
96 <option value="completed">Completed</option>
97 <option value="on_hold">On hold</option>
98 <option value="cancelled">Cancelled</option>
99 <option value="returned">Returned</option>
100 </select>
101 <label style="display:inline-flex;gap:6px;align-items:center;font-size:12px;color:var(--col-text-2);cursor:pointer">
102 <input type="checkbox" name="cascade" value="1" checked> apply to items
103 </label>
104 <button type="submit" class="btn btn-primary" style="height:36px">Update</button>
105 </form>
106 </div>
107</div>
108
109<div class="ord-grid">
110
111 <!-- LEFT COLUMN: items + labels + notes -->
112 <div class="stack">
113
114 <div class="ord-card">
115 <h3>Items in this order</h3>
116 [if:$has_items]
117 <div>
118 [loop:@items]
119 <div class="ord-item-row">
120 <div>
121 <div class="ord-item-name">$loop1.model_title <span style="color:var(--col-text-3);font-weight:400">&times; $loop1.quantity</span></div>
122 <div class="ord-item-meta">
123 $loop1.purchase_kind
124 [if:$loop1.color] &middot; $loop1.color[/if]
125 [if:$loop1.material] &middot; $loop1.material[/if]
126 [if:$loop1.weight] &middot; $loop1.weight g[/if]
127 [if:$loop1.has_tracking] &middot; <a href="$loop1.tracking_url" target="_blank" class="text-brand">$loop1.tracking</a>[/if]
128 </div>
129 </div>
130 <div style="font-family:var(--font-mono,monospace);font-weight:700">\$$loop1.price</div>
131 <div class="ord-item-actions">
132 <span class="ful-chip $loop1.status_class">$loop1.status_label</span>
133 [if:$loop1.is_physical]
134 <form method="POST" action="/fulfill_order.cgi" style="display:inline-flex;gap:4px">
135 <input type="hidden" name="_act" value="update_item">
136 <input type="hidden" name="order_id" value="$order_id">
137 <input type="hidden" name="item_id" value="$loop1.id">
138 <select name="new_status" class="select" style="height:30px;font-size:12px">
139 <option value="new">New</option>
140 <option value="processing">Processing</option>
141 <option value="printing">Printing</option>
142 <option value="printed">Printed</option>
143 <option value="packed">Packed</option>
144 <option value="shipped">Shipped</option>
145 <option value="delivered">Delivered</option>
146 <option value="completed">Completed</option>
147 <option value="cancelled">Cancelled</option>
148 <option value="returned">Returned</option>
149 </select>
150 <button type="submit" class="btn btn-secondary btn-sm">Set</button>
151 </form>
152 [/if]
153 </div>
154 </div>
155 [/loop]
156 </div>
157 [/if]
158 [if:!$has_items]
159 <p class="text-xs text-dim">(no items)</p>
160 [/if]
161 </div>
162
163 <div class="ord-card">
164 <h3>Shipping labels &amp; tracking</h3>
165
166 [if:$has_estimate]
167 <div class="ord-est" style="margin-bottom:12px">
168 <strong>Rate estimate</strong> for this destination: <span style="font-family:var(--font-mono,monospace);font-weight:700">\$$est_dollars</span> via <em>$est_zone</em>
169 [if:$est_min] &middot; ETA $est_min&ndash;$est_max days[/if]
170 <div class="text-xs text-dim" style="margin-top:2px">Formula: $est_formula cents (weight $weight_kg kg)</div>
171 </div>
172 [/if]
173 [if:!$has_estimate]
174 [if:!$has_zones]
175 <div class="ord-est" style="background:rgba(245,158,11,0.10);border-color:rgba(245,158,11,0.32);margin-bottom:12px">
176 No shipping zones defined &mdash; <a href="$settings_url" class="text-brand">create one in Shipping Settings</a> to get rate estimates per destination.
177 </div>
178 [/if]
179 [/if]
180
181 [if:$has_labels]
182 <div>
183 [loop:@labels]
184 <div class="ord-label[if:$loop1.is_voided] is-voided[/if]">
185 <div class="ord-label-main">
186 <div style="font-weight:600;font-size:14px">$loop1.carrier_label[if:$loop1.service] &middot; $loop1.service[/if]</div>
187 [if:$loop1.has_tracking]
188 <div style="font-family:var(--font-mono,monospace);font-size:12px;margin-top:2px"><a href="$loop1.tracking_url" target="_blank" class="text-brand">$loop1.tracking</a></div>
189 [/if]
190 <div class="text-xs text-dim" style="margin-top:4px">
191 <span class="ful-chip" style="background:rgba(124,58,237,0.15);color:var(--col-accent-bright);font-size:10px">$loop1.status_label</span>
192 [if:$loop1.has_cost] &middot; <span class="ord-label-cost">\$$loop1.cost</span>[/if]
193 [if:$loop1.weight] &middot; $loop1.weight g[/if]
194 [if:$loop1.purchased_at] &middot; created $loop1.purchased_at[/if]
195 [if:$loop1.shipped_at] &middot; shipped $loop1.shipped_at[/if]
196 </div>
197 </div>
198 <div class="ord-label-actions">
199 <a href="$loop1.print_href" class="btn btn-secondary btn-sm" target="_blank">Print</a>
200 [if:$loop1.is_active]
201 <form method="POST" action="/fulfill_order.cgi" style="display:inline">
202 <input type="hidden" name="_act" value="mark_shipped">
203 <input type="hidden" name="order_id" value="$order_id">
204 <input type="hidden" name="label_id" value="$loop1.id">
205 <button type="submit" class="btn btn-primary btn-sm">Mark shipped</button>
206 </form>
207 <form method="POST" action="/fulfill_order.cgi" style="display:inline"
208 data-confirm-title="Void this label?"
209 data-confirm-message="Voiding marks it cancelled in the system. If you paid the carrier, request a refund through their portal."
210 data-confirm-style="danger">
211 <input type="hidden" name="_act" value="void_label">
212 <input type="hidden" name="order_id" value="$order_id">
213 <input type="hidden" name="label_id" value="$loop1.id">
214 <button type="submit" class="btn btn-danger btn-sm">Void</button>
215 </form>
216 [/if]
217 </div>
218 </div>
219 [/loop]
220 </div>
221 [/if]
222
223 <h3 style="margin-top:18px">Create label / record tracking</h3>
224 <form method="POST" action="/fulfill_order.cgi" style="display:grid;grid-template-columns:repeat(4,1fr);gap:10px;align-items:end">
225 <input type="hidden" name="_act" value="create_label">
226 <input type="hidden" name="order_id" value="$order_id">
227 <div class="form-group" style="margin:0">
228 <label class="form-label">Carrier</label>
229 <select name="carrier" class="select">$carrier_opts_html</select>
230 </div>
231 <div class="form-group" style="margin:0">
232 <label class="form-label">Service <span class="text-xs text-dim">(optional)</span></label>
233 <input type="text" name="service" class="input" placeholder="e.g. Priority Mail">
234 </div>
235 <div class="form-group" style="margin:0">
236 <label class="form-label">Tracking number</label>
237 <input type="text" name="tracking_number" class="input" placeholder="9400 1000 0000 0000 0000 00">
238 </div>
239 <div class="form-group" style="margin:0">
240 <label class="form-label">Cost (\$)</label>
241 <input type="text" name="cost_cents" class="input" placeholder="Cents, e.g. 950 = \$9.50">
242 </div>
243 <div class="form-group" style="margin:0;grid-column:span 2">
244 <label class="form-label">Tracking URL <span class="text-xs text-dim">(optional &mdash; auto-filled for common carriers)</span></label>
245 <input type="text" name="tracking_url" class="input" placeholder="https://&hellip;">
246 </div>
247 <div class="form-group" style="margin:0">
248 <label class="form-label">Weight (g)</label>
249 <input type="text" name="weight_grams" class="input" value="$total_weight">
250 </div>
251 <div class="form-group" style="margin:0">
252 <button type="submit" class="btn btn-primary" style="width:100%">Save label</button>
253 </div>
254 <div class="form-group" style="margin:0;grid-column:span 4">
255 <label class="form-label">Notes <span class="text-xs text-dim">(optional, only visible to you)</span></label>
256 <input type="text" name="notes" class="input" placeholder="e.g. Picked up by USPS truck">
257 </div>
258 </form>
259 <p class="text-xs text-dim" style="margin-top:8px;line-height:1.5">Adding a tracking number auto-advances the order to <strong>Shipped</strong>. The label record is for your records; print it to generate an HTML label / packing slip.</p>
260 </div>
261
262 <div class="ord-card">
263 <h3>Notes &amp; history</h3>
264 <form method="POST" action="/fulfill_order.cgi" style="display:flex;gap:8px;align-items:start;margin-bottom:14px">
265 <input type="hidden" name="_act" value="add_note">
266 <input type="hidden" name="order_id" value="$order_id">
267 <input type="text" name="note" class="input" placeholder="Add a note (only visible to you)&hellip;" style="flex:1">
268 <button type="submit" class="btn btn-primary">Add</button>
269 </form>
270 [if:$has_notes]
271 [loop:@notes]
272 <div class="ord-note">
273 <div>$loop1.note</div>
274 <div class="ord-note-time">$loop1.created_at</div>
275 </div>
276 [/loop]
277 [/if]
278 [if:!$has_notes]
279 <p class="text-xs text-dim">No notes yet.</p>
280 [/if]
281 </div>
282 </div>
283
284 <!-- RIGHT COLUMN: addresses + totals -->
285 <div class="stack">
286 <div class="ord-card">
287 <h3>Ship to</h3>
288 <div class="ord-addr">$ship_to_html</div>
289 </div>
290
291 [if:$has_bill_to]
292 <div class="ord-card">
293 <h3>Bill to</h3>
294 <div class="ord-addr">$bill_to_html</div>
295 </div>
296 [/if]
297
298 <div class="ord-card">
299 <h3>Ship from <span class="text-xs text-dim" style="float:right;letter-spacing:0">(<a href="$settings_url" class="text-brand">edit</a>)</span></h3>
300 [if:$has_origin]
301 <div class="ord-addr">$origin_html</div>
302 [/if]
303 [if:!$has_origin]
304 <p class="text-xs text-dim" style="margin:0">No origin address yet. <a href="$settings_url" class="text-brand">Set one &rarr;</a></p>
305 [/if]
306 </div>
307
308 <div class="ord-card">
309 <h3>Totals</h3>
310 <dl class="ord-kv">
311 <dt>Subtotal</dt> <dd style="text-align:right;font-family:var(--font-mono,monospace)">\$$subtotal</dd>
312 <dt>Shipping</dt> <dd style="text-align:right;font-family:var(--font-mono,monospace)">\$$shipping_paid</dd>
313 <dt>Tax</dt> <dd style="text-align:right;font-family:var(--font-mono,monospace)">\$$tax_amount</dd>
314 <dt style="font-weight:700;color:var(--col-text)">Total</dt>
315 <dd style="text-align:right;font-family:var(--font-mono,monospace);font-weight:700;color:var(--col-accent-bright)">\$$total $currency</dd>
316 <dt>Payment</dt> <dd style="text-align:right">$pay_status[if:$has_paid_at] &middot; <span class="text-xs text-dim">$paid_at</span>[/if]</dd>
317 </dl>
318 </div>
319 </div>
320</div>
Keyboard: j next diff k previous diff g top G bottom r restore c compile-check ? help