Diff -- /var/www/vhosts/3dshawn.com/repricer.3dshawn.com/_attic/checkout_complete.cgi
Diff

/var/www/vhosts/3dshawn.com/repricer.3dshawn.com/_attic/checkout_complete.cgi

added on local at 2026-07-01 21:47:32

Added
+162
lines
Removed
-0
lines
Context
0
unchanged
Blobs
from
to 223f79ce9359
Restore this content →
Unified diff
Naive LCS-based line diff. Additions in emerald, deletions in rose. Both sides decompressed live from BLOB_STORE.
1#!/usr/bin/perl
2#======================================================================
3# RePricer - Post-purchase landing page (buyer-facing).
4#
5# GET /checkout_complete.cgi?order=N[&payment_intent=...&payment_intent_client_secret=...]
6#
7# Stripe redirects the buyer here after stripe.confirmPayment(). The
8# definitive payment state comes from the webhook (orders.status), but
9# Stripe also appends a `redirect_status` query param we use as a hint
10# while the webhook is in flight.
11#======================================================================
12use strict;
13use warnings;
14
15use lib '/var/www/vhosts/3dshawn.com/repricer.3dshawn.com';
16use CGI;
17use MODS::Template;
18use MODS::DBConnect;
19use MODS::RePricer::Config;
20use MODS::RePricer::Themes;
21use MODS::RePricer::Cart;
22use MODS::RePricer::Tax;
23
24$| = 1;
25
26my $q = CGI->new;
27my $form = $q->Vars;
28my $tfile = MODS::Template->new;
29my $db = MODS::DBConnect->new;
30my $config = MODS::RePricer::Config->new;
31my $themes = MODS::RePricer::Themes->new;
32my $cart = MODS::RePricer::Cart->new;
33my $DB = $config->settings('database_name');
34
35my $oid = $form->{order} || 0;
36$oid =~ s/[^0-9]//g;
37
38my $redirect_status = $form->{redirect_status} || '';
39
40unless ($oid) {
41 print "Status: 302 Found\nLocation: /\n\n";
42 exit;
43}
44
45my $dbh = $db->db_connect();
46
47my $order = $db->db_readwrite($dbh, qq~
48 SELECT o.id, o.storefront_id, o.status, o.buyer_email,
49 o.total_amount_cents, o.subtotal_cents, o.tax_amount_cents, o.currency,
50 s.name AS store_name, s.subdomain, s.theme_id
51 FROM `${DB}`.orders o
52 JOIN `${DB}`.storefronts s ON s.id = o.storefront_id
53 WHERE o.id='$oid' LIMIT 1
54~, $ENV{SCRIPT_NAME}, __LINE__);
55
56unless ($order && $order->{id}) {
57 $db->db_disconnect($dbh);
58 print "Status: 302 Found\nLocation: /\n\n";
59 exit;
60}
61
62# Pull line items so the receipt is itemized.
63my @items = $db->db_readwrite_multiple($dbh, qq~
64 SELECT oi.id, oi.price_paid_cents, oi.quantity,
65 m.id AS model_id, m.title
66 FROM `${DB}`.order_items oi
67 JOIN `${DB}`.models m ON m.id = oi.model_id
68 WHERE oi.order_id='$oid'
69 ORDER BY oi.id
70~, $ENV{SCRIPT_NAME}, __LINE__);
71
72# Clear the cart if the order is paid (webhook already fired) so the
73# buyer doesn't see stale items when they return to the storefront.
74if (($order->{status} || '') eq 'paid') {
75 my $token = $cart->read_token($q);
76 $cart->clear($db, $dbh, $DB, $token, $order->{storefront_id}) if $token;
77}
78
79my $theme = $themes->by_id($order->{theme_id});
80my $css_vars = $themes->css_vars($theme);
81
82# Per-jurisdiction tax breakdown for the receipt.
83my $tax_summary = MODS::RePricer::Tax->new->summary_for_order($db, $dbh, $DB, $oid);
84
85$db->db_disconnect($dbh);
86
87my $status = $order->{status} || 'pending';
88
89# UI state. Three possibilities:
90# paid -> webhook already fired; show success + download links
91# pending -> webhook in flight; show "processing" with auto-refresh
92# failed -> something went wrong; surface the error path
93my $is_paid = ($status eq 'paid') ? 1 : 0;
94my $is_failed = ($status eq 'failed') ? 1 : 0;
95my $is_pending = (!$is_paid && !$is_failed) ? 1 : 0;
96
97# A failed redirect_status from Stripe means the buyer's card was
98# declined or 3DS failed -- treat that as definitive failure even if
99# our DB row is still pending.
100if (lc($redirect_status) eq 'failed') {
101 $is_paid = 0;
102 $is_pending = 0;
103 $is_failed = 1;
104}
105
106my @item_rows;
107foreach my $it (@items) {
108 my $title = $it->{title} || ('Model #' . $it->{model_id});
109 $title =~ s/&/&amp;/g; $title =~ s/</&lt;/g; $title =~ s/>/&gt;/g; $title =~ s/"/&quot;/g;
110 push @item_rows, {
111 title => $title,
112 qty => $it->{quantity} || 1,
113 line_total => '$' . sprintf('%.2f', ($it->{price_paid_cents} || 0) * ($it->{quantity} || 1) / 100),
114 download_url => $is_paid ? "/download.cgi?order=$oid&item=$it->{id}" : '',
115 };
116}
117
118my @tax_rows;
119foreach my $l (@$tax_summary) {
120 push @tax_rows, {
121 label => $l->{jurisdiction_label},
122 rate => sprintf('%.2f', $l->{rate_pct}),
123 cents => '$' . sprintf('%.2f', ($l->{tax_amount_cents} || 0) / 100),
124 };
125}
126
127require MODS::RePricer::StoreChrome;
128my $chrome_dbh = $db->db_connect();
129my $chrome_html = MODS::RePricer::StoreChrome->header_html({
130 store_id => $order->{storefront_id},
131 store_name => $order->{store_name} || $order->{subdomain},
132 is_buyer_in => ($order->{buyer_email} ? 1 : 0),
133 cart_count => 0,
134 db => $db,
135 dbh => $chrome_dbh,
136 DB => $DB,
137});
138$db->db_disconnect($chrome_dbh);
139
140my $tvars = {
141 theme_css_vars => $css_vars,
142 order_id => $oid + 0,
143 store_name => $order->{store_name} || $order->{subdomain},
144 store_id => $order->{storefront_id},
145 store_chrome_html => $chrome_html,
146 buyer_email => $order->{buyer_email},
147 subtotal_display => '$' . sprintf('%.2f', ($order->{subtotal_cents} || 0) / 100),
148 tax_display => '$' . sprintf('%.2f', ($order->{tax_amount_cents} || 0) / 100),
149 has_tax => ($order->{tax_amount_cents} && $order->{tax_amount_cents} > 0) ? 1 : 0,
150 tax_lines => \@tax_rows,
151 total_display => '$' . sprintf('%.2f', ($order->{total_amount_cents} || 0) / 100),
152 is_paid => $is_paid,
153 is_pending => $is_pending,
154 is_failed => $is_failed,
155 items => \@item_rows,
156 has_items => scalar(@item_rows) ? 1 : 0,
157 back_href => "/store.cgi?id=$order->{storefront_id}",
158 orders_href => "/my_orders.cgi?id=$order->{storefront_id}",
159};
160
161print "Content-Type: text/html; charset=utf-8\nCache-Control: no-cache\n\n";
162print join('', $tfile->template('repricer_checkout_complete.html', $tvars, undef));
Keyboard: j next diff k previous diff g top G bottom r restore c compile-check ? help